Links

pmuellr is Patrick Mueller

other pmuellr thangs: home page, twitter, flickr, github

Sunday, September 10, 2017

moar profiling!

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 from moar-profiler

Here's what the profile viewer looks like with a profile loaded:

moar profile viewer

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 to stdout
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!