I'm a long-time fan of using CPU profilers to analyze programs.
CPU profilers are great because they provide insight into our programs that you can't get easily any other way - how fast - or more likely how slow - are functions in your code. I've learned with profilers that there's no point in guessing what code you think is fast or slow, because:
- you're likely wrong, or will find surprises
- it's so easy to profile some code, just do it!
For Node.js, there are some useful profilers available:
Of course I'm partial to N|Solid since I work on it, <wink/>.
And yet ... I've grown a little restless with our current crop of profiling tools.
The defacto visualization for profiles is flame graphs. But I have issues:
the interesting dimension to be looking for is the widths of the boxes, but my eye is often drawn to the heights
they don't provide much room for textual information, since many of the boxes can be very thin
usually, all I care about looking at a profile are the most expensive functions, but visually sorting box widths across a 2 dimensional graph of boxes doesn't make a lot of sense
The age-old profile visualization is the table/tree, where functions are displayed as rows in a table, but can be expanded to show the callers or callees of the individual functions. While a grand idea - merging tables and trees into a single UI widget - it's also as tedious as you can imagine it might be. Lots of clicking to expand/contract the tree bits, and then the whole thing gets very noisy.
Both of these tools are sufficient, and do provide a lot of value, but ... I feel like we can do better.
And so I've started playing with some new tooling:
moar-profiler
- a command-line tool to generate profiles for Node.js processes, that adds even moar information to the profile than what v8 provides (eg, source, package info, process meta data). These profiles are compatible with every v8.cpuprofile
digesting tool, they just extend the data provided in the "standard" profile data.moar-profile-viewer
- a web app to view v8.cpuprofile
files generated from Node.js profiling tools, that provides even moar goodies when displaying profiles generated frommoar-profiler
Here's what the profile viewer looks like with a profile loaded:
The viewer is at Minimum Viable Product state. There are no graphs. There are no call stacks. There are only lists of functions, and the ability to get more information on those functions - callers and callees - and a view of the source code of the function. Gotta start somewhere!
Some of the fun stuff the profile viewer does have is:
displaying the package and version a function came from, along with a link to the package info at npmjs.org
annotated source code
ability to toggle hiding "system" functions vs "user" functions
Generating a profile with moar-profiler
is pretty easy:
- run your program with the
--inspect
option (requires Node.js >= version 6):
node --inspect myProgram.js arg1 arg2 ...
- in a separate terminal, run
moar-profiler
which will generate the profile tostdout
moar-profiler --duration 5 9229 > myProgram.cpuprofile
In this case, a 5 second profile will be collected, by connecting to the Node.js process using the inspect port 9229 (the default inspect port).
Now that you have a .cpuprofile
file, head over to the moar profile viewer web
app, and load the file (or drop it on the page).
If you would like to test drive the web app without generating a .cpuprofile
file first, you can download this file, which is a profile of npm update
, and
then load it or drop it in the moar profile viewer web
app:
If you don't feel comfortable sending a .cpuprofile
file over the intertubes,
you can clone the moar-profile-viewer repo and open the docs/index.html
page
on your own machine - it's a single page app in an .html
file - no server
required.
There's a bunch of cleanup to do with the viewer, but I'd like for it to serve
as a basis for further investigation. The cool thing with both
moar-profiler
and the moar profile viewer is that they work with existing v8
profile tools. If you really need a flame chart from a profile generated with
moar-profiler
, just load it into your flavorite profile visualizer (eg, Chrome
DevTools). Likewise, the moar profile viewer can read profiles generated
with other Node.js profiling tools, but you won't have as nice of an experience
compared to profiles generated with moar-profiler
.
I do want to provide the ability to see call stacks, somehow. Current thought is Graphviz visualizations of the call stacks involving a selected function. Those might be small enough to provide useful visualization. Previous experiments rendering the entire profile call graph as a single Graphviz graph were ... disastrous, as most extremely large and complex Graphviz graphs tend to be.
This is all open source, of course, so feel free to chime in and help out. I'm obviously interested in bug reports, but also new feature requests. Dream on!