3 июн. 2020 г.

Profiling JavaScript code with Linux perf command

Profile V8 internals on Linux:

$ perf record d8 --perf-basic-prof test.js
$ perf report


Easy installation of V8 engine: https://www.npmjs.com/package/jsvu

Customize output of Benchmark.js results

By default Benchmark.js recommends the following code to view results of a benchmark:

.on('cycle', function(event) {
    console.log(String(event.target));
})

Example output:

<test 1> x 123,456 ops/sec ±5.67% (75 runs sampled)
<test 2> x 112,678 ops/sec ±4.56% (77 runs sampled)

The problem is that operations per second are not additive: if <test 2> has some added/removed code, we don't know the cost of that code in milliseconds (how many milliseconds it adds or removes from the total execution time).

To get that information, change the output code as follows:

.on('cycle', function(event) { const stats = event.target.stats; const sortedSample = stats.sample.sort((a, b) => b - a); const median = sortedSample[sortedSample.length >> 1]; const fastest = sortedSample[sortedSample.length - 1]; console.log( String(event.target), '\n\tfastest:', fastest * 1000000, 'μs/op', '\n\tmean:', stats.mean * 1000000, 'μs/op', // '±' + stats.rme.toFixed(2) + '%', '\n\tmedian:', median * 1000000, 'μs/op' ); })

here stats.rme means "relative margin of error" and is the same "±5.67%" as in example output above, so there is no need to duplicate it

Same code in TypeScript:

.on('cycle', function(event: { target: { stats: Stats }; }) { const stats: Stats = event.target.stats; const sortedSample = stats.sample.sort((a, b) => b - a); const median = sortedSample[sortedSample.length >> 1]; const fastest = sortedSample[sortedSample.length - 1]; console.log( String(event.target), '\n\tfastest:', fastest * 1000000, 'μs/op', '\n\tmean:', stats.mean * 1000000, 'μs/op', '\n\tmedian:', median * 1000000, 'μs/op' ); })

Type description (borrowed from https://benchmarkjs.com/docs):

type Stats = { /** The sample standard deviation. */ deviation: number, /** The sample arithmetic mean (secs). */ mean: number, /** The margin of error. */ moe: number, /** The relative margin of error (expressed as a percentage of the mean). */ rme: number, /** The array of sampled periods. */ sample: number[], /** The standard error of the mean. */ sem: number, /** The sample variance. */ variance: number };