Simple benchmarking tool for command-line (Node.js) and Web.
Install the benchmark library as a development dependency:
npm install -D @kayahr/benchmark
This is an example to benchmark the speed of Math.max
compared to a manual conditional expression:
import { benchmark } from "@kayahr/benchmark";
await benchmark([
{ name: "Math.max", operation: (a, b) => Math.max(a, b) },
{ name: "Conditional", operation: (a, b) => (a > b) ? a : b }
]);
The benchmark
function takes an array of test definitions. Each test definition has a name
property for displaying in the benchmark result, and an
operation
property defining a closure function containing the code to benchmark.
The operation function receives two numeric arguments which can be used as entropy to generate dynamic results which can be returned by the function to prevent the JS engine from discarding dead code or optimizing static code. The first argument is the current iteration index, starting with 0 and incremented on each iteration within the current test cycle. The second argument is the total number of iterations done in the current test cycle.
For the operation function the meaning of these two parameters usually do not matter. They are used as entropy because they already exist and doesn't consume time to calculate. Just keep in mind that the first value starts with 0 and is incremented by one on each iteration and the second one is always greater than 0 and stays the same within the current test cycle. Here are some examples how these two arguments could be used:
(a, b) => Math.max(a, b)
or a => Math.pow(a, 2)
. But don't use the arguments in places where large values can make trouble. Using one of the arguments as exponent for Math.pow
would be a bad idea and would most likely end up with Infinity
as a result. Instead you could use the first argument to toggle between two exponents: a => Math.pow(1234, a & 1 ? 10 : 20)
a => new Array(1000).fill(a)
. But don't use any of the two parameters as array size because depending on the benchmark speed the numbers can get very high.a => ("Test-String-" + a).toLowerCase()
Test data which is shared in all test runs can be created before the benchmark call and can be initialized/reset before each test cycle with an init callback like this:
let array: number[];
// Benchmark array clearing
await benchmark([
{
name: "Set length to 0",
operation: () => array.length = 0
},
{
name: "Set new empty array",
operation: () => array = []
},
{
name: "Call splice",
operation: () => array.splice(0)
}
], {
init: () => {
array = [ 1, 2, 3, 4 ];
}
});
To run the benchmark in Node.js, simply execute the JavaScript file with node
. It constantly measures the speed of all tests and updates the output every 250 milliseconds:
$ node benchmark-clear-array.js
╔═════════════════════╤════════════════════════════════════════════════════════╗
║ Test │ Speed (Latest) 137,257,007 ops/s ║
╟─────────────────────┼─────────┬──────────────────────────────────────────────╢
║ Set length to 0 │ 22.4 % │ ■■■■■■■■■■ ║
║ Set new empty array │ 100.0 % │ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ║
║ Call splice │ 55.4 % │ ■■■■■■■■■■■■■■■■■■■■■■■■ ║
╚═════════════════════╧═════════╧══════════════════════════════════════════════╝
Benchmarking... (Press CTRL-C or Q to quit, M to toggle speed display mode)
With the hotkey M
you can switch between latest and average speed. With Q
or Ctrl-C
you can exit the benchmark.
If the console is not interactive (for example when redirecting output into a file) then the benchmark is run 25 times (approximately 7 seconds) and the average result is printed once:
$ node benchmark-clear-array.js > result.txt
$ cat result.txt
╔═════════════════════╤════════════════════════════════════════════════════════╗
║ Test │ Speed (Average) 123,635,798 ops/s ║
╟─────────────────────┼─────────┬──────────────────────────────────────────────╢
║ Set length to 0 │ 24.8 % │ ■■■■■■■■■■■ ║
║ Set new empty array │ 100.0 % │ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ║
║ Call splice │ 58.4 % │ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ║
╚═════════════════════╧═════════╧══════════════════════════════════════════════╝
The easiest way is to run the benchmark script with node and the --web
command line option:
$ node benchmark-clear-array.js --web
Benchmark served on http://localhost:49152/
Press Ctrl-C to exit
And then simply open the given URL in the browser of your choice:
This solution is based on esbuild to bundle the benchmark script and all its dependencies into a single JavaScript file and starting a simple Node.js HTTP server to serve this JavaScript file together with a minimum HTML index file.
An alternative way is using a local webserver which can serve your projects via HTTP (like Apache with a public_html
directory) and writing an HTML file which defines an ESM import map to load dependencies like @kayahr/benchmark
and other dependencies needed by your benchmark tests and then load the benchmark test script as an ES module at the place where your want the output to appear:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Clear Array Benchmark</title>
<script type="importmap">
{
"imports": {
"@kayahr/benchmark": "./node_modules/@kayahr/benchmark/lib/main/index.js"
}
}
</script>
</head>
<body>
<script type="module" src="benchmark-clear-array.js"></script>
</body>
</html>