Piano
A performance monitoring require
hook for Node.js.
What does it do?
When you enable piano, all javascript processed by require
will be processed by piano,
which will wrap all function declarations in a __decl
call. Whenever a piano-wrapped function
is called, piano will record the length of time it took for that call to complete.
When you're done, just ask piano for the results, and you can perform analytics on the collected data.
Example
var piano = ready = var plate = tpl = '{% for i in x %}{{ i }}{% endfor %}' i = 0 ctxt = x:12345678910 SAMPLES = 100 tpl
API
var piano =
var ready = piano([pathFragment | regex])
Hooks piano onto require.extensions['.js']
. All files required after this point
will be parsed by piano if they match the path fragment (or regex). If no path or
regex is provided, it will attempt to process all javascript files will be processed.
ready(function(taps, helpers) { })
Call this function when you're finished running the code to be analyzed. It will call the provided callback
with a list of Tap
objects representing all processed functions, as well as a helpers
object, that contains
several 'sort' functions to help you sort your output.
Helpers include:
helpers.calls // sort by number of calls
helpers.min // sort by the minimum call time
helpers.max // sort by the maximum call time
helpers.avg // sort by the average call time
helpers.total // sort by the total amount of time spent in a function
// usage:
var ready = piano();
ready(function(taps, helpers) {
taps.
sort(helpers.calls).
forEach(function(tap) {
console.log(tap.calls.length)
})
})
ready.on('tap', function(tap, executionContext) {})
Emitted whenever a 'tapped' function is run -- that is, any function processed by piano.
It will be called with two arguments -- a Tap
object that represents piano's bookkeeping
on the current function, and an ExecutionContext
that represents all functions processed
by piano, as well as the current stack depth.
ready.release()
Restores the original require.extensions['.js']
callback.
ExecutionContext
An execution context may only be accessed through the on('tap')
event, and has the following attributes:
ready
Tap
A tap object contains all bookkeeping done for a function processed by piano. It is available via the on('tap')
function,
as well as when calling ready
. It has the following methods:
Tap#min
Returns the quickest call to the tapped function as an integer representing microseconds.
Tap#max
Returns the slowest call to the tapped function as an integer representing microseconds.
Tap#avg
Return the average time taken by a function over all calls as a float representing microseconds.
Tap#total
Return the total number of microseconds taken by a function over the duration of the test.
Tap#source
Returns the original line of code that generated the tap as a string.
Tap also has the following properties:
Tap.tapped_function
The original function object.
Tap.calls
An array of {start:integer, end:integer}
pairs, each representing a separate call to the function (and subsequent exit of the function).
Tap.filename
The filename the Tap was generated from.
Tap.line
The line number the Tap was generated from.
A Quick Note
Piano creates Taps
keyed by the function content concatenated to the filename and line number that the function was seen at.
This means that Piano will not create multiple taps for inlined functions -- even though inlined functions strictly represent separate objects in V8. An example:
var { // an inlined function: return { }; };
Will create one Tap
for fn
, and one Tap
for the function returned by fn. If, hypothetically, piano created Taps
based
on whether the function was present in a list of functions, the previous code would have generated 3 taps -- one for fn
, one for
the first time fn()()
was called, and one for the second time fn()()
was called. Since this isn't very useful behavior, I opted
to make Piano pay attention to the originating source of the function, not the function object itself.
LICENSE
MIT.