π₯ single-command flamegraph profiling π₯
Discover the bottlenecks and hot paths in your code, with flamegraphs.
0x can profile and generate an interactive flamegraph for a Node process with a single command,
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
Older versions of Node are supported via previous 0x versions:
| 0x | Node | macOS/SmartOS | Linux | Windows |
|---|---|---|---|---|
| v4 | v8.5.0+ | βοΈ | βοΈ | βοΈ |
| v3 | v6 β v8.4.0 | βοΈ | βοΈ | ‬ |
| v2 | v4 | βοΈ | βοΈ | ‬ |
An example interactive flamegraph can be viewed at http://davidmarkclements.github.io/0x-demo/
npm install -g 0xUse 0x to run a script:
0x my-app.jsImmediately open the flamegraph in the browser:
0x -o my-app.jsAutomatically execute profiling command against the first port opened by profiled process:
0x -P 'autocannon localhost:$PORT' my-app.jsUse a custom node executable:
0x -- /path/to/node my-app.jsPass custom arguments to node:
0x -- node --zero-fill-buffers my-app.jsWhen ready to generate a flamegraph, send a SIGINT.
The simplest way to do this is pressing CTRL+C.
When 0x catches the SIGINT, it process the stacks and
generates a profile folder (<pid>.0x), containing flamegraph.html.
The flamegraph.html file contains the 0x UI, which is explained in
docs/ui.md.
A lightweight, production server friendly, approach to generating a flamegraph is described in docs/production-servers.md.
By default, a Profile Folder will be created and named after the PID, e.g.
3866.0x (we can set this name manually using the --output-dir flag).
The Profile Folder is explained in more detail in docs/profile-folder.md
Clone this repo, run npm i -g and from the repo root run
0x examples/rest-apiIn another tab run
npm run stress-rest-exampleTo put some load on the rest server, once that's done use ctrl + c to kill the server.
Print usage info.
Open the flamegraph in the browser using open or xdg-open (see
https://www.npmjs.com/package/open for details).
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 to load-test the process:
0x -P 'autocannon localhost:$PORT' app.jsWhen 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).
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 =,
e.g. --name=-).
If either this flag or --output-html-file is set to -
then the HTML will go to STDOUT.
Default: flamegraph
Set the title to display in the flamegraph UI.
Default: the command that 0x ran to start the process
Specify artifact output directory. 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).
Default: {pid}.0x
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 =,
e.g. --output-html=-).
If either this flag or --name is set to -
then the HTML will go to STDOUT.
Default: {outputDir}/{name}.html
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 for more information.
Default: false
Limit output, the only output will be fatal errors or
the path to the flamegraph.html upon successful generation.
Default: false
Suppress all output, except fatal errors.
Default: false
Don't generate the flamegraph, only create the Profile Folder, with relevant outputs.
Default: false
Supply a path to a profile folder to build or rebuild visualization from original stacks.
Default: undefined
Show output from DTrace or perf(1) tools.
Default: false
Save the intermediate tree representation of captured trace output to a JSON file.
Default: false
0x can also be required as a Node module and scripted:
const zeroEks = require('0x')
const path = require('path')
async function capture () {
const opts = {
argv: [path.join(__dirname, 'my-app.js'), '--my-flag', '"value for my flag"'],
workingDir: __dirname
}
try {
const file = await zeroEks(opts)
console.log(`flamegraph in ${file}`)
} catch (e) {
console.error(e)
}
}
capture()The Programmatic API is detailed in docs/api.md.
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
in order to work around this when profiling:
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:
--js-flags="--stack-size 8024".
DEBUG=0x* 0x my-app.js
- https://github.com/brendangregg/FlameGraph (perl)
- https://www.npmjs.com/package/stackvis (node)
- https://www.npmjs.com/package/d3-flame-graph (node)
Sponsored by nearForm
This tool is inspired from various info and code sources and would have taken much longer without the following people and their Open Source/Info Sharing efforts:
- Thorsten Lorenz (http://thlorenz.com/)
- Dave Pacheco (http://dtrace.org/blogs/dap/about/)
- Brendan Gregg (http://www.brendangregg.com/)
- Martin Spier (http://martinspier.io/)
MIT