CPU Profiling
CPU Profiling allows you to understand where opportunities exist to improve the speed and load capacity of your Node processes.
Analyzing the Function Call Stack
Generated CPU profiles can be used to indicate all of the functions on the function call stack. For instance, if a function foo()
calls a function bar()
during its execution, and a sample was taken while bar()
was running, the function call stack will show that foo()
called bar()
. Because multiple samples may be taken while bar()
is executing, there will be an approximate start and stop time recorded for bar()
, which is an indication of how long it took to run. In addition, further samples before and after the ones that captured bar()
will capture foo()
, and likewise to the bottom of the function call stack.
This data can then be analyzed to show, for the function foo()
, how much time was actually spent in foo()
and not in bar()
. Every function has two time values, a self time and a total time. For the foo()
and bar()
case, if foo()
only calls the bar()
function, then the self time for foo()
plus the total time for bar()
will equal the total time for foo()
:
function foo() {
… processing that takes a lot of time but calls no other functions ...
bar()
… processing that takes a lot of time but calls no other functions …
}
function bar() {
…
}
foo() total time
= foo() self time
+ bar() total time
Note: Total time shows you which functions are fastest and slowest, from start to finish, but does not definitively tell you if the time was spent in that function or other functions.
Named Functions
Named functions are easier to spot in CPU profiles. The stack frame entries available in a CPU profile include the name of a function, and source code location information for detail views. For anonymous functions, the name will often be displayed as "(anonymous)". In some cases, the V8 JavaScript engine can calculate an "inferred name" for a function. When possible, name functions so that they can be easily spotted in a CPU profile.
For instance, a function busyFunction()
, which you like to easily track the callers for, is being called from an anonymous function:
setInterval(function(){busyFunction()}, 1000)
In a CPU profile, you'll see that busyFunction()
is being called by (anonymous)
.
To make this easier to spot in a CPU profile, you can simply use:
setInterval(function busyFunctionCaller(){busyFunction()}, 1000)
In the CPU profile, you'll now see that busyFunction()
is called by busyFunctionCaller()
.
For additional code cleanliness and clearer profiling, consider moving the entire function out into the same scope as the function usage:
setInterval(busyFunctionCaller, 1000)
//...
function busyFunctionCaller() {
busyFunction()
}
Because JavaScript functions are "hoisted" to the top level of the scope they're defined in, you can reference busyFunctionCaller
before it is actually defined.