Skip to content

Commit a9c848c

Browse files
committed
Add support for visualizing v8 profile gathered by CpuProfiler::StartProfling
1 parent 2e36dad commit a9c848c

File tree

5 files changed

+74
-9
lines changed

5 files changed

+74
-9
lines changed

cmd.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ async function cmd (argv, banner = defaultBanner) {
5858
version: 'v',
5959
help: 'h',
6060
visualizeOnly: 'visualize-only',
61+
visualizeV8Profile: 'visualize-v8-profile',
6162
collectOnly: 'collect-only',
6263
kernelTracing: 'kernel-tracing',
6364
kernelTracingDebug: 'kernel-tracing-debug',
@@ -89,6 +90,10 @@ async function cmd (argv, banner = defaultBanner) {
8990
status(`Creating flamegraph from ${args.visualizeOnly}`)
9091
}
9192

93+
if (args.visualizeV8Profile) {
94+
status(`Creating flamegraph from v8 profile ${args.visualizeV8Profile}`)
95+
}
96+
9297
const assetPath = await zeroEks(args)
9398

9499
if (args.collectOnly) {

index.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
const { sun, linux, windows, v8 } = require('./platform')
44
const debug = require('debug')('0x')
5-
const { join, isAbsolute, relative } = require('path')
5+
const { join, isAbsolute, relative, dirname } = require('path')
66
const fs = require('fs')
77
const validate = require('./lib/validate')(require('./schema.json'))
88
const traceStacksToTicks = require('./lib/trace-stacks-to-ticks')
@@ -26,11 +26,18 @@ async function zeroEks (args) {
2626

2727
validate(args)
2828
const { collectOnly, visualizeOnly, writeTicks, treeDebug, mapFrames } = args
29-
if (collectOnly && visualizeOnly) {
30-
throw Error('"collect only" and "visualize only" cannot be used together')
29+
30+
let incompatibleOptions = 0
31+
if (collectOnly) incompatibleOptions += 1
32+
if (visualizeOnly) incompatibleOptions += 1
33+
if (visualizeV8Profile) incompatibleOptions += 1
34+
35+
if (incompatibleOptions > 1) {
36+
throw Error('Only one of "collect only", "visualize only", "visualize v8 profile" can be used')
3137
}
3238

3339
if (visualizeOnly) return visualize(args)
40+
if (visualizeV8Profile) return visualizeV8Profile(args)
3441

3542
args.title = args.title || `node ${args.argv.join(' ')}`
3643
var { ticks, pid, folder, inlined } = await startProcessAndCollectTraceData(args)
@@ -97,11 +104,21 @@ async function generateFlamegraph (opts) {
97104
return file
98105
}
99106

107+
function getFolder (file, workingDir) {
108+
return isAbsolute(file)
109+
? relative(workingDir, file)
110+
: file
111+
}
112+
113+
async function visualizeV8Profile (opts) {
114+
const folder = dirname(opts.visualizeV8Profile)
115+
const file = await render({ ...opts, folder })
116+
return file
117+
}
118+
100119
async function visualize ({ visualizeOnly, treeDebug, workingDir, title, mapFrames, open, name, pathToNodeBinary }) {
101120
try {
102-
const folder = isAbsolute(visualizeOnly)
103-
? relative(workingDir, visualizeOnly)
104-
: visualizeOnly
121+
const folder = getFolder(visualizeOnly, workingDir)
105122
const ls = fs.readdirSync(folder)
106123
const traceFile = /^stacks\.(.*)\.out$/
107124
const isolateLog = /^isolate-((0x)?[0-9A-Fa-f]{2,16})-(.*)-v8\.(log|json)$/

lib/convert-v8-profile-to-tree.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
function convert (profile) {
2+
const converted = {
3+
children: new Array(profile.children.length),
4+
name: `${profile.functionName} ${profile.url}:${profile.lineNumber}`,
5+
top: profile.hitCount,
6+
value: profile.hitCount,
7+
S: 0,
8+
}
9+
10+
for (let i = 0; i < profile.children.length; i++) {
11+
converted.children[i] = convert(profile.children[i]);
12+
converted.value += converted.children[i].value;
13+
}
14+
15+
return converted;
16+
}
17+
18+
function convertV8Profile (profile) {
19+
const converted = convert(profile)
20+
return {
21+
merged: converted,
22+
unmerged: converted,
23+
}
24+
}
25+
26+
module.exports = {
27+
convertV8Profile,
28+
}

lib/render.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,25 @@ const pump = require('pump')
77
const debug = require('debug')('0x:render')
88
const ticksToTree = require('./ticks-to-tree')
99
const html = require('../visualizer/html')
10+
const { convertV8Profile } = require('./convert-v8-profile-to-tree')
1011

1112
module.exports = render
1213

1314
async function render (opts) {
1415
const {
1516
name, title, kernelTracing, outputHtml, pid,
16-
workingDir, mapFrames, ticks, inlined, folder, pathToNodeBinary
17+
workingDir, mapFrames, ticks, inlined, folder, pathToNodeBinary,
18+
visualizeV8Profile
1719
} = opts
1820
debug('converted stacks to intermediate format')
19-
const trees = ticksToTree(ticks, { mapFrames, inlined, pathToNodeBinary })
21+
22+
let trees
23+
if (visualizeV8Profile) {
24+
const v8Profile = require(path.resolve(workingDir, visualizeV8Profile))
25+
trees = convertV8Profile(v8Profile.head)
26+
} else {
27+
trees = ticksToTree(ticks, { mapFrames, inlined, pathToNodeBinary })
28+
}
2029

2130
const script = `
2231
${await createBundle()}

schema.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@
8080
"visualizeOnly": {
8181
"type": "string"
8282
},
83+
"visualize-v8-profile": {
84+
"type": "string"
85+
},
86+
"visualizeV8Profile": {
87+
"type": "string"
88+
},
8389
"collect-only": {
8490
"type": "boolean"
8591
},
@@ -94,7 +100,7 @@
94100
},
95101
"P": {
96102
"type": "string"
97-
},
103+
},
98104
"kernelTracing": {
99105
"type": "boolean"
100106
},

0 commit comments

Comments
 (0)