Comparing version 4.4.3 to 4.4.4
@@ -23,3 +23,4 @@ #!/usr/bin/env node | ||
cmd(process.argv.slice(2)).catch((err) => { | ||
console.error(hasUnicode ? `\nš« ${err.message}` : `\n${err.message}`) | ||
err.message = hasUnicode ? `\nš« ${err.message}` : `\n${err.message}` | ||
console.error(err) | ||
debug(err) | ||
@@ -26,0 +27,0 @@ process.exit(err.code || 1) |
@@ -39,3 +39,3 @@ 'use strict' | ||
if (treeDebug === true) { | ||
const tree = await ticksToTree(ticks, args, mapFrames, inlined) | ||
const tree = await ticksToTree(ticks, mapFrames, inlined, args.pathToNodeBinary) | ||
fs.writeFileSync(`${folder}/stacks.${pid}.json`, JSON.stringify(tree, 0, 2)) | ||
@@ -116,3 +116,3 @@ } | ||
if (treeDebug === true) { | ||
const tree = await ticksToTree(ticks, mapFrames, inlined) | ||
const tree = await ticksToTree(ticks, mapFrames, inlined, pathToNodeBinary) | ||
fs.writeFileSync(`${folder}/stacks.${pid}.json`, JSON.stringify(tree, 0, 2)) | ||
@@ -119,0 +119,0 @@ } |
@@ -16,6 +16,6 @@ 'use strict' | ||
name, title, kernelTracing, outputHtml, pid, | ||
workingDir, mapFrames, ticks, inlined, folder | ||
workingDir, mapFrames, ticks, inlined, folder, pathToNodeBinary | ||
} = opts | ||
debug('converted stacks to intermediate format') | ||
const trees = ticksToTree(ticks, mapFrames, inlined) | ||
const trees = ticksToTree(ticks, mapFrames, inlined, pathToNodeBinary) | ||
@@ -22,0 +22,0 @@ const script = ` |
'use strict' | ||
const { spawnSync } = require('child_process') | ||
const { join } = require('path') | ||
const debug = require('debug')('0x: ticks-to-tree') | ||
const { join } = require('path') | ||
const preloadDirRx = RegExp(join(__dirname, 'preload')) | ||
const internalModuleRegExp = /^.?(?:\(anonymous\)|internalBinding|NativeModule[^ ]*) [^/\\][a-zA-Z0-9_/\\-]+\.js:\d+:\d+$/ | ||
const nodeBootstrapRegExp = / internal\/bootstrap.+\.js:\d+:\d+$/ | ||
module.exports = ticksToTree | ||
function ticksToTree (ticks, mapFrames, inlined) { | ||
function ticksToTree (ticks, mapFrames, inlined, binary) { | ||
const merged = { | ||
@@ -22,2 +28,22 @@ name: 'all stacks', | ||
// Spawn a file that throws an error to get the loading stack. | ||
// Then create a regular expression that matches all those files. | ||
let childStderr = spawnSync(binary, ['--experimental-modules', join(__dirname, 'loading-stacks')]).stderr.toString() | ||
if (childStderr.includes('--experimental-modules')) { | ||
// Future proof to make sure it works even if the `experimental-modules` flag is removed. | ||
childStderr = spawnSync(binary, [join(__dirname, 'loading-stacks')]) | ||
} | ||
const stacks = childStderr | ||
.match(/ \(.+?:/g) | ||
.map((e) => e.slice(2)) | ||
.filter((e) => e[0] !== '/' && e[0] !== '\\') | ||
let regExpStr = '(' | ||
let separator = '' | ||
for (const frame of new Set(stacks)) { | ||
regExpStr += `${separator} ${frame.replace(/\\/g, '\\\\').replace(/\./g, '\\.')}\\d+:\\d+` | ||
separator = '|' | ||
} | ||
regExpStr += ')$' | ||
const regExp = new RegExp(regExpStr) | ||
ticks.forEach((stack) => { | ||
@@ -68,3 +94,3 @@ stack = removeInstrumentationFrames(stack) | ||
if (kind === 'Unopt') S += 1 | ||
if (kind === 'Opt') S += 2 | ||
else if (kind === 'Opt') S += 2 | ||
} | ||
@@ -76,3 +102,3 @@ | ||
stack = labelInitFrames(stack) | ||
labelInitFrames(stack, regExp) | ||
@@ -122,5 +148,5 @@ addToMergedTree(stack.map(({ S, name, value, top }) => ({ S, name, value, top }))) | ||
if (frame.S === 1) frame.name = '~' + frame.name | ||
if (frame.S === 2) frame.name = '*' + frame.name | ||
if (frame.S === 3) frame.name = '~' + frame.name + ' [INLINABLE]' | ||
if (frame.S === 4) frame.name = '*' + frame.name + ' [INLINABLE]' | ||
else if (frame.S === 2) frame.name = '*' + frame.name | ||
else if (frame.S === 3) frame.name = '~' + frame.name + ' [INLINABLE]' | ||
else if (frame.S === 4) frame.name = '*' + frame.name + ' [INLINABLE]' | ||
children.push(frame) | ||
@@ -140,50 +166,27 @@ } else frame = child | ||
function labelInitFrames (frames) { | ||
const startupBootstrapNodeIndex = frames.findIndex(({ name }, ix) => { | ||
if (frames[ix + 1] && /Module.runMain module\.js/.test(frames[ix + 1].name)) return false | ||
return /startup bootstrap_node\.js/.test(name) | ||
}) | ||
if (startupBootstrapNodeIndex !== -1) { | ||
frames.slice(startupBootstrapNodeIndex + 1).forEach((frame) => { | ||
if (frame.isInit) return | ||
function labelInitFrames (frames, loadingFrameRegExp) { | ||
let foundNodeModule = false | ||
for (var i = frames.length - 1; i >= 0; i--) { | ||
const frame = frames[i] | ||
if (foundNodeModule) { | ||
frame.name += ' [INIT]' | ||
frame.isInit = true | ||
}) | ||
} | ||
const moduleRunMainIndex = frames.findIndex(({ name }, ix) => { | ||
return /Module.runMain module\.js/.test(name) | ||
}) | ||
if (moduleRunMainIndex !== -1) { | ||
frames.slice(moduleRunMainIndex + 1).forEach((frame) => { | ||
if (frame.isInit) return | ||
if (/.+ (internal\/)?module\.js/.test(frame.name)) frame.name += ' [INIT]' | ||
// The last module initialization. This is only Node.js internally. | ||
// All frames before have to be internal as well. | ||
} else if (internalModuleRegExp.test(frame.name) || | ||
// Node.js 10 has some more bootstrapping code. | ||
nodeBootstrapRegExp.test(frame.name)) { | ||
foundNodeModule = true | ||
frame.name += ' [INIT]' | ||
frame.isInit = true | ||
}) | ||
} | ||
// if there's so many modules to load, the module requiring may | ||
// actually go into another tick, so far that's been observed where Module.load | ||
// is the first function, but there could be variation... | ||
const partOfModuleLoadingCycle = frames.findIndex(({ name }, ix) => { | ||
return /(Module\.load|Module\._load|tryModuleLoad|Module\._extensions.+|Module\._compile|Module.require|require internal.+) module\.js/.test(name) | ||
}) | ||
if (partOfModuleLoadingCycle === 0) { | ||
frames.forEach((frame) => { | ||
if (frame.isInit) return | ||
if (/.+ (internal\/)?module\.js/.test(frame.name)) frame.name += ' [INIT]' | ||
// Loading frames that we matches earlier. | ||
} else if (loadingFrameRegExp.test(frame.name)) { | ||
frame.name += ' [INIT]' | ||
frame.isInit = true | ||
}) | ||
} | ||
} | ||
return frames | ||
} | ||
function removeInstrumentationFrames (frames) { | ||
const preloadDirRx = RegExp(join(__dirname, 'preload')) | ||
return frames.filter((frame) => preloadDirRx.test(frame.name) === false) | ||
} |
{ | ||
"name": "0x", | ||
"version": "4.4.3", | ||
"version": "4.4.4", | ||
"description": "š„ single-command flamegraph profiling š„", | ||
@@ -27,3 +27,3 @@ "main": "index.js", | ||
"dependencies": { | ||
"ajv": "^6.5.3", | ||
"ajv": "^6.5.4", | ||
"browserify": "^16.2.2", | ||
@@ -45,3 +45,3 @@ "concat-stream": "^1.5.2", | ||
"on-net-listen": "^1.1.0", | ||
"opn": "^5.2.0", | ||
"opn": "^5.4.0", | ||
"perf-sym": "^2.0.3", | ||
@@ -48,0 +48,0 @@ "pump": "^3.0.0", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
88758
41
1791
8
Updatedajv@^6.5.4
Updatedopn@^5.4.0