Skip to content

Instantly share code, notes, and snippets.

@zeusdeux
Last active June 15, 2023 20:33
Show Gist options
  • Save zeusdeux/aac6f8500917319213c5 to your computer and use it in GitHub Desktop.
Save zeusdeux/aac6f8500917319213c5 to your computer and use it in GitHub Desktop.
Node.js flamegraphs on osx using instruments.app, node and http://thlorenz.github.io/flamegraph/web/

Flamegraphs for your node processes on OS X

This document will help you generate flamegraphs for your node processes on OS X.

You can read about the various types of flamegraphs and how they are useful
in Brendan Gregg's wonderful write up here.

By the end of this document, you should have a flamegraph for you node app to play with.

Let's get started.

Pre-requisites

  • Install Xcode from the App Store if you don't have it already
    • In this exercise, we need Xcode mainly so that we can use the instruments.app that comes packaged with it. Though it is quite a joy to have when you're trying to bridge C/C++ code with js land (see lldb-jbt)
  • Install node (version > 0.11.x). Distributions can be found here

Steps

  1. Open instruments.app
  2. Look for Time Profiler in the window that is presented to you and open it Time Profiler in instruments.app
  3. Run your node process with the --perf-basic-prof flag. This flag tells v8 to generate a perf-<pid>.map file (in /tmp/ by default) which can be consumed by the perf tool on *nix systems. You can read more here
  • Example node --perf-basic-prof app.js
    • It's a good idea to print the process.pid in app.js as we'll be using it later
      • console.log(process.pid) should suffice
  1. Go back to the Time Profiler window in instruments.app
  2. Click All Processes in the UI and select your node process (based on your process pid) node process in All Processes
  3. Hit the Record button (the red button in the left corner in the Time Profiler UI) to start recording a trace
  4. Click Stop when you've a large enough sample to work with (this is completely subjective as it depends on what you're actually looking for)
  5. In the Call Tree section of the Time Profiler UI, expand a tree fully (option + right arrow) Call tree
  6. In the menu bar for instruments.app, click on Instrument -> Export track for 'Time Profiler - node'... and save the csv file Save trace as csv
  7. Goto the flamegraph app by thlorenz.
  8. Upload you csv you saved in step 9 as the file for Callgraph
  • You should see a flamegraph appear with hex memory addresses. The next step will make those addresses take on human readable names
  1. Upload the map file as the file for Mapfile
  • To get to the map file, do the following
    • Click choose file in the flamegraph web app UI
    • In the file dialog that opens up, press cmd + shift + g
    • Type /tmp in the dialog that pops up and hit Go
    • In the folder that opens up, select perf-<your node process pid>.map and click Open
  1. Aaand we're done. The svg file should now have human readable symbols in place of hex memory addresses.

Happy debuggin'!

@thlorenz
Copy link

thlorenz commented Jan 4, 2015

Actually there is a faster way to launch instruments if you got a local Node.js copy.
Load it into Xcode, set your args in Run tab and configure Profiling tab.

Then simply press CMD-I in order to start profiling with Instruments. That's faster than attaching to process every time and the preferred way if you do this repeatedly.
That also allows you to quickly patch v8 in order to ensure that perf-<pid>.map file gets flushed continuously.

I'm pretty sure I used the other technique in this talk and it quickly becomes obvious how annoying it is to attach repeatedly.

@zeusdeux
Copy link
Author

zeusdeux commented Jan 4, 2015

Afaik, most node devs don't have a local copy of the source (most nvm it), let alone an Xcode project for node which is why I went with these instructions.

Nevertheless, I shall add the Xcode project method too for the veterans out there. Mainly for v8 patch trick to flush the mapfile continuously (atleast when I am debugging).

Do you have some docs on how to generate an Xcode project directly (will need to add this bit too) instead instantiating an empty one and then adding node src etc? If I am not wrong, there's something that I can pass to ./configure I think. Do not remember.

And yeah, I remember this method from that very talk haha. Also, I might know why the demo didn't work at the end 😜.

@thlorenz
Copy link

thlorenz commented Jan 4, 2015

Here is a script to just paste into the terminal to create Xcode project, pretty simple actually.
To just create the Xcode project without building you can omit the make step.

@zeusdeux
Copy link
Author

zeusdeux commented Jan 4, 2015

Awesome, let me add that in.

@zeusdeux
Copy link
Author

zeusdeux commented Jan 4, 2015

The Run tab and Profiling tab are the ones under Edit Scheme right?
What are the arguments that you provide under Profiling and Run?
For Run I am going to guess its node --perf-basic-prof app.js, but Profiling I am blank.

@ChuntaoLu
Copy link

It's worth noting that --perf-basic-prof flag requires node version at least v0.11

@bringingkatigbak
Copy link

Also worth noting that in order for the perf-.map to actually work I had to add the following line to my main file (server.js)
process.on('SIGINT',function(){server.close(); process.exit(0);});

HTH!

also, I used the forked version of flamegraphs that supports the -m flag

@shaine
Copy link

shaine commented Oct 14, 2016

The Time Profiler in the current Instruments.app doesn't seem to have an export option anymore. :/

@shaine
Copy link

shaine commented Oct 14, 2016

Oh, I'm talking about Instruments 8.0 on the Sierra beta - that's probably my problem.

@mattvv
Copy link

mattvv commented Oct 19, 2016

@zeusdeux Awesome instructions, although I cannot export. After expanding the tree I'm unable to export. Just getting a greyed out 'Export Data'

@tjmehta
Copy link

tjmehta commented Oct 20, 2016

I see the same "Instrument > Export Data..." is greyed out

@jamesabc
Copy link

+1 more to "Export Data..." being greyed out. Very frustrating as it's a difficult problem to google...

@fabdrol
Copy link

fabdrol commented Feb 28, 2017

@jamesabc @tjmehta same here, any progress?

@BlooJeans
Copy link

+1 to Export Data being greyed out

@mtin
Copy link

mtin commented Jun 20, 2017

+1 on 10.12.5 with Instruments 8.3.3, can not export the Time Profiler - what a mess.

@andiwinata
Copy link

andiwinata commented Feb 27, 2018

+1 to Export Data being greyed out

But found this library https://github.com/davidmarkclements/0x that works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment