11cb0ef41Sopenharmony_ci// Copyright 2019 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ciimport * as fs from 'fs'; 61cb0ef41Sopenharmony_ciimport * as path from 'path'; 71cb0ef41Sopenharmony_ciimport { Root } from 'protobufjs'; 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci// Requirements: node 10.4.0+, npm 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ci// Setup: 121cb0ef41Sopenharmony_ci// (nvm is optional, you can also just install node manually) 131cb0ef41Sopenharmony_ci// $ nvm use 141cb0ef41Sopenharmony_ci// $ npm install 151cb0ef41Sopenharmony_ci// $ npm run build 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ci// Usage: node proto-to-json.js path_to_trace.proto input_file output_file 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ci// Converts a binary proto file to a 'Trace Event Format' compatible .json file 201cb0ef41Sopenharmony_ci// that can be used with chrome://tracing. Documentation of this format: 211cb0ef41Sopenharmony_ci// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci// Attempts to reproduce the logic of the JSONTraceWriter in V8 in terms of the 241cb0ef41Sopenharmony_ci// JSON fields it will include/exclude based on the data present in the trace 251cb0ef41Sopenharmony_ci// event. 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ci// Convert a string representing an int or uint (64 bit) to a Number or throw 281cb0ef41Sopenharmony_ci// if the value won't fit. 291cb0ef41Sopenharmony_cifunction parseIntOrThrow(int: string) { 301cb0ef41Sopenharmony_ci if (BigInt(int) > Number.MAX_SAFE_INTEGER) { 311cb0ef41Sopenharmony_ci throw new Error("Loss of int precision"); 321cb0ef41Sopenharmony_ci } 331cb0ef41Sopenharmony_ci return Number(int); 341cb0ef41Sopenharmony_ci} 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_cifunction uint64AsHexString(val : string) : string { 371cb0ef41Sopenharmony_ci return "0x" + BigInt(val).toString(16); 381cb0ef41Sopenharmony_ci} 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_cifunction parseArgValue(arg: any) : any { 411cb0ef41Sopenharmony_ci if (arg.jsonValue) { 421cb0ef41Sopenharmony_ci return JSON.parse(arg.jsonValue); 431cb0ef41Sopenharmony_ci } 441cb0ef41Sopenharmony_ci if (typeof arg.stringValue !== 'undefined') { 451cb0ef41Sopenharmony_ci return arg.stringValue; 461cb0ef41Sopenharmony_ci } 471cb0ef41Sopenharmony_ci if (typeof arg.uintValue !== 'undefined') { 481cb0ef41Sopenharmony_ci return parseIntOrThrow(arg.uintValue); 491cb0ef41Sopenharmony_ci } 501cb0ef41Sopenharmony_ci if (typeof arg.intValue !== 'undefined') { 511cb0ef41Sopenharmony_ci return parseIntOrThrow(arg.intValue); 521cb0ef41Sopenharmony_ci } 531cb0ef41Sopenharmony_ci if (typeof arg.boolValue !== 'undefined') { 541cb0ef41Sopenharmony_ci return arg.boolValue; 551cb0ef41Sopenharmony_ci } 561cb0ef41Sopenharmony_ci if (typeof arg.doubleValue !== 'undefined') { 571cb0ef41Sopenharmony_ci // Handle [-]Infinity and NaN which protobufjs outputs as strings here. 581cb0ef41Sopenharmony_ci return typeof arg.doubleValue === 'string' ? 591cb0ef41Sopenharmony_ci arg.doubleValue : Number(arg.doubleValue); 601cb0ef41Sopenharmony_ci } 611cb0ef41Sopenharmony_ci if (typeof arg.pointerValue !== 'undefined') { 621cb0ef41Sopenharmony_ci return uint64AsHexString(arg.pointerValue); 631cb0ef41Sopenharmony_ci } 641cb0ef41Sopenharmony_ci} 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci// These come from 671cb0ef41Sopenharmony_ci// https://cs.chromium.org/chromium/src/base/trace_event/common/trace_event_common.h 681cb0ef41Sopenharmony_ciconst TRACE_EVENT_FLAG_HAS_ID: number = 1 << 1; 691cb0ef41Sopenharmony_ciconst TRACE_EVENT_FLAG_FLOW_IN: number = 1 << 8; 701cb0ef41Sopenharmony_ciconst TRACE_EVENT_FLAG_FLOW_OUT: number = 1 << 9; 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ciasync function main() { 731cb0ef41Sopenharmony_ci const root = new Root(); 741cb0ef41Sopenharmony_ci const { resolvePath } = root; 751cb0ef41Sopenharmony_ci const numDirectoriesToStrip = 2; 761cb0ef41Sopenharmony_ci let initialOrigin: string|null; 771cb0ef41Sopenharmony_ci root.resolvePath = (origin, target) => { 781cb0ef41Sopenharmony_ci if (!origin) { 791cb0ef41Sopenharmony_ci initialOrigin = target; 801cb0ef41Sopenharmony_ci for (let i = 0; i <= numDirectoriesToStrip; i++) { 811cb0ef41Sopenharmony_ci initialOrigin = path.dirname(initialOrigin); 821cb0ef41Sopenharmony_ci } 831cb0ef41Sopenharmony_ci return resolvePath(origin, target); 841cb0ef41Sopenharmony_ci } 851cb0ef41Sopenharmony_ci return path.resolve(initialOrigin!, target); 861cb0ef41Sopenharmony_ci }; 871cb0ef41Sopenharmony_ci const traceProto = await root.load(process.argv[2]); 881cb0ef41Sopenharmony_ci const Trace = traceProto.lookupType("Trace"); 891cb0ef41Sopenharmony_ci const payload = await fs.promises.readFile(process.argv[3]); 901cb0ef41Sopenharmony_ci const msg = Trace.decode(payload).toJSON(); 911cb0ef41Sopenharmony_ci const output = { 921cb0ef41Sopenharmony_ci traceEvents: msg.packet 931cb0ef41Sopenharmony_ci .filter((packet: any) => !!packet.chromeEvents) 941cb0ef41Sopenharmony_ci .map((packet: any) => packet.chromeEvents.traceEvents) 951cb0ef41Sopenharmony_ci .map((traceEvents: any) => traceEvents.map((e: any) => { 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci const bind_id = (e.flags & (TRACE_EVENT_FLAG_FLOW_IN | 981cb0ef41Sopenharmony_ci TRACE_EVENT_FLAG_FLOW_OUT)) ? e.bindId : undefined; 991cb0ef41Sopenharmony_ci const scope = (e.flags & TRACE_EVENT_FLAG_HAS_ID) && e.scope ? 1001cb0ef41Sopenharmony_ci e.scope : undefined; 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci return { 1031cb0ef41Sopenharmony_ci pid: e.processId, 1041cb0ef41Sopenharmony_ci tid: e.threadId, 1051cb0ef41Sopenharmony_ci ts: parseIntOrThrow(e.timestamp), 1061cb0ef41Sopenharmony_ci tts: parseIntOrThrow(e.threadTimestamp), 1071cb0ef41Sopenharmony_ci ph: String.fromCodePoint(e.phase), 1081cb0ef41Sopenharmony_ci cat: e.categoryGroupName, 1091cb0ef41Sopenharmony_ci name: e.name, 1101cb0ef41Sopenharmony_ci dur: parseIntOrThrow(e.duration), 1111cb0ef41Sopenharmony_ci tdur: parseIntOrThrow(e.threadDuration), 1121cb0ef41Sopenharmony_ci bind_id: bind_id, 1131cb0ef41Sopenharmony_ci flow_in: e.flags & TRACE_EVENT_FLAG_FLOW_IN ? true : undefined, 1141cb0ef41Sopenharmony_ci flow_out: e.flags & TRACE_EVENT_FLAG_FLOW_OUT ? true : undefined, 1151cb0ef41Sopenharmony_ci scope: scope, 1161cb0ef41Sopenharmony_ci id: (e.flags & TRACE_EVENT_FLAG_HAS_ID) ? 1171cb0ef41Sopenharmony_ci uint64AsHexString(e.id) : undefined, 1181cb0ef41Sopenharmony_ci args: (e.args || []).reduce((js_args: any, proto_arg: any) => { 1191cb0ef41Sopenharmony_ci js_args[proto_arg.name] = parseArgValue(proto_arg); 1201cb0ef41Sopenharmony_ci return js_args; 1211cb0ef41Sopenharmony_ci }, {}) 1221cb0ef41Sopenharmony_ci }; 1231cb0ef41Sopenharmony_ci })) 1241cb0ef41Sopenharmony_ci .flat() 1251cb0ef41Sopenharmony_ci }; 1261cb0ef41Sopenharmony_ci await fs.promises.writeFile(process.argv[4], JSON.stringify(output, null, 2)); 1271cb0ef41Sopenharmony_ci} 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_cimain().catch(console.error); 130