Chrome has a setting that allows you to include native functions when running the profiler.
If you enable the “Show native functions” setting Chrome will show these functions in the profiler output.
A note on how the Chrome profiler works
To find out where your code is spending the most time, the profiler captures a stack trace every 100 μs.
This means that, if a function only takes 50 μs to execute, it may not show up in the profiler at all!
When profiling for more than a few milliseconds you’ll get an accurate understanding of where your app is spending the most time. However, as you zoom in, the information becomes less accurate.
The profiler isn’t consistent either. It will produce a slightly different result every time you run it. Sometimes a very short function call may be recorded, other times it may be missed.
For the purposes of this blog post I’m showing the profiles that are most convenient to demonstrate capturing native functions. When you run the code yourself the results may look different.
So let’s try this out! This is the code I’m running:
Select the “Chart” view in the profiler.
First, without “Show native functions” enabled:
Then after enabling it:
When we hover over the individual function call we can get a more detailed location in the source code.
We can now head over to the Chrome code search and look for “array.js”. The line number won’t be exact though, since the code Chrome is running is likely slightly older than what you find on the Chromium master branch.
You can see that
ArrayJoin is calling through to
Join which calls
DoJoin then calls
%StringBuilderJoin, which is implemented in C++.
We’re steering a bit off-topic, but I think it’s quite fascinating how V8 deals with sparse arrays (
Why is this useful?
What does this code do?
It’s not immediately clear. You don’t normally perform an addition on two arrays. But for some reason some code I looked at recently did that.
Without being able to see native functions all you get is an anonymous function call.
However, native functions reveal that a whole lot is going on. Chrome is stringifying the array by calling
join on it.
Error().stack to obtain a stack trace at the currently running function.
Two separate things happen when we run that code. First we create a new
Error object, then we access its
Obtaining the string version of the stack trace takes a significant amount of time.
I was able to speed up some code I was working on by obtaining an
Error object, but only resolving its
stack property when I wanted to display the stack trace.
At the top of my post I mentioned how looking at small intervals gives inaccurate results. Just to illustrate that, here’s another profile I captured running
FormatErrorString didn’t show up in the previous example!
(The total execution time here is ~1ms, which means Chrome took 10 samples of the call stack. The example above took ~10ms because I called
Error().stack 10 times in a loop.)