Skip to content

Commit

Permalink
doc: move Plugins to its own documentation file
Browse files Browse the repository at this point in the history
  • Loading branch information
RafaelGSS committed Sep 16, 2024
1 parent f9baeca commit 85006e4
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 180 deletions.
185 changes: 5 additions & 180 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ suite.run();
```

This module uses V8 deoptimization to guarantee the code block won't be eliminated producing
a noop comparisson. See [writting JavasCript Microbenchmark mistakes][] section.
a noop comparisson. See [writting JavasCript Microbenchmark mistakes][#TODO] section.

```console
$ node --allow-natives-syntax my-benchmark.js
Expand All @@ -44,21 +44,8 @@ See [examples folder](./examples/) for common usage.
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)

## Class: `Suite`

Expand Down Expand Up @@ -122,171 +109,9 @@ the stored benchmarks and obtain the corresponding 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 are a powerful mechanism for modifying the benchmark template.

[V8NeverOptimizePlugin](#class-v8neveroptimizeplugin) is enabled by default.

### 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)

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.

### `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 {
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';
}
}
```

## Official Plugins

This is a list of official plugins that can be fetched when requiring
`bench-node` module.

```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.
See [Plugins](./doc/Plugins.md).

## Using custom reporter

Expand Down
167 changes: 167 additions & 0 deletions doc/Plugins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# 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.

[V8NeverOptimizePlugin](#class-v8neveroptimizeplugin) is enabled by default.

## 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)

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.

### `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 {
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';
}
}
```

## Official Plugins

This is a list of official plugins that can be fetched when requiring
`bench-node` module.

```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.

0 comments on commit 85006e4

Please sign in to comment.