Skip to content

Commit

Permalink
Add support for visualizing v8 profile gathered by CpuProfiler::Start…
Browse files Browse the repository at this point in the history
…Profling
  • Loading branch information
slonka committed Nov 25, 2018
1 parent 2e36dad commit 01744d7
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 9 deletions.
5 changes: 5 additions & 0 deletions cmd.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ async function cmd (argv, banner = defaultBanner) {
version: 'v',
help: 'h',
visualizeOnly: 'visualize-only',
visualizeV8Profile: 'visualize-v8-profile',
collectOnly: 'collect-only',
kernelTracing: 'kernel-tracing',
kernelTracingDebug: 'kernel-tracing-debug',
Expand Down Expand Up @@ -89,6 +90,10 @@ async function cmd (argv, banner = defaultBanner) {
status(`Creating flamegraph from ${args.visualizeOnly}`)
}

if (args.visualizeV8Profile) {
status(`Creating flamegraph from v8 profile ${args.visualizeV8Profile}`)
}

const assetPath = await zeroEks(args)

if (args.collectOnly) {
Expand Down
29 changes: 23 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

validate(args)
const { collectOnly, visualizeOnly, writeTicks, treeDebug, mapFrames } = args
if (collectOnly && visualizeOnly) {
throw Error('"collect only" and "visualize only" cannot be used together')

let incompatibleOptions = 0
if (collectOnly) incompatibleOptions += 1
if (visualizeOnly) incompatibleOptions += 1
if (visualizeV8Profile) incompatibleOptions += 1

if (incompatibleOptions > 1) {
throw Error('Only one of "collect only", "visualize only", "visualize v8 profile" can be used')
}

if (visualizeOnly) return visualize(args)
if (visualizeV8Profile) return visualizeV8Profile(args)

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

function getFolder (file, workingDir) {
return isAbsolute(file)
? relative(workingDir, file)
: file
}

async function visualizeV8Profile (opts) {
const folder = dirname(opts.visualizeV8Profile)
const file = await render({ ...opts, folder })
return file
}

async function visualize ({ visualizeOnly, treeDebug, workingDir, title, mapFrames, open, name, pathToNodeBinary }) {
try {
const folder = isAbsolute(visualizeOnly)
? relative(workingDir, visualizeOnly)
: visualizeOnly
const folder = getFolder(visualizeOnly, workingDir)
const ls = fs.readdirSync(folder)
const traceFile = /^stacks\.(.*)\.out$/
const isolateLog = /^isolate-((0x)?[0-9A-Fa-f]{2,16})-(.*)-v8\.(log|json)$/
Expand Down
28 changes: 28 additions & 0 deletions lib/convert-v8-profile-to-tree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
function convert (profile) {
const converted = {
children: new Array(profile.children.length),
name: `${profile.functionName} ${profile.url}:${profile.lineNumber}`,
top: profile.hitCount,
value: profile.hitCount,
S: 0,
}

for (let i = 0; i < profile.children.length; i++) {
converted.children[i] = convert(profile.children[i]);
converted.value += converted.children[i].value;
}

return converted;
}

function convertV8Profile (profile) {
const converted = convert(profile)
return {
merged: converted,
unmerged: converted,
}
}

module.exports = {
convertV8Profile,
}
13 changes: 11 additions & 2 deletions lib/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,25 @@ const pump = require('pump')
const debug = require('debug')('0x:render')
const ticksToTree = require('./ticks-to-tree')
const html = require('../visualizer/html')
const { convertV8Profile } = require('./convert-v8-profile-to-tree')

module.exports = render

async function render (opts) {
const {
name, title, kernelTracing, outputHtml, pid,
workingDir, mapFrames, ticks, inlined, folder, pathToNodeBinary
workingDir, mapFrames, ticks, inlined, folder, pathToNodeBinary,
visualizeV8Profile
} = opts
debug('converted stacks to intermediate format')
const trees = ticksToTree(ticks, { mapFrames, inlined, pathToNodeBinary })

let trees
if (visualizeV8Profile) {
const v8Profile = require(path.resolve(workingDir, visualizeV8Profile))
trees = convertV8Profile(v8Profile.head)
} else {
trees = ticksToTree(ticks, { mapFrames, inlined, pathToNodeBinary })
}

const script = `
${await createBundle()}
Expand Down
8 changes: 7 additions & 1 deletion schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@
"visualizeOnly": {
"type": "string"
},
"visualize-v8-profile": {
"type": "string"
},
"visualizeV8Profile": {
"type": "string"
},
"collect-only": {
"type": "boolean"
},
Expand All @@ -94,7 +100,7 @@
},
"P": {
"type": "string"
},
},
"kernelTracing": {
"type": "boolean"
},
Expand Down

0 comments on commit 01744d7

Please sign in to comment.