[tracing] Add the proto to json converter for trace events
This is used to convert files with binary proto data to the Trace Event .json format for use with the chrome://tracing viewer. Change-Id: Ib5478f6aa2326b5e085506859f4a7f30f95c79f5 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1535823 Commit-Queue: Peter Marshall <petermarshall@chromium.org> Reviewed-by: Mathias Bynens <mathias@chromium.org> Cr-Commit-Position: refs/heads/master@{#60422}
This commit is contained in:
parent
48fcceea8c
commit
247c4fff17
1
tools/tracing/proto-converter/.gitignore
vendored
Normal file
1
tools/tracing/proto-converter/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
proto-to-json.js
|
1
tools/tracing/proto-converter/.nvmrc
Normal file
1
tools/tracing/proto-converter/.nvmrc
Normal file
@ -0,0 +1 @@
|
||||
v11.9.0
|
123
tools/tracing/proto-converter/package-lock.json
generated
Normal file
123
tools/tracing/proto-converter/package-lock.json
generated
Normal file
@ -0,0 +1,123 @@
|
||||
{
|
||||
"requires": true,
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
"@protobufjs/aspromise": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
||||
"integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=",
|
||||
"dev": true
|
||||
},
|
||||
"@protobufjs/base64": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
|
||||
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
|
||||
"dev": true
|
||||
},
|
||||
"@protobufjs/codegen": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
|
||||
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
|
||||
"dev": true
|
||||
},
|
||||
"@protobufjs/eventemitter": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
|
||||
"integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=",
|
||||
"dev": true
|
||||
},
|
||||
"@protobufjs/fetch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
|
||||
"integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@protobufjs/aspromise": "^1.1.1",
|
||||
"@protobufjs/inquire": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"@protobufjs/float": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
||||
"integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=",
|
||||
"dev": true
|
||||
},
|
||||
"@protobufjs/inquire": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
|
||||
"integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=",
|
||||
"dev": true
|
||||
},
|
||||
"@protobufjs/path": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
||||
"integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=",
|
||||
"dev": true
|
||||
},
|
||||
"@protobufjs/pool": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
||||
"integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=",
|
||||
"dev": true
|
||||
},
|
||||
"@protobufjs/utf8": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
||||
"integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/long": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz",
|
||||
"integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "11.11.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.4.tgz",
|
||||
"integrity": "sha512-02tIL+QIi/RW4E5xILdoAMjeJ9kYq5t5S2vciUdFPXv/ikFTb0zK8q9vXkg4+WAJuYXGiVT1H28AkD2C+IkXVw==",
|
||||
"dev": true
|
||||
},
|
||||
"long": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
||||
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==",
|
||||
"dev": true
|
||||
},
|
||||
"protobufjs": {
|
||||
"version": "6.8.8",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz",
|
||||
"integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@protobufjs/aspromise": "^1.1.2",
|
||||
"@protobufjs/base64": "^1.1.2",
|
||||
"@protobufjs/codegen": "^2.0.4",
|
||||
"@protobufjs/eventemitter": "^1.1.0",
|
||||
"@protobufjs/fetch": "^1.1.0",
|
||||
"@protobufjs/float": "^1.0.2",
|
||||
"@protobufjs/inquire": "^1.1.0",
|
||||
"@protobufjs/path": "^1.1.2",
|
||||
"@protobufjs/pool": "^1.1.0",
|
||||
"@protobufjs/utf8": "^1.1.0",
|
||||
"@types/long": "^4.0.0",
|
||||
"@types/node": "^10.1.0",
|
||||
"long": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "10.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.1.tgz",
|
||||
"integrity": "sha512-Rymt08vh1GaW4vYB6QP61/5m/CFLGnFZP++bJpWbiNxceNa6RBipDmb413jvtSf/R1gg5a/jQVl2jY4XVRscEA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.3.4000",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.4000.tgz",
|
||||
"integrity": "sha512-jjOcCZvpkl2+z7JFn0yBOoLQyLoIkNZAs/fYJkUG6VKy6zLPHJGfQJYFHzibB6GJaF/8QrcECtlQ5cpvRHSMEA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
11
tools/tracing/proto-converter/package.json
Normal file
11
tools/tracing/proto-converter/package.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "tsc proto-to-json.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^11.11.4",
|
||||
"protobufjs": "^6.8.8",
|
||||
"typescript": "^3.3.4000"
|
||||
}
|
||||
}
|
132
tools/tracing/proto-converter/proto-to-json.ts
Normal file
132
tools/tracing/proto-converter/proto-to-json.ts
Normal file
@ -0,0 +1,132 @@
|
||||
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { Root } from 'protobufjs';
|
||||
|
||||
// Requirements: node 10.4.0+, npm
|
||||
|
||||
// Setup:
|
||||
// (nvm is optional, you can also just install node manually)
|
||||
// $ nvm use
|
||||
// $ npm install
|
||||
// $ npm run build
|
||||
|
||||
// Usage: node proto-to-json.js path_to_trace.proto input_file output_file
|
||||
|
||||
// Converts a binary proto file to a 'Trace Event Format' compatible .json file
|
||||
// that can be used with chrome://tracing. Documentation of this format:
|
||||
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU
|
||||
|
||||
// Attempts to reproduce the logic of the JSONTraceWriter in V8 in terms of the
|
||||
// JSON fields it will include/exclude based on the data present in the trace
|
||||
// event.
|
||||
|
||||
// TODO(petermarshall): Replace with Array#flat once it lands in Node.js.
|
||||
const flatten = <T>(a: T[], b: T[]) => { a.push(...b); return a; }
|
||||
|
||||
// Convert a string representing an int or uint (64 bit) to a Number or throw
|
||||
// if the value won't fit.
|
||||
function parseIntOrThrow(int: string) {
|
||||
if (BigInt(int) > Number.MAX_SAFE_INTEGER) {
|
||||
throw new Error("Loss of int precision");
|
||||
}
|
||||
return Number(int);
|
||||
}
|
||||
|
||||
function uint64AsHexString(val : string) : string {
|
||||
return "0x" + BigInt(val).toString(16);
|
||||
}
|
||||
|
||||
function parseArgValue(arg: any) : any {
|
||||
if (arg.jsonValue) {
|
||||
return JSON.parse(arg.jsonValue);
|
||||
}
|
||||
if (typeof arg.stringValue !== 'undefined') {
|
||||
return arg.stringValue;
|
||||
}
|
||||
if (typeof arg.uintValue !== 'undefined') {
|
||||
return parseIntOrThrow(arg.uintValue);
|
||||
}
|
||||
if (typeof arg.intValue !== 'undefined') {
|
||||
return parseIntOrThrow(arg.intValue);
|
||||
}
|
||||
if (typeof arg.boolValue !== 'undefined') {
|
||||
return arg.boolValue;
|
||||
}
|
||||
if (typeof arg.doubleValue !== 'undefined') {
|
||||
// Handle [-]Infinity and NaN which protobufjs outputs as strings here.
|
||||
return typeof arg.doubleValue === 'string' ?
|
||||
arg.doubleValue : Number(arg.doubleValue);
|
||||
}
|
||||
if (typeof arg.pointerValue !== 'undefined') {
|
||||
return uint64AsHexString(arg.pointerValue);
|
||||
}
|
||||
}
|
||||
|
||||
// These come from
|
||||
// https://cs.chromium.org/chromium/src/base/trace_event/common/trace_event_common.h
|
||||
const TRACE_EVENT_FLAG_HAS_ID: number = 1 << 1;
|
||||
const TRACE_EVENT_FLAG_FLOW_IN: number = 1 << 8;
|
||||
const TRACE_EVENT_FLAG_FLOW_OUT: number = 1 << 9;
|
||||
|
||||
async function main() {
|
||||
const root = new Root();
|
||||
const { resolvePath } = root;
|
||||
const numDirectoriesToStrip = 2;
|
||||
let initialOrigin: string|null;
|
||||
root.resolvePath = (origin, target) => {
|
||||
if (!origin) {
|
||||
initialOrigin = target;
|
||||
for (let i = 0; i <= numDirectoriesToStrip; i++) {
|
||||
initialOrigin = path.dirname(initialOrigin);
|
||||
}
|
||||
return resolvePath(origin, target);
|
||||
}
|
||||
return path.resolve(initialOrigin!, target);
|
||||
};
|
||||
const traceProto = await root.load(process.argv[2]);
|
||||
const Trace = traceProto.lookupType("Trace");
|
||||
const payload = await fs.promises.readFile(process.argv[3]);
|
||||
const msg = Trace.decode(payload).toJSON();
|
||||
const output = {
|
||||
traceEvents: msg.packet
|
||||
.filter((packet: any) => !!packet.chromeEvents)
|
||||
.map((packet: any) => packet.chromeEvents.traceEvents)
|
||||
.map((traceEvents: any) => traceEvents.map((e: any) => {
|
||||
|
||||
const bind_id = (e.flags & (TRACE_EVENT_FLAG_FLOW_IN |
|
||||
TRACE_EVENT_FLAG_FLOW_OUT)) ? e.bindId : undefined;
|
||||
const scope = (e.flags & TRACE_EVENT_FLAG_HAS_ID) && e.scope ?
|
||||
e.scope : undefined;
|
||||
|
||||
return {
|
||||
pid: e.processId,
|
||||
tid: e.threadId,
|
||||
ts: parseIntOrThrow(e.timestamp),
|
||||
tts: parseIntOrThrow(e.threadTimestamp),
|
||||
ph: String.fromCodePoint(e.phase),
|
||||
cat: e.categoryGroupName,
|
||||
name: e.name,
|
||||
dur: parseIntOrThrow(e.duration),
|
||||
tdur: parseIntOrThrow(e.threadDuration),
|
||||
bind_id: bind_id,
|
||||
flow_in: e.flags & TRACE_EVENT_FLAG_FLOW_IN ? true : undefined,
|
||||
flow_out: e.flags & TRACE_EVENT_FLAG_FLOW_OUT ? true : undefined,
|
||||
scope: scope,
|
||||
id: (e.flags & TRACE_EVENT_FLAG_HAS_ID) ?
|
||||
uint64AsHexString(e.id) : undefined,
|
||||
args: (e.args || []).reduce((js_args: any, proto_arg: any) => {
|
||||
js_args[proto_arg.name] = parseArgValue(proto_arg);
|
||||
return js_args;
|
||||
}, {})
|
||||
};
|
||||
}))
|
||||
.reduce(flatten, [])
|
||||
};
|
||||
await fs.promises.writeFile(process.argv[4], JSON.stringify(output, null, 2));
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
12
tools/tracing/proto-converter/tsconfig.json
Normal file
12
tools/tracing/proto-converter/tsconfig.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2018",
|
||||
"module": "commonjs",
|
||||
"lib": ["es6","dom"],
|
||||
"outDir": "lib",
|
||||
"rootDir": "src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user