mirror of
https://github.com/davidmarkclements/0x.git
synced 2026-01-25 14:47:55 +00:00
Revert "Merge pull request #165 from BridgeAR/filter-init"
This reverts commit be8e703b03ed86d0252d3a32399fef17a415a485, reversing changes made to 2bbc814beeee89693f2a55764a5c41ce22d54a61.
This commit is contained in:
parent
e88214ce22
commit
0a5eb02a0e
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,5 +5,4 @@ node_modules
|
||||
win
|
||||
package-lock.json
|
||||
todo
|
||||
.vscode
|
||||
*.0x
|
||||
.vscode
|
||||
@ -23,7 +23,6 @@ function ticksToTree (ticks, mapFrames, inlined) {
|
||||
stack = removeInstrumentationFrames(stack)
|
||||
if (typeof mapFrames === 'function') stack = mapFrames(stack)
|
||||
if (!stack) return
|
||||
|
||||
stack = stack.map(({name, kind, type}, ix) => {
|
||||
name = name.replace(/ (:[0-9]+:[0-9]+)/, (_, loc) => ` [eval]${loc}`)
|
||||
// 0 no info
|
||||
@ -65,15 +64,14 @@ function ticksToTree (ticks, mapFrames, inlined) {
|
||||
}
|
||||
}
|
||||
if (kind === 'Unopt') S += 1
|
||||
else if (kind === 'Opt') S += 2
|
||||
if (kind === 'Opt') S += 2
|
||||
}
|
||||
|
||||
if (type && type !== 'JS') name += ' [' + type + (kind ? ':' + kind : '') + ']'
|
||||
|
||||
return {S, name, value: 0, top: 0}
|
||||
})
|
||||
|
||||
labelInitFrames(stack)
|
||||
stack = labelInitFrames(stack)
|
||||
|
||||
addToMergedTree(stack.map(({S, name, value, top}) => ({S, name, value, top})))
|
||||
// mutate original (save another loop over stack + extra objects)
|
||||
@ -118,9 +116,9 @@ function ticksToTree (ticks, mapFrames, inlined) {
|
||||
if (child === undefined) {
|
||||
frame.fn = frame.name
|
||||
if (frame.S === 1) frame.name = '~' + frame.name
|
||||
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]'
|
||||
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]'
|
||||
children.push(frame)
|
||||
} else frame = child
|
||||
|
||||
@ -135,14 +133,51 @@ function ticksToTree (ticks, mapFrames, inlined) {
|
||||
return { merged, unmerged }
|
||||
}
|
||||
|
||||
|
||||
function labelInitFrames (frames) {
|
||||
frames.findIndex((frame) => {
|
||||
if (/^.?\(anonymous\) \/.+\.m?js:[0-9]+:[0-9]+/.test(frame.name)) {
|
||||
return true
|
||||
}
|
||||
frame.name += ' [INIT]'
|
||||
frame.isInit = true
|
||||
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
|
||||
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]'
|
||||
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]'
|
||||
frame.isInit = true
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return frames
|
||||
}
|
||||
|
||||
function removeInstrumentationFrames (frames) {
|
||||
|
||||
@ -45,7 +45,6 @@ function linux (args, sudo, binary, cb) {
|
||||
'--',
|
||||
node,
|
||||
'--perf-basic-prof',
|
||||
'-r', path.join(__dirname, '..', 'lib', 'preload', 'no-cluster'),
|
||||
'-r', path.join(__dirname, '..', 'lib', 'preload', 'soft-exit'),
|
||||
...(onPort ? ['-r', path.join(__dirname, '..', 'lib', 'preload', 'detect-port.js')] : [])
|
||||
].filter(Boolean).concat(args.argv), {
|
||||
|
||||
@ -33,7 +33,6 @@ function sun (args, sudo, binary, cb) {
|
||||
|
||||
args = Object.assign([
|
||||
'--perf-basic-prof',
|
||||
'-r', path.join(__dirname, '..', 'lib', 'preload', 'no-cluster'),
|
||||
'-r', path.join(__dirname, '..', 'lib', 'preload', 'soft-exit'),
|
||||
...(onPort ? ['-r', path.join(__dirname, '..', 'lib', 'preload', 'detect-port.js')] : [])
|
||||
].concat(args.argv), args)
|
||||
@ -52,6 +51,7 @@ function sun (args, sudo, binary, cb) {
|
||||
})
|
||||
var folder
|
||||
var prof
|
||||
var profExited = false
|
||||
|
||||
function start () {
|
||||
prof = spawn('sudo', [profile, '-p', proc.pid])
|
||||
@ -80,7 +80,7 @@ function sun (args, sudo, binary, cb) {
|
||||
else status('Profiling')
|
||||
|
||||
start()
|
||||
|
||||
|
||||
if (onPort) when(proc.stdio[5], 'data').then((port) => {
|
||||
const whenPort = spawnOnPort(onPort, port)
|
||||
whenPort.then(() => proc.kill('SIGINT'))
|
||||
@ -122,11 +122,11 @@ function sun (args, sudo, binary, cb) {
|
||||
try { process.kill(prof.pid, 'SIGKILL') } catch (e) {}
|
||||
}
|
||||
|
||||
try {
|
||||
translate = sym({silent: true, pid: proc.pid})
|
||||
try {
|
||||
translate = sym({silent: true, pid: proc.pid})
|
||||
capture(attempts, translate)
|
||||
} catch (e) {
|
||||
setTimeout(capture, 300, attempts - 1)
|
||||
setTimeout(capture, 300, attempts - 1)
|
||||
}
|
||||
} else {
|
||||
status('Unable to find map file!\n')
|
||||
@ -137,7 +137,7 @@ function sun (args, sudo, binary, cb) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
translate = translate || sym({silent: true, pid: proc.pid})
|
||||
|
||||
if (!translate) {
|
||||
|
||||
@ -150,12 +150,12 @@ function collectInliningInfo (sp) {
|
||||
const [ match, inlinedFn ] = /INLINE \((.*)\)/.exec(s) || [ false ]
|
||||
// shouldn't not match though..
|
||||
if (match === false) return cb()
|
||||
|
||||
if (lastOptimizedFrame === null) return cb()
|
||||
|
||||
if (lastOptimizedFrame === null) return cb()
|
||||
const { fn, file } = lastOptimizedFrame
|
||||
// could be a big problem if the fn doesn't match
|
||||
if (fn !== inlinedFn) return cb()
|
||||
|
||||
|
||||
const key = `${fn} ${file}`
|
||||
inlined[key] = inlined[key] || []
|
||||
inlined[key].push(lastOptimizedFrame)
|
||||
@ -177,7 +177,7 @@ function collectInliningInfo (sp) {
|
||||
if (ix === '-1') root = {file, fn, id, ix, pos, key: `${fn} ${file}`}
|
||||
else {
|
||||
lastOptimizedFrame = {file, fn, id, ix, pos, caller: root}
|
||||
}
|
||||
}
|
||||
} else process.stdout.write(s)
|
||||
}
|
||||
|
||||
|
||||
77
readme.md
77
readme.md
@ -16,7 +16,7 @@ on any platform which Node runs on (macOs, Linux, Windows, Android...).
|
||||
* Node v8.5.0 and above
|
||||
* Default usage supports any Operating System that Node runs on!
|
||||
* Chrome
|
||||
* Other browsers may open flamegraphs in a degraded, but functional form
|
||||
* Other browsers may open flamegraphs in a degraded, but functional form
|
||||
|
||||
## Legacy
|
||||
|
||||
@ -82,12 +82,12 @@ generates a profile folder (`<pid>.0x`), containing `flamegraph.html`.
|
||||
|
||||
## The UI
|
||||
|
||||
The `flamegraph.html` file contains the 0x UI, which is explained in
|
||||
The `flamegraph.html` file contains the 0x UI, which is explained in
|
||||
[docs/ui.md](docs/ui.md).
|
||||
|
||||
## Production Servers
|
||||
|
||||
A lightweight, production server friendly, approach to generating a
|
||||
A lightweight, production server friendly, approach to generating a
|
||||
flamegraph is described in [docs/production-servers.md](docs/production-servers.md).
|
||||
|
||||
## The Profile Folder
|
||||
@ -125,30 +125,30 @@ Print usage info.
|
||||
Open the flamegraph in the browser using `open` or `xdg-open` (see
|
||||
https://www.npmjs.com/package/open for details).
|
||||
|
||||
### --on-port | -P
|
||||
### --on-port | -P
|
||||
|
||||
Run a given command and then generate the flamegraph.
|
||||
The command as specified has access to a `$PORT` variable.
|
||||
The `$PORT` variable is set according to the first port that
|
||||
profiled process opens.
|
||||
Run a given command and then generate the flamegraph.
|
||||
The command as specified has access to a `$PORT` variable.
|
||||
The `$PORT` variable is set according to the first port that
|
||||
profiled process opens.
|
||||
|
||||
For instance, here's an example of using [autocannon](http://npm.im/autocannon)
|
||||
For instance, here's an example of using [autocannon](http://npm.im/autocannon)
|
||||
to load-test the process:
|
||||
|
||||
```sh
|
||||
0x -P 'autocannon localhost:$PORT' app.js
|
||||
```
|
||||
|
||||
When the load-test completes, the profiled processed will be
|
||||
sent a SIGINT and the flamegraph will be automatically generated.
|
||||
When the load-test completes, the profiled processed will be
|
||||
sent a SIGINT and the flamegraph will be automatically generated.
|
||||
|
||||
Remember to use single quotes to avoid bash interpolation,
|
||||
or else escape variable (e.g. `0x -P "autocannon localhost:$PORT" app.js`
|
||||
won't work wheras `0x -P "autocannon localhost:\$PORT" app.js` will).
|
||||
|
||||
Note: On Windows interpolation usually occurs with `%PORT%`, however
|
||||
in this case the dollar-prefix `$PORT` is the correct syntax
|
||||
(because the interpolation is not shell based).
|
||||
in this case the dollar-prefix `$PORT` is the correct syntax
|
||||
(because the interpolation is not shell based).
|
||||
|
||||
Default: ''
|
||||
|
||||
@ -156,24 +156,24 @@ Default: ''
|
||||
|
||||
The name of the HTML file, without the .html extension
|
||||
Can be set to - to write HTML to STDOUT (note
|
||||
due to the nature of CLI argument parsing, this must be set using `=`,
|
||||
due to the nature of CLI argument parsing, this must be set using `=`,
|
||||
e.g. `--name=-`).
|
||||
|
||||
If either this flag or `--output-html-file` is set to `-`
|
||||
If either this flag or `--output-html-file` is set to `-`
|
||||
then the HTML will go to STDOUT.
|
||||
|
||||
Default: flamegraph
|
||||
|
||||
### ---title
|
||||
### ---title
|
||||
|
||||
Set the title to display in the flamegraph UI.
|
||||
|
||||
Default: the command that 0x ran to start the process
|
||||
Default: the command that 0x ran to start the process
|
||||
|
||||
### --output-dir | -D
|
||||
|
||||
Specify artifact output directory. This can be specified in template
|
||||
form with possible variables being `{pid}`, `{timestamp}`, `{name}`
|
||||
form with possible variables being `{pid}`, `{timestamp}`, `{name}`
|
||||
(based on the `--name` flag) and `{outputDir}`(variables
|
||||
must be specified without whitespace, e.g. `{ pid }` is not supported).
|
||||
|
||||
@ -181,34 +181,34 @@ Default: `{pid}.0x`
|
||||
|
||||
### --output-html | -F
|
||||
|
||||
Specify destination of the generated flamegraph HTML file.
|
||||
This can be specified in template form with possible variables
|
||||
being `{pid}`, `{timestamp}`, `{name}` (based on the `--name` flag) and
|
||||
`{outputDir}` (variables must be specified without whitespace,
|
||||
e.g. `{ pid }` is not supported). It can also be set to `-` to
|
||||
Specify destination of the generated flamegraph HTML file.
|
||||
This can be specified in template form with possible variables
|
||||
being `{pid}`, `{timestamp}`, `{name}` (based on the `--name` flag) and
|
||||
`{outputDir}` (variables must be specified without whitespace,
|
||||
e.g. `{ pid }` is not supported). It can also be set to `-` to
|
||||
send the HTML output to STDOUT (note
|
||||
due to the nature of CLI argument parsing, this must be set using `=`,
|
||||
due to the nature of CLI argument parsing, this must be set using `=`,
|
||||
e.g. `--output-html=-`).
|
||||
|
||||
If either this flag or `--name` is set to `-`
|
||||
If either this flag or `--name` is set to `-`
|
||||
then the HTML will go to STDOUT.
|
||||
|
||||
Default: `{outputDir}/{name}.html`
|
||||
|
||||
### --kernel-tracing
|
||||
|
||||
Use an OS kernel tracing tool (perf on Linux or
|
||||
dtrace on macOS and SmartOS). This will capture
|
||||
native stack frames (C++ modules and Libuv I/O),
|
||||
Use an OS kernel tracing tool (perf on Linux or
|
||||
dtrace on macOS and SmartOS). This will capture
|
||||
native stack frames (C++ modules and Libuv I/O),
|
||||
but may result in missing stacks on Node 8.
|
||||
|
||||
See [docs/kernel-tracing.md](docs/kernel-tracing.md) for more information.
|
||||
|
||||
Default: false
|
||||
Default: false
|
||||
|
||||
### --quiet | -q
|
||||
### --quiet | -q
|
||||
|
||||
Limit output, the only output will be fatal errors or
|
||||
Limit output, the only output will be fatal errors or
|
||||
the path to the `flamegraph.html` upon successful generation.
|
||||
|
||||
Default: false
|
||||
@ -226,9 +226,9 @@ with relevant outputs.
|
||||
|
||||
Default: false
|
||||
|
||||
### --visualize-only
|
||||
### --visualize-only
|
||||
|
||||
Supply a path to a profile folder to build or rebuild visualization
|
||||
Supply a path to a profile folder to build or rebuild visualization
|
||||
from original stacks.
|
||||
|
||||
Default: undefined
|
||||
@ -246,7 +246,7 @@ file.
|
||||
|
||||
Default: false
|
||||
|
||||
## Programmatic API
|
||||
## Programmatic API
|
||||
|
||||
0x can also be required as a Node module and scripted:
|
||||
|
||||
@ -268,6 +268,7 @@ async function capture () {
|
||||
}
|
||||
|
||||
capture()
|
||||
|
||||
```
|
||||
|
||||
The Programmatic API is detailed in [docs/api.md](docs/api.md).
|
||||
@ -276,9 +277,9 @@ The Programmatic API is detailed in [docs/api.md](docs/api.md).
|
||||
|
||||
### Memory Issues
|
||||
|
||||
Very complex applications with lots of stacks may hit memory issues.
|
||||
Very complex applications with lots of stacks may hit memory issues.
|
||||
|
||||
The `--stack-size` flag can be used to set the memory to the maximum 8GB
|
||||
The `--stack-size` flag can be used to set the memory to the maximum 8GB
|
||||
in order to work around this when profiling:
|
||||
|
||||
```
|
||||
@ -287,7 +288,7 @@ node --stack-size=8024 $(which 0x) my-app.js
|
||||
|
||||
There may still be a problem opening the flamegraph in Chrome. The same work
|
||||
around can be used by opening Chrome from the command line (platform dependent)
|
||||
and nesting the `--stack-size` flag within the `--js-flags` flag:
|
||||
and nesting the `--stack-size` flag within the `--js-flags` flag:
|
||||
`--js-flags="--stack-size 8024"`.
|
||||
|
||||
## Debugging
|
||||
@ -305,7 +306,7 @@ and nesting the `--stack-size` flag within the `--js-flags` flag:
|
||||
Sponsored by [nearForm](http://nearform.com)
|
||||
|
||||
This tool is inspired from various info and code sources
|
||||
and would have taken much longer without the following people and
|
||||
and would have taken much longer without the following people and
|
||||
their Open Source/Info Sharing efforts:
|
||||
|
||||
* Thorsten Lorenz (<http://thlorenz.com/>)
|
||||
|
||||
48
usage.txt
48
usage.txt
@ -1,15 +1,15 @@
|
||||
--open | -o Automatically open after finishing
|
||||
|
||||
|
||||
Default: false
|
||||
|
||||
--on-port | -P Run a given command and then generate
|
||||
the flamegraph. The command as specified
|
||||
has access to a $PORT variable.
|
||||
has access to a $PORT variable.
|
||||
The $PORT variable is set according
|
||||
to the first port that profiled process
|
||||
opens.
|
||||
to the first port that profiled process
|
||||
opens.
|
||||
|
||||
Example:
|
||||
Example:
|
||||
0x -P 'autocannon localhost:$PORT' app.js
|
||||
|
||||
Note: Remember to use single quotes or else
|
||||
@ -19,49 +19,49 @@
|
||||
|
||||
|
||||
-q | --quiet Only output flamegraph URI, and fatal errors.
|
||||
|
||||
|
||||
Default: false
|
||||
|
||||
-s | --silent Complete silence, 0x will not output anything,
|
||||
other than fatal errors.
|
||||
|
||||
|
||||
Default: false
|
||||
|
||||
--kernel-tracing Use an OS kernel tracing tool (perf on Linux or
|
||||
dtrace on macOs and Solaris). This will capture
|
||||
native stack frames (C++ modules and Libuv I/O),
|
||||
--kernel-tracing Use an OS kernel tracing tool (perf on Linux or
|
||||
dtrace on macOs and Solaris). This will capture
|
||||
native stack frames (C++ modules and Libuv I/O),
|
||||
but may result in missing stacks on Node 8.
|
||||
|
||||
|
||||
Default: false
|
||||
|
||||
|
||||
|
||||
--output-dir | -D Specify artifact output directory.
|
||||
Template variables {outputDir}, {pid}, {timestamp}, {cwd}
|
||||
(current working directory) and {name}
|
||||
(current working directory) and {name}
|
||||
(based on the --name flag) are supported.
|
||||
|
||||
Default: '{pid}.0x'
|
||||
|
||||
--output-html | -F Specify destination path for the flamegraph HTML file.
|
||||
Template variables {outputDir}, {pid}, {timestamp}, {cwd}
|
||||
(current working directory) and {name}
|
||||
(based on the --name flag) are supported.
|
||||
(current working directory) and {name}
|
||||
(based on the --name flag) are supported.
|
||||
May also be set to - to send HTML file to STDOUT (note
|
||||
due to the nature of CLI argument parsing, this must be
|
||||
due to the nature of CLI argument parsing, this must be
|
||||
set using =, e.g. --output-html=-).
|
||||
|
||||
If either this flag or --name is set to - then the HTML
|
||||
will go to STDOUT.
|
||||
|
||||
If either this flag or --name is set to - then the HTML
|
||||
will go to STDOUT.
|
||||
|
||||
Default: '{outputDir}/{name}.html'
|
||||
|
||||
--kernel-tracing-debug Show output from dtrace or perf tools.
|
||||
|
||||
--kernel-tracing-debug Show output from dtrace or perf tools.
|
||||
|
||||
Default: false
|
||||
|
||||
--tree-debug Output a JSON file of stacks as {outputDir}/stacks.{pid}.json
|
||||
|
||||
|
||||
Default: false
|
||||
|
||||
--collect-only Do not process captured stacks into a flamegraph.
|
||||
@ -71,16 +71,16 @@
|
||||
|
||||
--name The name of the HTML file, without the .html extension
|
||||
Can be set to - to write HTML to STDOUT (note
|
||||
due to the nature of CLI argument parsing, this must
|
||||
due to the nature of CLI argument parsing, this must
|
||||
be set using =, e.g. --name=-)
|
||||
|
||||
If either this flag or --output-html is set to -
|
||||
If either this flag or --output-html is set to -
|
||||
then the HTML will go to STDOUT.
|
||||
|
||||
Default: flamegraph
|
||||
|
||||
--title Set the title to display in the flamegraph UI
|
||||
|
||||
|
||||
Default: node [nodeFlags] script.js
|
||||
|
||||
-v | --version Output the 0x version
|
||||
|
||||
@ -15,12 +15,11 @@ module.exports = function (trees, opts) {
|
||||
|
||||
const chart = graph()
|
||||
const tree = trees.unmerged // default view
|
||||
|
||||
const categorizer = !kernelTracing && graph.v8cats
|
||||
const flamegraph = fg({
|
||||
categorizer,
|
||||
tree,
|
||||
exclude: Array.from(exclude),
|
||||
categorizer,
|
||||
tree,
|
||||
exclude: Array.from(exclude),
|
||||
element: chart,
|
||||
topOffset: 55
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user