Security News
Node.js EOL Versions CVE Dubbed the "Worst CVE of the Year" by Security Experts
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
bench-node
Advanced tools
The `bench-node` module allows you to measure operations per second of Node.js code blocks.
bench-node
The bench-node
module allows you to measure operations per second of Node.js code blocks.
$ npm install bench-node
const { Suite } = require('bench-node');
const suite = new Suite({
reporter: (bench, result) => {
console.log(`Benchmark: ${bench.name}`);
console.log(`Operations per second: ${result.opsSec}`);
console.log(`Iterations: ${result.iterations}`);
console.log(`Histogram: ${result.histogram}`);
}
});
suite.add('Using delete property', () => {
const data = { x: 1, y: 2, z: 3 };
delete data.y;
data.x;
data.y;
data.z;
});
suite.run().then(results => {
console.log('Benchmark complete.');
}).catch(err => {
console.error('Error running benchmarks:', err);
});
This module uses V8 deoptimization to helps that the code block is not optimized away, producing accurate benchmarks -- But, not realistics. See the Writing JavaScript Microbenchmark Mistakes section for more details.
$ node --allow-natives-syntax my-benchmark.js
Using delete property x 3,326,913 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(0ns ... 0ns) p75=0ns p99=0ns
See the examples folder for more common usage examples.
Suite
Stability: 1.1 Active Development
A Suite
manages and executes benchmark functions. It provides two methods: add()
and run()
.
new Suite([options])
options
{Object} Configuration options for the suite. Supported properties:
reporter
{Function} Callback function for reporting results. Receives two arguments:
suite
{Suite} The Suite instance.result
{Object} Contains:
opsSec
{string} Operations per second.iterations
{Number} Number of iterations.histogram
{Histogram} Histogram instance.If no reporter
is provided, results are printed to the console.
const { Suite } = require('bench-node');
const suite = new Suite();
If you don't want results to be printed to the console, false
and null
can be used
const { Suite } = require('bench-node');
const suite = new Suite({ reporter: false });
suite.add(name[, options], fn)
name
{string} The name of the benchmark, displayed when reporting results.options
{Object} Configuration options for the benchmark. Supported properties:
minTime
{number} Minimum duration for the benchmark to run. Default: 0.05
seconds.maxTime
{number} Maximum duration for the benchmark to run. Default: 0.5
seconds.fn
{Function|AsyncFunction} The benchmark function. Can be synchronous or asynchronous.Adds a benchmark function to the suite.
$ node --allow-natives-syntax my-benchmark.js
Using delete property x 5,853,505 ops/sec ± 0.01% (10 runs sampled) min..max=(169ns ... 171ns) p75=170ns p99=171ns
suite.run()
{Promise<Array<Object>>}
An array of benchmark results, each containing:
opsSec
{number} Operations per second.iterations
{number} Number of executions of fn
.histogram
{Histogram} Histogram of benchmark iterations.name
{string} Benchmark name.plugins
{Object} Object with plugin results if any plugins are active.Runs all added benchmarks and returns the results.
Plugins extend the functionality of the benchmark module.
See Plugins for details.
isSupported()
: Checks if the plugin can run in the current environment.beforeClockTemplate(varNames)
: Injects code before the benchmark starts. Returns an array with:
Code
{string} JavaScript code to execute.Wrapper
{string} (optional) Function to wrap the benchmark function.afterClockTemplate(varNames)
: Injects code after the benchmark finishes. Returns an array with:
Code
{string} JavaScript code to execute.onCompleteBenchmark(result)
: Called when the benchmark completes, allowing plugins to process results.toString()
: Returns a string identifier for the plugin.class V8OptimizeOnNextCallPlugin {
isSupported() {
try {
new Function(`%OptimizeFunctionOnNextCall(() => {})`)();
return true;
} catch (e) {
return false;
}
}
beforeClockTemplate({ awaitOrEmpty, bench }) {
let code = '';
code += `%OptimizeFunctionOnNextCall(${bench}.fn);\n`;
code += `${awaitOrEmpty}${bench}.fn();\n`;
code += `${awaitOrEmpty}${bench}.fn();\n`;
return [code];
}
toString() {
return 'V8OptimizeOnNextCallPlugin';
}
}
Customize data reporting by providing a reporter
function when creating the Suite
:
const { Suite } = require('bench-node');
function reporter(bench, result) {
console.log(`Benchmark: ${bench.name}`);
console.log(`Operations per second: ${result.opsSec}`);
console.log(`Iterations: ${result.iterations}`);
console.log(`Histogram: ${result.histogram}`);
}
const suite = new Suite({ reporter });
suite.add('Using delete to remove property from object', () => {
const data = { x: 1, y: 2, z: 3 };
delete data.y;
data.x;
data.y;
data.z;
});
suite.run();
$ node --allow-natives-syntax my-benchmark.js
Benchmark: Using delete to remove property from object - 6,032,212 ops/sec
Control the benchmark function's setup and teardown using the timer argument:
const { Suite } = require('bench-node');
const { readFileSync, writeFileSync, rmSync } = require('node:fs');
const suite = new Suite();
suite.add('readFileSync', (timer) => {
const randomFile = Date.now();
const filePath = `./${randomFile}.txt`;
writeFileSync(filePath, Math.random().toString());
timer.start();
readFileSync(filePath, 'utf8');
timer.end();
rmSync(filePath);
}).run();
For advanced setups, use the timer argument to start and end timing explicitly:
const { Suite } = require('bench-node');
const { readFileSync, writeFileSync, rmSync } = require('node:fs');
const suite = new Suite();
suite.add('readFileSync', (timer) => {
const randomFile = Date.now();
const filePath = `./${randomFile}.txt`;
writeFileSync(filePath, Math.random().toString());
timer.start();
for (let i = 0; i < timer.count; i++) {
readFileSync(filePath, 'utf8');
}
timer.end(timer.count);
rmSync(filePath);
});
suite.run();
[!WARNING] When using the
timer
, the setup will also be deoptimized. As a result, if you compare this approach with one that uses functions outside the benchmark function, the results may not match. See: Deleting Properties Example.
Ensure you call .start()
and .end()
methods when using the timer argument, or an ERR_BENCHMARK_MISSING_OPERATION
error will be thrown.
In regular benchmarks (when timer
is not used), you run the benchmarked function in a loop,
and the timing is managed implicitly.
This means each iteration of the benchmarked function is measured directly.
The downside is that optimizations like inlining or caching might affect the timing, especially for fast operations.
Example:
suite.add('Using includes', function () {
const text = 'text/html,...';
const r = text.includes('application/json');
});
Here, %DoNotOptimize
is being called inside the loop for regular benchmarks (assuming V8NeverOptimizePlugin is being used),
ensuring that the operation is not overly optimized within each loop iteration.
This prevents V8 from optimizing away the operation (e.g., skipping certain steps because the result is not used or the function is too trivial).
Managed benchmarks explicitly handle timing through start()
and end()
calls around the benchmarked code.
This encapsulates the entire set of iterations in one timed block,
which can result in tighter measurement with less overhead.
However, it can lead to over-optimistic results, especially if the timer’s start and stop calls are placed outside of the loop,
allowing V8 to over-optimize the entire block.
Example:
suite.add('[Managed] Using includes', function (timer) {
timer.start();
for (let i = 0; i < timer.count; i++) {
const text = 'text/html,...';
const r = text.includes('application/json');
assert.ok(r); // Ensure the result is used so it doesn't get V8 optimized away
}
timer.end(timer.count);
});
In this case, %DoNotOptimize
is being applied outside the loop, so it does not protect each iteration from
excessive optimization. This can result in higher operation counts because V8 might optimize away repetitive tasks.
That's why an assert.ok(r)
has been used. To avoid V8 optimizing the entire block as the r
var was not being used.
[!NOTE] V8 assumptions can change any time soon. Therefore, it's crucial to investigate results between versions of V8/Node.js.
FAQs
The `bench-node` module allows you to measure operations per second of Node.js code blocks.
We found that bench-node demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.