New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

bench-node

Package Overview
Dependencies
Maintainers
0
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bench-node - npm Package Compare versions

Comparing version 0.0.4-beta.1 to 0.0.4-beta.2

doc/Plugins.md

15

lib/clock.js

@@ -1,2 +0,2 @@

const { debug } = require('node:util');
const { debug, types } = require('node:util');
const { validateNumber } = require('./validators');

@@ -35,18 +35,18 @@

if (timeInNs > 1e9) {
return `${ (timeInNs / 1e9, 2).toFixed() }s`;
return `${ (timeInNs / 1e9).toFixed(2) }s`;
}
if (timeInNs > 1e6) {
return `${ (timeInNs / 1e6, 2).toFixed() }ms`;
return `${ (timeInNs / 1e6).toFixed(2) }ms`;
}
if (timeInNs > 1e3) {
return `${ (timeInNs / 1e3, 2).toFixed() }us`;
return `${ (timeInNs / 1e3).toFixed(2) }us`;
}
if (timeInNs > 1e2) {
return `${ (timeInNs, 0).toFixed() }ns`;
return `${ (timeInNs).toFixed(2) }ns`;
}
return `${ (timeInNs, 2).toFixed() }ns`;
return `${ (timeInNs).toFixed(2) }ns`;
}

@@ -203,3 +203,3 @@ }

function createRunner(bench, recommendedCount) {
const isAsync = bench.fn.constructor === AsyncFunction;
const isAsync = types.isAsyncFunction(bench.fn);
const hasArg = bench.fn.length >= 1;

@@ -209,3 +209,2 @@

process.emitWarning(`The benchmark "${ bench.name }" function should not have more than 1 argument.`);
process.exit(1);
}

@@ -212,0 +211,0 @@

@@ -115,7 +115,10 @@ const { validateNumber } = require('./validators');

calculateStd() {
const avgSquares = this.all.reduce(
(acc, value) => Math.min(Number.MAX_SAFE_INTEGER, Math.pow(value, 2) + acc), 0,
) * (1 / this.all.length);
this.stddev = Math.sqrt(Math.max(0, this.all.length / (this.all.length - 1) * (avgSquares - (this.mean * this.mean))));
if (this.all.length < 2) {
this.stddev = 0;
return;
}
const variance = this.all.reduce((acc, value) => {
return acc + Math.pow(value - this.mean, 2);
}, 0) / (this.all.length - 1);
this.stddev = Math.sqrt(variance);
}

@@ -129,3 +132,3 @@

calculateCv() {
if (this.all.length < 2) {
if (this.all.length < 2 || this.mean === 0) {
this.cv = 0;

@@ -132,0 +135,0 @@ return;

@@ -16,3 +16,3 @@ const { clockBenchmark, debugBench, MIN_RESOLUTION, timer } = require('./clock');

const result = {}
for (p of plugins) {
for (const p of plugins) {
result[p.toString()] = p.getResult?.() ?? 'enabled';

@@ -19,0 +19,0 @@ }

{
"name": "bench-node",
"version": "0.0.4-beta.1",
"version": "0.0.4-beta.2",
"description": "",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

@@ -1,10 +0,9 @@

# bench-node
# `bench-node`
The `bench-node` module gives the ability to measure
operations per second of Node.js code block
The `bench-node` module allows you to measure operations per second of Node.js code blocks.
## Install
```console
$ npm i bench-node
```bash
$ npm install bench-node
```

@@ -17,5 +16,12 @@

const suite = new Suite();
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 to remove property from object', function() {
suite.add('Using delete property', () => {
const data = { x: 1, y: 2, z: 3 };

@@ -29,36 +35,26 @@ delete data.y;

suite.run();
suite.run().then(results => {
console.log('Benchmark complete.');
}).catch(err => {
console.error('Error running benchmarks:', err);
});
```
This module uses V8 deoptimization to guarantee the code block won't be eliminated producing
a noop comparisson. See [writting JavasCript Microbenchmark mistakes][] section.
This module uses V8 deoptimization to ensure that the code block is not optimized away, producing accurate benchmarks. See the [Writing JavaScript Microbenchmark Mistakes](#TODO) section for more details.
```console
```bash
$ 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
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 [examples folder](./examples/) for common usage.
See the [examples folder](./examples/) for more common usage examples.
## Table of Contents
1. [class `Suite`](#class-suite)
1. [Class `Suite`](#class-suite)
1. [`suite.add()`](#suiteaddname-options-fn)
2. [`suite.run()`](#suiterun)
2. [Plugins](#plugins)
1. [Structure](#structure)
2. [Plugin Methods](#plugin-methods)
* [`isSupported()` (required)](#issupported-required)
* [`beforeClockTemplate(varNames)`](#beforeclocktemplatevarnames)
* [`afterClockTemplate(varNames)`](#afterclocktemplatevarnames)
* [`onCompleteBenchmark(result)`](#oncompletebenchmarkresult)
* [`toString()` (required)](#tostring-required)
3. [Example Plugins](#example-plugins)
* [V8OptimizeOnNextCallPlugin](#class-v8optimizeonnextcallplugin)
3. [Official Plugins](#official-plugins)
* [Class: `V8OptimizeOnNextCallPlugin`](#class-v8optimizeonnextcallplugin-1)
* [Class: `V8NeverOptimizePlugin`](#class-v8neveroptimizeplugin)
* [Class: `V8GetOptimizationStatus`](#class-v8getoptimizationstatus)
4. [Using custom reporter](#using-custom-reporter)
5. [Setup and Teardown](#setup-and-teardown)
3. [Using Custom Reporter](#using-custom-reporter)
4. [Setup and Teardown](#setup-and-teardown)

@@ -69,16 +65,15 @@ ## Class: `Suite`

An `Suite` is responsible for managing and executing
benchmark functions. It provides two methods: `add()` and `run()`.
A `Suite` manages and executes benchmark functions. It provides two methods: `add()` and `run()`.
### `new Suite([options])`
* `options` {Object} Configuration options for the suite. The following
properties are supported:
* `reporter` {Function} Callback function with results to be called after
benchmark is concluded. The callback function should receive two arguments:
`suite` - A {Suite} object and
`result` - A object containing three properties:
`opsSec` {string}, `iterations {Number}`, `histogram` {Histogram} instance.
* `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, the results will printed to the console.
If no `reporter` is provided, results are printed to the console.

@@ -92,20 +87,14 @@ ```js

* `name` {string} The name of the benchmark, which is displayed when reporting
benchmark results.
* `options` {Object} Configuration options for the benchmark. The following
properties are supported:
* `minTime` {number} The minimum time a benchmark can run.
**Default:** `0.05` seconds.
* `maxTime` {number} The maximum time a benchmark can run.
**Default:** `0.5` seconds.
* `fn` {Function|AsyncFunction}
* `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.
* Returns: {Suite}
This method stores the benchmark of a given function (`fn`).
The `fn` parameter can be either an asynchronous (`async function () {}`) or
a synchronous (`function () {}`) function.
Adds a benchmark function to the suite.
```console
```bash
$ 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
Using delete property x 5,853,505 ops/sec ± 0.01% (10 runs sampled) min..max=(169ns ... 171ns) p75=170ns p99=171ns
```

@@ -115,127 +104,31 @@

* Returns: `{Promise<Array<Object>>}`
* `opsSec` {number} The amount of operations per second
* `iterations` {number} The amount executions of `fn`
* `histogram` {Histogram} Histogram object used to record benchmark iterations
* `name` {string} Benchmark name
* `plugins` {object} Object containing the plugin results if there's one active
* Returns: `{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.
The purpose of the run method is to run all the benchmarks that have been
added to the suite using the [`suite.add()`][] function.
By calling the run method, you can easily trigger the execution of all
the stored benchmarks and obtain the corresponding results.
Runs all added benchmarks and returns the results.
## Plugins
The benchmark module supports a flexible plugin system that
allows you to extend its functionality by adding custom plugins.
This documentation explains how to create, validate, and use
plugins within the benchmarking framework.
Plugins extend the functionality of the benchmark module.
[V8NeverOptimizePlugin](#class-v8neveroptimizeplugin) is enabled by default.
See [Plugins](./doc/Plugins.md) for details.
### Structure
Each plugin is expected to follow a specific structure with required methods
for integration into the benchmark module. The plugins are required to define
the following methods:
* `isSupported()`: This method checks if the plugin can run in the
current environment. If the plugin uses features specific to certain
environments (e.g., V8 engine features), it should return `true` if those
features are available and `false` otherwise.
* `toString()`: This method should return a string representation of the plugin.
It’s used for logging and error messages.
In addition to these required methods, plugins can optionally define other
methods based on their functionality, such as `beforeClockTemplate()`,
`afterClockTemplate()`, `onCompleteBenchmark()`, and more.
### Plugin Methods
### `isSupported()` (required)
- **`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.
This method checks if the plugin's functionality is available in the
current environment. For instance, if a plugin uses specific V8 engine commands,
this method ensures the environment supports them.
### Example Plugin
### `beforeClockTemplate(varNames)`
* `varNames` {Object}
* `bench` {string} - Name for the benchmark variable.
* `context` {string} - Name for the context variable.
* `timer` {string} - Name for the timer variable.
* `awaitOrEmpty` {string} - A string with `await` or empty string (`''`).
Some plugins need to modify or prepare the code before the benchmark starts.
The `beforeClockTemplate()` method allows you to inject code before the timing
process begins.
This method must return an array where:
* The first element is a string representing the JavaScript code to be executed
before the benchmark function.
* The second element (optional) is a string representing a function that will
wrap the benchmark function. This wrapper is used to customize how the
benchmark function is called during execution.
The wrapped function provides a powerful way to manipulate how the benchmark
is run without directly modifying the benchmark logic.
```js
beforeClockTemplate() {
let code = '';
code += `
function DoNotOptimize(x) {}
// Prevent DoNotOptimize from optimizing or being inlined.
%NeverOptimizeFunction(DoNotOptimize);
`
return [code, 'DoNotOptimize'];
}
```
In this example, the plugin injects the `DoNotOptimize` function and also
provides it as a wrapper for the benchmark function.
### `afterClockTemplate(varNames)`
* `varNames` {Object}
* `bench` {string} - Name for the benchmark variable.
* `context` {string} - Name for the context variable.
* `timer` {string} - Name for the timer variable.
* `awaitOrEmpty` {string} - A string with `await` or empty string (`''`).
After the benchmark runs, this method can inject code to gather performance data
or reset configurations. It must return an array where:
* The first element is a string containing the JavaScript code to be executed
after the benchmark finishes.
Unlike `beforeClockTemplate`, `afterClockTemplate` does not support a second
element in the returned array, as it only runs cleanup or data collection code
after the benchmark is executed.
### `onCompleteBenchmark(result)`
* `result` {Object}
* `duration` {number} - Benchmark duration
* `count` {number} - Number of iterations
* `context` {Object} - A object used to store results after the benchmark clock
This method is called when the benchmark completes. Plugins can collect and
process data from the benchmark results in this step.
### `toString()` (required)
This method returns a string identifier for the plugin, typically the plugin’s
name. It is used in error messages and logging.
### Example Plugins
Here are examples of plugins that follow the required structure and functionality.
```js
class V8OptimizeOnNextCallPlugin {

@@ -253,7 +146,5 @@ isSupported() {

let code = '';
code += `%OptimizeFunctionOnNextCall(${ bench }.fn);\n`;
code += `${ awaitOrEmpty }${ bench }.fn();\n`;
code += `${ awaitOrEmpty }${ bench }.fn();\n`;
code += `%OptimizeFunctionOnNextCall(${bench}.fn);\n`;
code += `${awaitOrEmpty}${bench}.fn();\n`;
code += `${awaitOrEmpty}${bench}.fn();\n`;
return [code];

@@ -268,40 +159,14 @@ }

## Official Plugins
## Using Custom Reporter
This is a list of official plugins that can be fetched when requiring
`bench-node` module.
Customize data reporting by providing a `reporter` function when creating the `Suite`:
```js
const { V8OptimizeOnNextCallPlugin, Suite } = require('bench-node');
const suite = new Suite({
plugins: [new V8OptimizeOnNextCallPlugin()],
})
```
### Class: `V8OptimizeOnNextCallPlugin`
The `V8OptimizeOnNextCallPlugin` triggers the V8 engine to optimize the
function before it is called. This can improve performance in repeated
benchmarks.
### Class: `V8NeverOptimizePlugin`
The `V8NeverOptimizePlugin` prevents the V8 engine from optimizing or inlining
a function, useful when you want to benchmark functions without any
optimization.
### Class: `V8GetOptimizationStatus`
The `V8GetOptimizationStatus` plugin collects the V8 engine's optimization
status for a given function after it has been benchmarked.
## Using custom reporter
You can customize the data reporting by passing an function to the `reporter` argument while creating your `Suite`:
```js
const { Suite } = require('bench-node');
function reporter(bench, result) {
console.log(`Benchmark: ${bench.name} - ${result.opsSec} ops/sec`);
console.log(`Benchmark: ${bench.name}`);
console.log(`Operations per second: ${result.opsSec}`);
console.log(`Iterations: ${result.iterations}`);
console.log(`Histogram: ${result.histogram}`);
}

@@ -323,5 +188,5 @@

```console
```bash
$ node --allow-natives-syntax my-benchmark.js
Benchmark: Using delete to remove property from object - 6032212 ops/sec
Benchmark: Using delete to remove property from object - 6,032,212 ops/sec
```

@@ -331,6 +196,5 @@

The benchmark function has a special handling when you pass an argument,
for example:
Control the benchmark function's setup and teardown using the timer argument:
```cjs
```js
const { Suite } = require('bench-node');

@@ -354,10 +218,4 @@ const { readFileSync, writeFileSync, rmSync } = require('node:fs');

In this way, you can control when the `timer` will start
and also when the `timer` will stop.
For advanced setups, use the timer argument to start and end timing explicitly:
In the timer, we also give you a property `count`
that will tell you how much iterations
you should run your function to achieve the `benchmark.minTime`,
see the following example:
```js

@@ -375,7 +233,5 @@ const { Suite } = require('bench-node');

timer.start();
for (let i = 0; i < timer.count; i++)
for (let i = 0; i < timer.count; i++) {
readFileSync(filePath, 'utf8');
// You must send to the `.end` function the amount of
// times you executed the function, by default,
// the end will be called with value 1.
}
timer.end(timer.count);

@@ -389,4 +245,2 @@

Once your function has at least one argument,
you must call `.start` and `.end`, if you didn't,
it will throw the error `ERR_BENCHMARK_MISSING_OPERATION`
Ensure you call `.start()` and `.end()` methods when using the timer argument, or an `ERR_BENCHMARK_MISSING_OPERATION` error will be thrown.

@@ -172,5 +172,1 @@ const { Suite } = require('../lib/index');

});
todo('async tasks should behave similar to sync tasks', async () => {
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc