Full Code of RafaelGSS/bench-node for AI

main 0765fdc5aa64 cached
107 files
299.9 KB
91.2k tokens
195 symbols
1 requests
Download .txt
Showing preview only (326K chars total). Download the full file or copy to clipboard to get everything.
Repository: RafaelGSS/bench-node
Branch: main
Commit: 0765fdc5aa64
Files: 107
Total size: 299.9 KB

Directory structure:
gitextract_nbr14g_8/

├── .devcontainer/
│   └── devcontainer.json
├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       ├── benchmark-comparison.yml
│       ├── commit-message-validation.yml
│       ├── release.yml
│       ├── runner_warmer.yml
│       └── test.yml
├── .gitignore
├── .npmignore
├── .release-please-manifest.json
├── BENCHMARK_COMPARISSON.md
├── CHANGELOG.md
├── Dockerfile
├── README.md
├── assets/
│   └── README.md
├── bench-node-0.14.0.tgz
├── biome.json
├── doc/
│   ├── Inconclusive.md
│   └── Plugins.md
├── examples/
│   ├── .gitignore
│   ├── benchmark-comparison/
│   │   ├── README.md
│   │   └── comparison.js
│   ├── chart-report/
│   │   └── node.js
│   ├── create-uint32array/
│   │   ├── node.js
│   │   └── node.js.log
│   ├── crypto-verify/
│   │   ├── node.js
│   │   ├── node.js.log
│   │   ├── private-key.pem
│   │   └── public-key.pem
│   ├── csv-report/
│   │   └── node.js
│   ├── dce-detection/
│   │   ├── example.js
│   │   ├── with-dce-disabled.js
│   │   └── without-never-optimize.js
│   ├── deleting-properties/
│   │   ├── node.js
│   │   └── node.js.log
│   ├── empty/
│   │   ├── node.js
│   │   └── node.js.log
│   ├── fs-read-async/
│   │   ├── node.js
│   │   ├── node.js.log
│   │   ├── node.managed.js
│   │   ├── node.managed.js.log
│   │   └── sample-file.txt
│   ├── fs-read-sync/
│   │   ├── node.js
│   │   ├── node.js.log
│   │   └── sample-file.txt
│   ├── html-report/
│   │   ├── node.js
│   │   └── result.html
│   ├── json-report/
│   │   └── node.js
│   ├── plugins/
│   │   ├── all.js
│   │   ├── all.js.log
│   │   ├── memory.js
│   │   ├── v8-get-opt-status.js
│   │   ├── v8-get-opt-status.js.log
│   │   ├── v8-never-optimize.js
│   │   ├── v8-never-optimize.js.log
│   │   ├── v8-optimize-next-call.js
│   │   └── v8-optimize-next-call.js.log
│   ├── pretty-report/
│   │   └── node.js
│   ├── run.sh
│   ├── statistical-significance/
│   │   ├── README.md
│   │   └── node.js
│   ├── string-replace/
│   │   ├── node.js
│   │   └── node.js.log
│   ├── string-searching/
│   │   ├── node.js
│   │   └── node.js.log
│   ├── time-mode.js
│   └── worker-threads/
│       └── node.js
├── index.d.ts
├── lib/
│   ├── clock.js
│   ├── histogram.js
│   ├── index.js
│   ├── lifecycle.js
│   ├── plugins/
│   │   ├── dce-detection.js
│   │   ├── memory.js
│   │   ├── v8-never-opt.js
│   │   ├── v8-opt.js
│   │   └── v8-print-status.js
│   ├── plugins.js
│   ├── report.js
│   ├── reporter/
│   │   ├── chart.js
│   │   ├── csv.js
│   │   ├── html.js
│   │   ├── json.js
│   │   ├── pretty.js
│   │   ├── template.html
│   │   └── text.js
│   ├── utils/
│   │   ├── analyze.js
│   │   ├── styleText.js
│   │   └── ttest.js
│   ├── validators.js
│   └── worker-runner.js
├── package.json
├── release-please-config.json
├── test/
│   ├── async.js
│   ├── basic.js
│   ├── env.js
│   ├── fixtures/
│   │   ├── bench.js
│   │   ├── copy.js
│   │   └── opt-managed.js
│   ├── managed.js
│   ├── plugin-api-doc.js
│   ├── plugins.js
│   ├── reporter.js
│   ├── time-mode.js
│   ├── ttest.js
│   └── worker.js
└── types/
    └── types.test-d.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .devcontainer/devcontainer.json
================================================
{
	"name": "Bench-node Container",
	"build": {
		"dockerfile": "../Dockerfile"
	}
}


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [RafaelGSS] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']


================================================
FILE: .github/workflows/benchmark-comparison.yml
================================================
name: Benchmark Comparison

on:
  push:
    branches:
      - main
  workflow_dispatch:

permissions:
  issues: write
  contents: read
  id-token: write

jobs:
  runner-start:
    runs-on: ubuntu-latest
    steps:
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v5
        with:
          aws-region: us-west-2
          role-to-assume: arn:aws:iam::800406105498:role/RafaelGSS-nodejs-bench-operations
      - name: Checkout
        uses: actions/checkout@v5

      - name: Start Runner
        uses: nodesource/aws-eco-runner@v1.0.0-beta.3
        with:
          instances_id: '["i-065f0f848eb1615ae"]'
          action: 'start'
          aws_default_region: 'us-west-2'

  benchmark:
    name: Run Benchmark Comparisons
    runs-on: self-hosted
    continue-on-error: true

    strategy:
      matrix:
        node-version: [20, 22, 24]

    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: ${{ matrix.node-version }}

      - name: Install dependencies
        run: npm install --dev

      - name: Run basic comparison
        run: node --allow-natives-syntax examples/benchmark-comparison/comparison.js


================================================
FILE: .github/workflows/commit-message-validation.yml
================================================
name: Commit Message Validation

on:
  pull_request:

jobs:
  validate:
    name: Validate
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0

      - uses: webiny/action-conventional-commits@v1.3.0
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  push:
    branches:
      - main

permissions:
  contents: write
  pull-requests: write
  id-token: write

jobs:
  release-please:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v5

      - name: Release Please
        uses: google-github-actions/release-please-action@v4
        id: release

      - name: Use Node 22.x
        uses: actions/setup-node@v6
        if: ${{ steps.release.outputs.release_created }}
        with:
          node-version: 22
          registry-url: 'https://registry.npmjs.org'

      - name: Install Deps
        run: npm install
        if: ${{ steps.release.outputs.release_created }}

      - name: NPM Publish
        run: npm publish --provenance --access public
        if: ${{ steps.release.outputs.release_created }}
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}


================================================
FILE: .github/workflows/runner_warmer.yml
================================================
name: Cron - Keep Runners Active

on:
  schedule:
    # Runs this workflow every Sunday at 12:00 UTC. You can adjust the schedule according to your needs.
    - cron: '0 12 * * 0'
  workflow_dispatch: # Allows manual triggering of the workflow

permissions:
  issues: write
  contents: read
  id-token: write

jobs:
  start_runner:
    runs-on: ubuntu-latest
    steps:
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v5
        with:
          aws-region: us-west-2
          role-to-assume: arn:aws:iam::800406105498:role/RafaelGSS-nodejs-bench-operations

      - name: Start Runner
        uses: nodesource/aws-eco-runner@v1.0.0-beta.3
        with:
          instances_id: '["i-065f0f848eb1615ae"]'
          action: 'start'
          aws_default_region: 'us-west-2'

  keep-runner-active:
    runs-on: [self-hosted]
    steps:
      - name: Run task to keep the runner active
        run: echo "Keep the runner active"


================================================
FILE: .github/workflows/test.yml
================================================
name: Test CI

on:
  push:
    branches:
      - main
  pull_request:

permissions:
  issues: write
  contents: read
  id-token: write

jobs:
  runner-start:
    runs-on: ubuntu-latest
    steps:
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v5
        with:
          aws-region: us-west-2
          role-to-assume: arn:aws:iam::800406105498:role/RafaelGSS-nodejs-bench-operations
      - name: Checkout
        uses: actions/checkout@v5

      - name: Start Runner
        uses: nodesource/aws-eco-runner@v1.0.0-beta.3
        with:
          instances_id: '["i-065f0f848eb1615ae"]'
          action: 'start'
          aws_default_region: 'us-west-2'

  build:
    runs-on: self-hosted

    strategy:
      matrix:
        node-version: [18, 20, 22, 24, 25]

    env:
      CI: true

    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Set up Node.js
        uses: actions/setup-node@v6
        with:
          node-version: ${{ matrix.node-version }}

      - name: Install dependencies
        run: npm install

      - name: Run tests
        run: npm test


================================================
FILE: .gitignore
================================================
tags
.idea
node_modules/
package-lock.json

coverage


================================================
FILE: .npmignore
================================================
# We don't want to publish the logo and others
assets

coverage


================================================
FILE: .release-please-manifest.json
================================================
{
	".": "0.15.0"
}


================================================
FILE: BENCHMARK_COMPARISSON.md
================================================
# Benchmark Library Comparison

This document provides a comprehensive comparison between `bench-node` and other popular Node.js benchmarking libraries based on real benchmark results across different Node.js versions. This comparison helps identify potential errors in our benchmarking approach and provides insights for specific algorithm comparisons.

## Overview

The following benchmarking libraries are compared in this document:

- **bench-node** - Our library with V8 optimization control
- **benchmark.js** - The most popular JavaScript benchmarking library
- **mitata** - Modern, fast benchmarking library
- **tinybench** - Lightweight benchmarking tool

## Test Environment

All benchmarks were executed on:
- **CPU**: Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz
- **Platform**: Linux x64
- **Node.js versions**: 20.19.3, 22.17.0, 24.3.0



## Detailed Benchmark Results

### Simple Operations - JIT Optimizable

This test measures a simple operation that V8 can heavily optimize:

#### Node.js 24.3.0
| Library | ops/sec | Margin | Relative Performance |
|---------|---------|--------|---------------------|
| benchmark.js | 141,211,777 | ±5.18% | **1.00x** (baseline) |
| bench-node | 125,902,288 | N/A | 0.89x |
| mitata | 37,131,930 | ±5.00% | 0.26x |
| tinybench | 28,207,575 | ±0.10% | 0.20x |

#### Node.js 22.17.0
| Library | ops/sec | Margin | Relative Performance |
|---------|---------|--------|---------------------|
| benchmark.js | 142,037,530 | ±3.88% | **1.00x** (baseline) |
| bench-node | 141,504,337 | N/A | 1.00x |
| tinybench | 17,040,169 | ±1.40% | 0.12x |
| mitata | 12,382,061 | ±5.00% | 0.09x |

#### Node.js 20.19.3
| Library | ops/sec | Margin | Relative Performance |
|---------|---------|--------|---------------------|
| **benchmark.js** | **843,084,082** | ±0.25% | **1.00x** (baseline) |
| bench-node | 136,801,267 | N/A | 0.16x |
| tinybench | 24,275,731 | ±0.11% | 0.03x |
| mitata | 18,411,459 | ±5.00% | 0.02x |



### String Processing - Regex Test

This test performs regex matching on strings:

#### Cross-Version Comparison
| Node.js Version | bench-node | benchmark.js | mitata | tinybench |
|-----------------|------------|--------------|--------|-----------|
| **24.3.0** | 4,352,775 | 4,299,609 (±0.58%) | 3,543,737 (±5.00%) | 3,654,837 (±0.40%) |
| **22.17.0** | 4,349,482 | 4,382,198 (±0.49%) | 3,933,431 (±5.00%) | 3,526,797 (±0.83%) |
| **20.19.3** | 4,419,500 | 4,320,038 (±0.40%) | 3,475,360 (±5.00%) | 3,698,242 (±1.85%) |



### CPU Intensive - Fibonacci Calculations

#### Fibonacci(10) - Light CPU Load

| Node.js Version | benchmark.js | bench-node | mitata | tinybench |
|-----------------|--------------|------------|--------|-----------|
| **24.3.0** | 77,510,123 (±2.38%) | 69,120,722 | 42,308,343 (±5.00%) | 26,206,646 (±0.09%) |
| **22.17.0** | 56,097,219 (±1.68%) | 54,623,064 | 51,268,905 (±5.00%) | 15,451,469 (±0.09%) |
| **20.19.3** | 73,590,107 (±0.23%) | 57,284,808 | 10,910,003 (±5.00%) | 22,108,774 (±0.11%) |

#### Fibonacci(30) - Medium CPU Load

| Node.js Version | benchmark.js | bench-node | mitata | tinybench |
|-----------------|--------------|------------|--------|-----------|
| **24.3.0** | 43,276,919 (±1.26%) | 40,936,562 | 30,824,240 (±5.00%) | 18,752,734 (±0.11%) |
| **22.17.0** | 22,187,269 (±0.53%) | 21,316,196 | 14,024,655 (±5.00%) | 11,373,272 (±1.98%) |
| **20.19.3** | 22,078,755 (±0.27%) | 21,783,805 | 21,708,455 (±5.00%) | 14,162,915 (±0.11%) |

#### Fibonacci(40) - Heavy CPU Load

| Node.js Version | benchmark.js | bench-node | mitata | tinybench |
|-----------------|--------------|------------|--------|-----------|
| **24.3.0** | 35,115,900 (±1.30%) | 33,956,245 | 26,752,990 (±5.00%) | 18,719,206 (±0.10%) |
| **22.17.0** | 16,511,904 (±0.91%) | 16,112,632 | 15,599,164 (±5.00%) | 9,496,167 (±4.91%) |
| **20.19.3** | 16,726,334 (±0.31%) | 16,504,271 | 16,264,129 (±5.00%) | 11,755,080 (±3.32%) |

### Fibonacci Recursive(10) - Algorithm Comparison

| Node.js Version | bench-node | mitata | benchmark.js | tinybench |
|-----------------|------------|--------|--------------|-----------|
| **24.3.0** | **999,165** | 992,635 (±5.00%) | 986,251 (±0.31%) | 977,228 (±0.09%) |
| **22.17.0** | **978,652** | 972,507 (±5.00%) | 969,517 (±0.30%) | 938,449 (±0.07%) |
| **20.19.3** | **989,935** | 939,466 (±5.00%) | 973,359 (±0.19%) | 965,775 (±0.07%) |


---

*Last updated: August 2025 | Based on bench-node v2.x, benchmark.js v2.1.4, mitata v1.x, tinybench v2.x*
*Benchmark workflow: [benchmark-comparison.yml](https://github.com/RafaelGSS/bench-node/actions/workflows/benchmark-comparison.yml)*
*Test results from Node.js versions 20.19.3, 22.17.0, and 24.3.0*

================================================
FILE: CHANGELOG.md
================================================
# Changelog

## [0.15.0](https://github.com/RafaelGSS/bench-node/compare/v0.14.0...v0.15.0) (2026-05-08)


### Features

* Add fixed-unit time format to JSON min/max output for use in ([#157](https://github.com/RafaelGSS/bench-node/issues/157)) ([38d10d1](https://github.com/RafaelGSS/bench-node/commit/38d10d1ad5bb56d66fc60e764b7eb54eaa1f5d1e))
* Expose bar width flag. ([#152](https://github.com/RafaelGSS/bench-node/issues/152)) ([83ddc1d](https://github.com/RafaelGSS/bench-node/commit/83ddc1d720feb7746598dbde9a887e96766531a2))
* Support benchmark warmup with useWorkers=true ([#154](https://github.com/RafaelGSS/bench-node/issues/154)) ([f73ed33](https://github.com/RafaelGSS/bench-node/commit/f73ed3366300993aa7189fef306df417c3da173e))


### Bug Fixes

* **plugin:** make V8NeverOptimizePlugin target benchmark functions ([#163](https://github.com/RafaelGSS/bench-node/issues/163)) ([c0975c8](https://github.com/RafaelGSS/bench-node/commit/c0975c80d35edafa8820a375e744339de772fe30))


### Miscellaneous Chores

* --test flag propagation appears to be fixed. ([#162](https://github.com/RafaelGSS/bench-node/issues/162)) ([8750bfc](https://github.com/RafaelGSS/bench-node/commit/8750bfc7b7580cd2199f8c62e75fe96462aea6e5))
* add node v25 to test matrix ([#144](https://github.com/RafaelGSS/bench-node/issues/144)) ([08526ea](https://github.com/RafaelGSS/bench-node/commit/08526ea0e561328a72862d2c0cd42717884cd6a2))
* add node v25 to test matrix ([#159](https://github.com/RafaelGSS/bench-node/issues/159)) ([946bbdc](https://github.com/RafaelGSS/bench-node/commit/946bbdc068a6f955e631470acea608648e868665))


### Code Refactoring

* Clarify the purpose and units of various numbers in lifecycle.js ([#151](https://github.com/RafaelGSS/bench-node/issues/151)) ([28e872e](https://github.com/RafaelGSS/bench-node/commit/28e872eab08a92a8c364f1885a76f1a57f7de141))

## [0.14.0](https://github.com/RafaelGSS/bench-node/compare/v0.13.0...v0.14.0) (2025-12-17)


### Features

* add dce detection plugin ([#131](https://github.com/RafaelGSS/bench-node/issues/131)) ([2e2a6be](https://github.com/RafaelGSS/bench-node/commit/2e2a6be87e7dc7562952dd53b9e34017e0822b8e))
* add t-test mode for statistical significance testing ([#133](https://github.com/RafaelGSS/bench-node/issues/133)) ([53e20aa](https://github.com/RafaelGSS/bench-node/commit/53e20aae67fbd747a05465b6ad824f56483e231a))
* Narrow the bar display by another couple of characters by using ANSI line drawing. ([#134](https://github.com/RafaelGSS/bench-node/issues/134)) ([814e88e](https://github.com/RafaelGSS/bench-node/commit/814e88e905da60d00615a2b95cfeed23b6034c7d))


### Bug Fixes

* Clock inaccuracy in libuv is causing flaky tests. ([cad6bfa](https://github.com/RafaelGSS/bench-node/commit/cad6bfac1b03f270da38c81f3d1703db95a7b0f4))
* implement support to timers to workers ([35eb144](https://github.com/RafaelGSS/bench-node/commit/35eb144908e76b73667ef6de9131c4d37425974b))


### Miscellaneous Chores

* Localize op/sec in text reporter ([#146](https://github.com/RafaelGSS/bench-node/issues/146)) ([18302e3](https://github.com/RafaelGSS/bench-node/commit/18302e369b3f430d35fe856177d0fd0a55592eaf))

## [0.13.0](https://github.com/RafaelGSS/bench-node/compare/v0.12.0...v0.13.0) (2025-11-27)


### Features

* export to<format> functions and rework some of the tests. ([960cb87](https://github.com/RafaelGSS/bench-node/commit/960cb87caf3e73c01550cf93127679991c928ef8))


### Miscellaneous Chores

* change printTree to formatTree ([d6ff418](https://github.com/RafaelGSS/bench-node/commit/d6ff418dcc50fbe256b89e9bd562521efc8b7095))
* Convert json reporter to allow json generation to string. ([cfc464c](https://github.com/RafaelGSS/bench-node/commit/cfc464c4709c1ed4415ff86d486a29dc39556708))
* Convert printResult to generate a line of output. ([4199a57](https://github.com/RafaelGSS/bench-node/commit/4199a578f29eec173b5c22a21affb80c9b415f07))
* extract toCSV from csv reporter. ([033dd4b](https://github.com/RafaelGSS/bench-node/commit/033dd4bdd8cd874d0fe985a0f6dae34666452e68))
* Extract toPretty() method ([c2e54a3](https://github.com/RafaelGSS/bench-node/commit/c2e54a36387ff812c461961724e66aa2389e4358))
* extract toText from text reporter ([db850ca](https://github.com/RafaelGSS/bench-node/commit/db850ca95b124fd8f4a1ce8dd140868be2f2de5d))
* Move lint after unit tests. ([e0c019d](https://github.com/RafaelGSS/bench-node/commit/e0c019d48c9bdd77dc934e2c5c15231fd1a3b836))
* Move short branch to top of conditional block. ([e7254b3](https://github.com/RafaelGSS/bench-node/commit/e7254b35286f58a18622c30aebea7d2e127542b7))
* Remove duplicate time code in pretty and text printers ([a977b97](https://github.com/RafaelGSS/bench-node/commit/a977b972adab5b947b290bb347c774d93ff011fd))
* Split out text only chart creation function. ([80538fa](https://github.com/RafaelGSS/bench-node/commit/80538fa6447fe542284a6f58d1d8f08c0d362696))
* Use report for tests. ([b14db92](https://github.com/RafaelGSS/bench-node/commit/b14db929b058f2a25717a0ff83f5f911c015fb66))

## [0.12.0](https://github.com/RafaelGSS/bench-node/compare/v0.11.0...v0.12.0) (2025-11-03)


### Features

* add several code refactor/fixes ([#123](https://github.com/RafaelGSS/bench-node/issues/123)) ([cf96c3d](https://github.com/RafaelGSS/bench-node/commit/cf96c3deaace1086df64dfa0424aeb5bbe90ca5f))
* Deduplicate the data summarization code. ([#120](https://github.com/RafaelGSS/bench-node/issues/120)) ([85bfd3e](https://github.com/RafaelGSS/bench-node/commit/85bfd3e8b4a7da047859c70a1ec5e43e81161c10))
* make minSamples option available per Suite creation ([#126](https://github.com/RafaelGSS/bench-node/issues/126)) ([152b945](https://github.com/RafaelGSS/bench-node/commit/152b94571e870246db75311e80b962451e2af9ca))


### Bug Fixes

* **plugins:** export plugin memory ([52bb536](https://github.com/RafaelGSS/bench-node/commit/52bb536117460cff49518881a5680b96ef06426c))


### Miscellaneous Chores

* **index.d.ts:** update exported types for plugins ([abc828f](https://github.com/RafaelGSS/bench-node/commit/abc828fd7f77fe6bb48aa239155e1ad4ca9f9e63))
* typo ([#125](https://github.com/RafaelGSS/bench-node/issues/125)) ([88aff41](https://github.com/RafaelGSS/bench-node/commit/88aff41f3b190a005fd33160b41a888f9227b3b4))


### Code Refactoring

* **plugins:** enable support for memory & fixes on types ([cd4f96e](https://github.com/RafaelGSS/bench-node/commit/cd4f96e5a48a3381242047c18fc082e293ef7723))


### Continuous Integration

* bump ci ([#124](https://github.com/RafaelGSS/bench-node/issues/124)) ([2d7ba17](https://github.com/RafaelGSS/bench-node/commit/2d7ba17eac29328a7d09393efe2692960c84c869))

## [0.11.0](https://github.com/RafaelGSS/bench-node/compare/v0.10.0...v0.11.0) (2025-09-22)


### Features

* add comparisson with other benchmark libs ([#106](https://github.com/RafaelGSS/bench-node/issues/106)) ([19de73f](https://github.com/RafaelGSS/bench-node/commit/19de73f3a3fb4f11e8ea1d746154c8f3391d0192))
* Allow for configurable column width for the chart output. ([#104](https://github.com/RafaelGSS/bench-node/issues/104)) ([315d551](https://github.com/RafaelGSS/bench-node/commit/315d551209e25827c844c0f4a301afa6e2bc276b))
* reduce NPM package size by adding files field to package.json ([#111](https://github.com/RafaelGSS/bench-node/issues/111)) ([a584269](https://github.com/RafaelGSS/bench-node/commit/a584269c8267a30a3fb9b0bb77fccf201f77381c))


### Bug Fixes

* optional iterations count for end(), add type tests ([a4dc145](https://github.com/RafaelGSS/bench-node/commit/a4dc145dee4dd53d331cd294771f83333efba7f6))


### Documentation

* add comprehensive library comparison document ([#109](https://github.com/RafaelGSS/bench-node/issues/109)) ([caa18a9](https://github.com/RafaelGSS/bench-node/commit/caa18a914f416be9f53357d2a2c8e2ca8a092c66))


### Miscellaneous Chores

* **main:** release 0.11.0.beta-1 ([b234ce7](https://github.com/RafaelGSS/bench-node/commit/b234ce76b8f03db0b4668eaddf531291819bd922))
* use active versions only for bench comparisson ([#107](https://github.com/RafaelGSS/bench-node/issues/107)) ([bf119c7](https://github.com/RafaelGSS/bench-node/commit/bf119c783df026ad40b7e26209fc7b2368b6a292))

## [0.10.0](https://github.com/RafaelGSS/bench-node/compare/v0.9.0...v0.10.0) (2025-07-31)


### Features

* Add code coverage to the test code. ([#96](https://github.com/RafaelGSS/bench-node/issues/96)) ([daff350](https://github.com/RafaelGSS/bench-node/commit/daff3509be6731e7415eaa2a8ba0b7464d1b7408))
* add fastest/slowest value for feature parity with benchmark.js ([9ad4c94](https://github.com/RafaelGSS/bench-node/commit/9ad4c9461f105f7681a77f80a2c33eea521ddba6))
* Show bar chart with 2% resolution by using partial width box characters. ([#97](https://github.com/RafaelGSS/bench-node/issues/97)) ([4c65557](https://github.com/RafaelGSS/bench-node/commit/4c65557b6472c8437eba98d4f91b52da8628d614))


### Bug Fixes

* cpus().length is broken under docker. ([#100](https://github.com/RafaelGSS/bench-node/issues/100)) ([c423cdd](https://github.com/RafaelGSS/bench-node/commit/c423cdd0220bc7317861fa387c99a230a34076ee))


### Styles

* Blue works better on light terminals and still looks good on dark. ([#95](https://github.com/RafaelGSS/bench-node/issues/95)) ([5ec0319](https://github.com/RafaelGSS/bench-node/commit/5ec0319787c08ff69ecd54c8003c715e96eafdc7))


### Miscellaneous Chores

* do not stop machine on runner_warmer ([6e0e71d](https://github.com/RafaelGSS/bench-node/commit/6e0e71dd30e4eb3bb5a1902a9eb9e6050bbccef7))
* run lint:ci on test ([#103](https://github.com/RafaelGSS/bench-node/issues/103)) ([a85e15c](https://github.com/RafaelGSS/bench-node/commit/a85e15cfb6b8bbf90a56c28aea49a3ff2e913567))

## [0.9.0](https://github.com/RafaelGSS/bench-node/compare/v0.8.0...v0.9.0) (2025-07-17)


### Features

* add reporterOptions support with printHeader opt ([#92](https://github.com/RafaelGSS/bench-node/issues/92)) ([20d34e9](https://github.com/RafaelGSS/bench-node/commit/20d34e90340d179ea20958f760f732f7e1573551))

## [0.8.0](https://github.com/RafaelGSS/bench-node/compare/v0.7.0...v0.8.0) (2025-07-16)


### Features

* add baseline and summary to pretty and text reporter ([#83](https://github.com/RafaelGSS/bench-node/issues/83)) ([3aa57cb](https://github.com/RafaelGSS/bench-node/commit/3aa57cb1e487274b141ab79a99e7ed0718cdbf63))
* add pretty-reporter and shorthand pretty: true ([#82](https://github.com/RafaelGSS/bench-node/issues/82)) ([45efe9c](https://github.com/RafaelGSS/bench-node/commit/45efe9c833cc39e7d8abfd203fbb05a4e84e9daa))
* export bench-node ts types ([#77](https://github.com/RafaelGSS/bench-node/issues/77)) ([d93f111](https://github.com/RafaelGSS/bench-node/commit/d93f111472515ff19b0fbe57bce588fdc51cfc9d))


### Bug Fixes

* fix imports in type test file ([#87](https://github.com/RafaelGSS/bench-node/issues/87)) ([defa158](https://github.com/RafaelGSS/bench-node/commit/defa158ffadceb6b8c660a802445eafe33933db5))
* use self-hosted runner for test CI ([#81](https://github.com/RafaelGSS/bench-node/issues/81)) ([a65af10](https://github.com/RafaelGSS/bench-node/commit/a65af107859946808ac8458d7b15bb9c887b12da))


### Miscellaneous Chores

* drop Node.js v23 and add v24 ([#78](https://github.com/RafaelGSS/bench-node/issues/78)) ([c2dae5f](https://github.com/RafaelGSS/bench-node/commit/c2dae5f038e3ec613aaac753091fbff5ed927b3f))

## [0.7.0](https://github.com/RafaelGSS/bench-node/compare/v0.6.0...v0.7.0) (2025-05-15)


### Features

* add opsSecPerRun result ([#74](https://github.com/RafaelGSS/bench-node/issues/74)) ([34ad9e9](https://github.com/RafaelGSS/bench-node/commit/34ad9e95b23d92d80442955569f04efdafc97655))

## [0.6.0](https://github.com/RafaelGSS/bench-node/compare/v0.5.4...v0.6.0) (2025-04-30)


### Features

* add time mode benchmark ([#71](https://github.com/RafaelGSS/bench-node/issues/71)) ([9d72044](https://github.com/RafaelGSS/bench-node/commit/9d72044a13a9fd93ae5f1b97fc26ff4a7db7d5f1))


### Documentation

* add JSDoc to functions ([#69](https://github.com/RafaelGSS/bench-node/issues/69)) ([e5c6695](https://github.com/RafaelGSS/bench-node/commit/e5c66957ec737f1a8f5ecc4f204e8032daf50aca))


### Miscellaneous Chores

* start issuing semver-minor ([3a261ae](https://github.com/RafaelGSS/bench-node/commit/3a261ae94ea029e8aed68153968570eb7c38a2c1))

## [0.5.4](https://github.com/RafaelGSS/bench-node/compare/v0.5.3...v0.5.4) (2025-03-13)


### Features

* expose histogram sample data to reporters via sampleData property ([#67](https://github.com/RafaelGSS/bench-node/issues/67)) ([833bec1](https://github.com/RafaelGSS/bench-node/commit/833bec16ae8167785e148ec939fc6211a0662822))

## [0.5.3](https://github.com/RafaelGSS/bench-node/compare/v0.5.2...v0.5.3) (2025-02-24)


### Features

* add min samples as param  ([#65](https://github.com/RafaelGSS/bench-node/issues/65)) ([9c6812e](https://github.com/RafaelGSS/bench-node/commit/9c6812e1124f44d95f8d086cba01b5302ec5187e))


### Miscellaneous Chores

* **readme:** clean + update ([#61](https://github.com/RafaelGSS/bench-node/issues/61)) ([b5e1e8b](https://github.com/RafaelGSS/bench-node/commit/b5e1e8bb507b9f8b017a91e8c814fb1046908042))

## [0.5.2](https://github.com/RafaelGSS/bench-node/compare/v0.5.1...v0.5.2) (2025-01-27)


### Features

* **chartReport:** include node-v ([#53](https://github.com/RafaelGSS/bench-node/issues/53)) ([695842e](https://github.com/RafaelGSS/bench-node/commit/695842eb58c8b6106598a4cef26fe44a552065c6))
* improve htmlReport UX ([#60](https://github.com/RafaelGSS/bench-node/issues/60)) ([79ce533](https://github.com/RafaelGSS/bench-node/commit/79ce5335e95d531b90c4e26fde983ec1c6de9502))


### Documentation

* **readme:** add badges and links ([f85f809](https://github.com/RafaelGSS/bench-node/commit/f85f809aa0f85987d3b01ef9737ed0a855e46741))


### Miscellaneous Chores

* **"branding":** add logo ([#58](https://github.com/RafaelGSS/bench-node/issues/58)) ([3eedd06](https://github.com/RafaelGSS/bench-node/commit/3eedd064791f5804810545db247a509aea618234))

## [0.5.1](https://github.com/RafaelGSS/bench-node/compare/v0.5.0...v0.5.1) (2025-01-19)


### Features

* create csv reporter ([#38](https://github.com/RafaelGSS/bench-node/issues/38)) ([11be8e5](https://github.com/RafaelGSS/bench-node/commit/11be8e52e8cbb5e17f378a8462dd1c4bf7b35351))
* **reporter:** polish chart output ([#40](https://github.com/RafaelGSS/bench-node/issues/40)) ([91082b6](https://github.com/RafaelGSS/bench-node/commit/91082b6441cfa6ba7b195d7386d493d689e29454))
* use biome linter ([#34](https://github.com/RafaelGSS/bench-node/issues/34)) ([11c1108](https://github.com/RafaelGSS/bench-node/commit/11c11088e12d2b77547389eb0a5055ad3ff11427))


### Bug Fixes

* ignore package.json due to release-please ([7c95b0a](https://github.com/RafaelGSS/bench-node/commit/7c95b0a4fd41aa81576503ac9444a775ed498eda))
* lint package.json ([549f6ca](https://github.com/RafaelGSS/bench-node/commit/549f6ca574f4a30915e86dff9cd073b3d90def1e))


### Miscellaneous Chores

* **main:** release 0.5.1 ([#44](https://github.com/RafaelGSS/bench-node/issues/44)) ([4e51324](https://github.com/RafaelGSS/bench-node/commit/4e51324ea129c3607229aaec3b8d22ef221d0e7d))
* **main:** release 0.5.2 ([#45](https://github.com/RafaelGSS/bench-node/issues/45)) ([baf2014](https://github.com/RafaelGSS/bench-node/commit/baf20147c1f09f3e50491845e536c590db0d8aa5))
* **main:** release 0.5.3 ([4757182](https://github.com/RafaelGSS/bench-node/commit/4757182c015cfbd769ebf3969c8269120271e5b3))


### Tests

* add managed basic tests ([#36](https://github.com/RafaelGSS/bench-node/issues/36)) ([c491a32](https://github.com/RafaelGSS/bench-node/commit/c491a328329bc79b2ef8124856b162c8df0e8cfb))


### Continuous Integration

* **release:** add support to release via release-please ([#42](https://github.com/RafaelGSS/bench-node/issues/42)) ([5263cc6](https://github.com/RafaelGSS/bench-node/commit/5263cc68a5c854a260b68e1f5b930496153ac7fb))

## [0.5.3](https://github.com/RafaelGSS/bench-node/compare/v0.5.2...v0.5.3) (2025-01-16)


### Features

* add benchmark repetition ([#27](https://github.com/RafaelGSS/bench-node/issues/27)) ([d65e8aa](https://github.com/RafaelGSS/bench-node/commit/d65e8aab609b882a32331a48bb60fb81ee2db24a))
* add enough context to plugin methods to figure out bench task name ([c16cf34](https://github.com/RafaelGSS/bench-node/commit/c16cf340699cf198ca10146f30c158697afff908))
* add html reporter ([a69fdfb](https://github.com/RafaelGSS/bench-node/commit/a69fdfb7415eeb4645e7116be125ccf876d00ebc))
* add JSONReporter ([7b51c16](https://github.com/RafaelGSS/bench-node/commit/7b51c16db1446b4a2c921c2548e14462197f4779))
* code and examples ([#1](https://github.com/RafaelGSS/bench-node/issues/1)) ([503b573](https://github.com/RafaelGSS/bench-node/commit/503b573a67cf9245383da949274b30412c366084))
* create csv reporter ([#38](https://github.com/RafaelGSS/bench-node/issues/38)) ([11be8e5](https://github.com/RafaelGSS/bench-node/commit/11be8e52e8cbb5e17f378a8462dd1c4bf7b35351))
* **enrichers:** added V8NeverOptimizeEnricher and V8OptimizeOnNextCallEnricher ([16e842e](https://github.com/RafaelGSS/bench-node/commit/16e842eb5dad9703fd009979f68b4f71c98436b2))
* initial commit ([ee2d46f](https://github.com/RafaelGSS/bench-node/commit/ee2d46fc446a481c7bca731639759e4b7529c405))
* **memory-enricher:** added support to report memory heap statistics ([441b3ad](https://github.com/RafaelGSS/bench-node/commit/441b3adfee5d92cdd32cb0d4bfd5e7b49d14c2af))
* **reporter:** polish chart output ([#40](https://github.com/RafaelGSS/bench-node/issues/40)) ([91082b6](https://github.com/RafaelGSS/bench-node/commit/91082b6441cfa6ba7b195d7386d493d689e29454))
* use biome linter ([#34](https://github.com/RafaelGSS/bench-node/issues/34)) ([11c1108](https://github.com/RafaelGSS/bench-node/commit/11c11088e12d2b77547389eb0a5055ad3ff11427))


### Bug Fixes

* handle htmlReport when bench suite is uppercase ([1685144](https://github.com/RafaelGSS/bench-node/commit/16851442e3fe3a97f8e6fc5c98993c77162dc4bc))
* **lifecycle:** missing imports ([08c6064](https://github.com/RafaelGSS/bench-node/commit/08c60646736ee1236cb371143594e337b1d5f502))
* typo ([d2a36ae](https://github.com/RafaelGSS/bench-node/commit/d2a36aec5dae24b9a4e95e4f055109a73d3b6bbc))


### Miscellaneous Chores

* add exec permission to run.sh ([5d0f4ef](https://github.com/RafaelGSS/bench-node/commit/5d0f4ef72849189472b6700ddf7e56376eea61a2))
* add node_modules to ignore ([478f24c](https://github.com/RafaelGSS/bench-node/commit/478f24c3fb8cd896e28e1c87e3212269fe9e31eb))
* **examples:** added example benchmarks ([b4b50b2](https://github.com/RafaelGSS/bench-node/commit/b4b50b23def45698c854bf3bbe434d3f3a92567d))
* **gitignore:** ignore .idea folder ([e9a13ae](https://github.com/RafaelGSS/bench-node/commit/e9a13ae640fd2ec2d7e714c0c6c9240f4ab1c628))
* **main:** release 0.5.1 ([#44](https://github.com/RafaelGSS/bench-node/issues/44)) ([4e51324](https://github.com/RafaelGSS/bench-node/commit/4e51324ea129c3607229aaec3b8d22ef221d0e7d))
* **main:** release 0.5.2 ([#45](https://github.com/RafaelGSS/bench-node/issues/45)) ([baf2014](https://github.com/RafaelGSS/bench-node/commit/baf20147c1f09f3e50491845e536c590db0d8aa5))
* rename to bench-node ([2f15705](https://github.com/RafaelGSS/bench-node/commit/2f157051e3b1988ac3a8094e0fc7e4daee267a48))
* rename to nodebenchmark ([9806a31](https://github.com/RafaelGSS/bench-node/commit/9806a31c819073d705bd59c29adc35e808e61d6c))
* **run:** added script to run all examples ([6733730](https://github.com/RafaelGSS/bench-node/commit/6733730de9fa83a0b6ee7f243b1c3c0576f6f4ad))
* update rafaelgss email ([a5ec544](https://github.com/RafaelGSS/bench-node/commit/a5ec5445a777c9db12181cae70cd47def0ac56c2))


### Code Refactoring

* **lib:** from esm to commonjs ([f25d0e4](https://github.com/RafaelGSS/bench-node/commit/f25d0e40c293a07fe865f09f9bd6693b3152e5b0))
* **lib:** make the code usable outside/inside node core ([c60c80e](https://github.com/RafaelGSS/bench-node/commit/c60c80e8fd6cad52f5275419252e313e03767893))
* **validators:** added missing validators on clock ([478fc7e](https://github.com/RafaelGSS/bench-node/commit/478fc7e3456c84797cd718b2c7eeb7e876bad2bc))


### Tests

* add a test documenting the plugin signature and lifecycle ([fd379d6](https://github.com/RafaelGSS/bench-node/commit/fd379d6ed51317504255eb78a24e33db21e0b3a7))
* add basic test suite ([8349ee0](https://github.com/RafaelGSS/bench-node/commit/8349ee0f96236646776fd12843c01d1d9c806b42))
* add managed basic tests ([#36](https://github.com/RafaelGSS/bench-node/issues/36)) ([c491a32](https://github.com/RafaelGSS/bench-node/commit/c491a328329bc79b2ef8124856b162c8df0e8cfb))
* add scenario for optimized managed benchmark ([74c4db1](https://github.com/RafaelGSS/bench-node/commit/74c4db1046857f9af57c0c54cc5bf801d0195339))
* add test case for copy function ([ddf6dc7](https://github.com/RafaelGSS/bench-node/commit/ddf6dc7b4e7a695f6bff5766788b4b0d5beec527))
* fix the plugin api test ([be8ec69](https://github.com/RafaelGSS/bench-node/commit/be8ec69ff9481ce55b8e49f5732e01a468f6b5de))
* include TODO test for managed and async ([15ff469](https://github.com/RafaelGSS/bench-node/commit/15ff46924bb969d724d1f92f5611a3f4385f0d47))
* increase percentage diff on CI ([fa57188](https://github.com/RafaelGSS/bench-node/commit/fa571883f30fd7033a12e05f291fe12bf4816152))


### Build System

* move run.sh to examples folder ([08ac769](https://github.com/RafaelGSS/bench-node/commit/08ac7699032a32f3a04a252cc48ee1514fd734bd))


### Continuous Integration

* **release:** add support to release via release-please ([#42](https://github.com/RafaelGSS/bench-node/issues/42)) ([5263cc6](https://github.com/RafaelGSS/bench-node/commit/5263cc68a5c854a260b68e1f5b930496153ac7fb))

## [0.5.2](https://github.com/RafaelGSS/bench-node/compare/v0.5.1...v0.5.2) (2025-01-16)


### Features

* add benchmark repetition ([#27](https://github.com/RafaelGSS/bench-node/issues/27)) ([d65e8aa](https://github.com/RafaelGSS/bench-node/commit/d65e8aab609b882a32331a48bb60fb81ee2db24a))
* add enough context to plugin methods to figure out bench task name ([c16cf34](https://github.com/RafaelGSS/bench-node/commit/c16cf340699cf198ca10146f30c158697afff908))
* add html reporter ([a69fdfb](https://github.com/RafaelGSS/bench-node/commit/a69fdfb7415eeb4645e7116be125ccf876d00ebc))
* add JSONReporter ([7b51c16](https://github.com/RafaelGSS/bench-node/commit/7b51c16db1446b4a2c921c2548e14462197f4779))
* code and examples ([#1](https://github.com/RafaelGSS/bench-node/issues/1)) ([503b573](https://github.com/RafaelGSS/bench-node/commit/503b573a67cf9245383da949274b30412c366084))
* create csv reporter ([#38](https://github.com/RafaelGSS/bench-node/issues/38)) ([11be8e5](https://github.com/RafaelGSS/bench-node/commit/11be8e52e8cbb5e17f378a8462dd1c4bf7b35351))
* **enrichers:** added V8NeverOptimizeEnricher and V8OptimizeOnNextCallEnricher ([16e842e](https://github.com/RafaelGSS/bench-node/commit/16e842eb5dad9703fd009979f68b4f71c98436b2))
* initial commit ([ee2d46f](https://github.com/RafaelGSS/bench-node/commit/ee2d46fc446a481c7bca731639759e4b7529c405))
* **memory-enricher:** added support to report memory heap statistics ([441b3ad](https://github.com/RafaelGSS/bench-node/commit/441b3adfee5d92cdd32cb0d4bfd5e7b49d14c2af))
* **reporter:** polish chart output ([#40](https://github.com/RafaelGSS/bench-node/issues/40)) ([91082b6](https://github.com/RafaelGSS/bench-node/commit/91082b6441cfa6ba7b195d7386d493d689e29454))
* use biome linter ([#34](https://github.com/RafaelGSS/bench-node/issues/34)) ([11c1108](https://github.com/RafaelGSS/bench-node/commit/11c11088e12d2b77547389eb0a5055ad3ff11427))


### Bug Fixes

* handle htmlReport when bench suite is uppercase ([1685144](https://github.com/RafaelGSS/bench-node/commit/16851442e3fe3a97f8e6fc5c98993c77162dc4bc))
* **lifecycle:** missing imports ([08c6064](https://github.com/RafaelGSS/bench-node/commit/08c60646736ee1236cb371143594e337b1d5f502))
* typo ([d2a36ae](https://github.com/RafaelGSS/bench-node/commit/d2a36aec5dae24b9a4e95e4f055109a73d3b6bbc))


### Miscellaneous Chores

* add exec permission to run.sh ([5d0f4ef](https://github.com/RafaelGSS/bench-node/commit/5d0f4ef72849189472b6700ddf7e56376eea61a2))
* add node_modules to ignore ([478f24c](https://github.com/RafaelGSS/bench-node/commit/478f24c3fb8cd896e28e1c87e3212269fe9e31eb))
* **examples:** added example benchmarks ([b4b50b2](https://github.com/RafaelGSS/bench-node/commit/b4b50b23def45698c854bf3bbe434d3f3a92567d))
* **gitignore:** ignore .idea folder ([e9a13ae](https://github.com/RafaelGSS/bench-node/commit/e9a13ae640fd2ec2d7e714c0c6c9240f4ab1c628))
* **main:** release 0.5.1 ([#44](https://github.com/RafaelGSS/bench-node/issues/44)) ([4e51324](https://github.com/RafaelGSS/bench-node/commit/4e51324ea129c3607229aaec3b8d22ef221d0e7d))
* rename to bench-node ([2f15705](https://github.com/RafaelGSS/bench-node/commit/2f157051e3b1988ac3a8094e0fc7e4daee267a48))
* rename to nodebenchmark ([9806a31](https://github.com/RafaelGSS/bench-node/commit/9806a31c819073d705bd59c29adc35e808e61d6c))
* **run:** added script to run all examples ([6733730](https://github.com/RafaelGSS/bench-node/commit/6733730de9fa83a0b6ee7f243b1c3c0576f6f4ad))
* update rafaelgss email ([a5ec544](https://github.com/RafaelGSS/bench-node/commit/a5ec5445a777c9db12181cae70cd47def0ac56c2))


### Code Refactoring

* **lib:** from esm to commonjs ([f25d0e4](https://github.com/RafaelGSS/bench-node/commit/f25d0e40c293a07fe865f09f9bd6693b3152e5b0))
* **lib:** make the code usable outside/inside node core ([c60c80e](https://github.com/RafaelGSS/bench-node/commit/c60c80e8fd6cad52f5275419252e313e03767893))
* **validators:** added missing validators on clock ([478fc7e](https://github.com/RafaelGSS/bench-node/commit/478fc7e3456c84797cd718b2c7eeb7e876bad2bc))


### Tests

* add a test documenting the plugin signature and lifecycle ([fd379d6](https://github.com/RafaelGSS/bench-node/commit/fd379d6ed51317504255eb78a24e33db21e0b3a7))
* add basic test suite ([8349ee0](https://github.com/RafaelGSS/bench-node/commit/8349ee0f96236646776fd12843c01d1d9c806b42))
* add managed basic tests ([#36](https://github.com/RafaelGSS/bench-node/issues/36)) ([c491a32](https://github.com/RafaelGSS/bench-node/commit/c491a328329bc79b2ef8124856b162c8df0e8cfb))
* add scenario for optimized managed benchmark ([74c4db1](https://github.com/RafaelGSS/bench-node/commit/74c4db1046857f9af57c0c54cc5bf801d0195339))
* add test case for copy function ([ddf6dc7](https://github.com/RafaelGSS/bench-node/commit/ddf6dc7b4e7a695f6bff5766788b4b0d5beec527))
* fix the plugin api test ([be8ec69](https://github.com/RafaelGSS/bench-node/commit/be8ec69ff9481ce55b8e49f5732e01a468f6b5de))
* include TODO test for managed and async ([15ff469](https://github.com/RafaelGSS/bench-node/commit/15ff46924bb969d724d1f92f5611a3f4385f0d47))
* increase percentage diff on CI ([fa57188](https://github.com/RafaelGSS/bench-node/commit/fa571883f30fd7033a12e05f291fe12bf4816152))


### Build System

* move run.sh to examples folder ([08ac769](https://github.com/RafaelGSS/bench-node/commit/08ac7699032a32f3a04a252cc48ee1514fd734bd))


### Continuous Integration

* **release:** add support to release via release-please ([#42](https://github.com/RafaelGSS/bench-node/issues/42)) ([5263cc6](https://github.com/RafaelGSS/bench-node/commit/5263cc68a5c854a260b68e1f5b930496153ac7fb))

## [0.5.1](https://github.com/RafaelGSS/bench-node/compare/v0.5.0...v0.5.1) (2025-01-14)


### Features

* create csv reporter ([#38](https://github.com/RafaelGSS/bench-node/issues/38)) ([11be8e5](https://github.com/RafaelGSS/bench-node/commit/11be8e52e8cbb5e17f378a8462dd1c4bf7b35351))
* **reporter:** polish chart output ([#40](https://github.com/RafaelGSS/bench-node/issues/40)) ([91082b6](https://github.com/RafaelGSS/bench-node/commit/91082b6441cfa6ba7b195d7386d493d689e29454))
* use biome linter ([#34](https://github.com/RafaelGSS/bench-node/issues/34)) ([11c1108](https://github.com/RafaelGSS/bench-node/commit/11c11088e12d2b77547389eb0a5055ad3ff11427))


### Tests

* add managed basic tests ([#36](https://github.com/RafaelGSS/bench-node/issues/36)) ([c491a32](https://github.com/RafaelGSS/bench-node/commit/c491a328329bc79b2ef8124856b162c8df0e8cfb))


### Continuous Integration

* **release:** add support to release via release-please ([#42](https://github.com/RafaelGSS/bench-node/issues/42)) ([5263cc6](https://github.com/RafaelGSS/bench-node/commit/5263cc68a5c854a260b68e1f5b930496153ac7fb))


================================================
FILE: Dockerfile
================================================
FROM node:24-trixie-slim

RUN apt update && apt install git -y


================================================
FILE: README.md
================================================
<h1 align="center">
  <img
    src="https://raw.githubusercontent.com/RafaelGSS/bench-node/refs/heads/main/assets/logo.svg"
    alt="Bench Node logo"
  />
  Bench Node
</h1>

<p align="center">
  <a href="#install">Install</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
  <a href="#usage">Usage</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
  <a href="#class-suite">Suite</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
  <a href="#plugins">Plugins</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
  <a href="#using-reporter">Using Reporter</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
  <a href="#setup-and-teardown">Setup and Teardown</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
  <a href="#benchmark-modes">Benchmark Modes</a>&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;
  <a href="#writing-javascript-mistakes">Writing JavaScript Mistakes</a>
</p>

[![npm package][npm-img]][npm-url]
[![Build Status][build-img]][build-url]
[![Downloads][downloads-img]][downloads-url]
[![Issues][issues-img]][issues-url]

The `bench-node` module allows you to measure operations per second of Node.js code blocks.

## Install

```bash
$ npm install bench-node
```

## Usage

```cjs
const { Suite } = require('bench-node');

const suite = new Suite();

suite.add('Using delete property', () => {
  const data = { x: 1, y: 2, z: 3 };
  delete data.y;

  data.x;
  data.y;
  data.z;
});

suite.run()
```

```bash
$ 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
```

This module uses V8 deoptimization to help ensure that the code block is not optimized away, producing accurate benchmarks -- but not realistic.
See the [Writing JavaScript Microbenchmark Mistakes](#writing-javascript-mistakes) section for more details.

The [`bench-node-cli`](https://github.com/RafaelGSS/bench-node-cli) tool allows you to execute a `bench-node` benchmark
from any location, eliminating the need to install the `bench-node` package locally.
Simply use the following command to run your benchmark:

```bash
npx bench-node-cli my-benchmark.js
```

See the [examples folder](./examples/) for more common usage examples.

## Table of Contents

- [Install](#install)
- [Usage](#usage)
- [Table of Contents](#table-of-contents)
- [Sponsors](#sponsors)
- [Class: `Suite`](#class-suite)
  - [`new Suite([options])`](#new-suiteoptions)
  - [`suite.add(name[, options], fn)`](#suiteaddname-options-fn)
  - [`suite.run()`](#suiterun)
- [Dead Code Elimination Detection](#dead-code-elimination-detection)
  - [How It Works](#how-it-works)
  - [Configuration](#configuration)
  - [When DCE Warnings Appear](#when-dce-warnings-appear)
- [Plugins](#plugins)
  - [Plugin Methods](#plugin-methods)
  - [Example Plugin](#example-plugin)
- [Using Reporter](#using-reporter)
  - [`textReport` (Default)](#textreport-default)
  - [`chartReport`](#chartreport)
  - [`htmlReport`](#htmlreport)
  - [`jsonReport`](#jsonreport)
  - [CSV Reporter](#csv-reporter)
  - [Pretty Reporter](#pretty-reporter)
  - [Custom Reporter](#custom-reporter)
- [Setup and Teardown](#setup-and-teardown)
  - [Managed Benchmarks](#managed-benchmarks)
  - [Worker Threads](#worker-threads)
- [Benchmark Modes](#benchmark-modes)
  - [Operations Mode](#operations-mode)
  - [Time Mode](#time-mode)
- [Baseline Comparisons](#baseline-comparisons)
- [Statistical Significance Testing](#statistical-significance-testing-t-test)
  - [Direct API Usage](#direct-api-usage)
  - [Fixing Inconclusive Tests](#fixing-inconclusive-tests)
- [Writing JavaScript Mistakes](#writing-javascript-mistakes)

## Sponsors

Test machines are generously sponsored by [NodeSource](https://nodesource.com/).  
<img src="https://github.com/user-attachments/assets/c30ddaf6-145b-465e-a81f-c9942cb93175" alt="NodeSource logo" width="200"/>

## Class: `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.
  * `reporter` {Function} Callback function for reporting results. Receives two arguments:
    * `results` {Object[]} Array of benchmark results:
      * `name` {string} Benchmark name.
      * `opsSec` {string} Operations per second.
      * `iterations` {Number} Number of iterations.
      * `histogram` {Histogram} Histogram instance.
  * `ttest` {boolean} Enable Welch's t-test for statistical significance testing. Automatically sets `repeatSuite=30`. **Default:** `false`.
  * `reporterOptions` {Object} Reporter-specific options.
    * `printHeader` {boolean} Whether to print system information header. **Default:** `true`.
    * `labelWidth` {number} Width for benchmark labels in output. **Default:** `45`.
    * `alpha` {number} Significance level for t-test (e.g., 0.05 for 95% confidence). **Default:** `0.05`.
  * `benchmarkMode` {string} Benchmark mode to use. Can be 'ops' or 'time'. **Default:** `'ops'`.
    * `'ops'` - Measures operations per second (traditional benchmarking).
    * `'time'` - Measures actual execution time for a single run.
  * `useWorkers` {boolean} Whether to run benchmarks in worker threads. **Default:** `false`.
  * `plugins` {Array} Array of plugin instances to use.
  * `repeatSuite` {number} Number of times to repeat each benchmark. Automatically set to `30` when `ttest: true`. **Default:** `1`.
  * `plugins` {Array} Array of plugin instances to use. **Default:** `[V8NeverOptimizePlugin]`.
  * `minSamples` {number} Minimum number of samples per round for all benchmarks in the suite. Can be overridden per benchmark. **Default:** `10` samples.
  * `detectDeadCodeElimination` {boolean} Enable dead code elimination detection. When enabled, default plugins are disabled to allow V8 optimizations. **Default:** `false`.
  * `dceThreshold` {number} Threshold multiplier for DCE detection. Benchmarks faster than baseline × threshold will trigger warnings. **Default:** `10`.

If no `reporter` is provided, results are printed to the console.

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

```js
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} The minimum duration of each sampling interval. **Default:** `0.05` seconds.
  * `maxTime` {number} Maximum duration for the benchmark to run. **Default:** `0.5` seconds.
  * `repeatSuite` {number} Number of times to repeat benchmark to run. **Default:** `1` times.
  * `minSamples` {number} Number minimum of samples the each round. **Default:** `10` samples.
  * `baseline` {boolean} Mark this benchmark as the baseline for comparison. Only one benchmark per suite can be baseline. **Default:** `false`.
* `fn` {Function|AsyncFunction} The benchmark function. Can be synchronous or asynchronous. 
* Returns: {Suite}

Adds a benchmark function to the suite.

```bash
$ node --allow-natives-syntax my-benchmark.js
Using delete property x 5,853,505 ops/sec (10 runs sampled) min..max=(169ns ... 171ns)
```

### `suite.run()`

* Returns: `{Promise<Array<Object>>}` An array of benchmark results, each containing:
  * `opsSec` {number} Operations per second (Only in 'ops' mode).
  * `opsSecPerRun` {Array} Array of operations per second (useful when repeatSuite > 1).
  * `totalTime` {number} Total execution time in seconds (Only in 'time' mode).
  * `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.

## Dead Code Elimination Detection

**bench-node** includes optional detection of dead code elimination (DCE) to help identify benchmarks that may be producing inaccurate results. When the JIT compiler optimizes away your benchmark code, it can run nearly as fast as an empty function, leading to misleading performance measurements.

**Important:** DCE detection is **opt-in**. When enabled, the `V8NeverOptimizePlugin` is automatically disabled to allow V8 optimizations to occur naturally. This helps catch benchmarks that would be optimized away in real-world scenarios.

### How It Works

When enabled, bench-node measures a baseline (empty function) performance before running your benchmarks. After each benchmark completes, it compares the timing against this baseline. If a benchmark runs suspiciously fast (less than 10× slower than the baseline by default), a warning is emitted.

### Example Warning Output

```
⚠️  Dead Code Elimination Warnings:
The following benchmarks may have been optimized away by the JIT compiler:

  • array creation
    Benchmark: 3.98ns/iter
    Baseline:  0.77ns/iter  
    Ratio:     5.18x of baseline
    Suggestion: Ensure the result is used or assign to a variable

ℹ️  These benchmarks are running nearly as fast as an empty function,
   which suggests the JIT may have eliminated the actual work.
```

### Configuration

```js
const { Suite, V8NeverOptimizePlugin } = require('bench-node');

// Enable DCE detection (disables V8NeverOptimizePlugin automatically)
const suite = new Suite({
  detectDeadCodeElimination: true
});

// Enable DCE detection with custom threshold (default is 10x)
const strictSuite = new Suite({
  detectDeadCodeElimination: true,
  dceThreshold: 20 // Only warn if < 20x slower than baseline
});

// Use both DCE detection AND prevent optimization
// (helpful for educational purposes to see warnings even when using %NeverOptimizeFunction)
const educationalSuite = new Suite({
  plugins: [new V8NeverOptimizePlugin()],
  detectDeadCodeElimination: true
});
```

### When DCE Warnings Appear

Common scenarios that trigger warnings:

```js
// ❌ Result not used - will be optimized away
suite.add('computation', () => {
  const result = Math.sqrt(144);
  // result is never used
});

// ✅ Result is used - less likely to be optimized
suite.add('computation', () => {
  const result = Math.sqrt(144);
  if (result !== 12) throw new Error('Unexpected');
});
```

**Note:** DCE detection only works in `'ops'` benchmark mode and when not using worker threads. It is automatically disabled for `'time'` mode and worker-based benchmarks.

See [examples/dce-detection/](./examples/dce-detection/) for more examples.

## Plugins

Plugins extend the functionality of the benchmark module. 

See [Plugins](./doc/Plugins.md) for details.

### Plugin Methods

- **`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, bench)`**: Called when the benchmark completes, allowing plugins to process results.
- **`toString()`**: Returns a string identifier for the plugin.
- **`getReport(benchmarkName)`**: Returns a string to be displayed in the benchmark result line.
- **`getResult(benchmarkName)`**: Returns the data that can be used by the reporter.
- **`reset()`**: Resets the plugin state, to avoid carrying over data between benchmarks.

### Example Plugin

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

## Using Reporter

This module exports two reporters that control how benchmark results are displayed:
a detailed `textReport` for statistical analysis, and a visual `chartReport` that
displays a bar graph in the terminal.

### `textReport` (Default)

The `textReport` is the default reporter, which provides simple statistical information
about each benchmark result. It includes the number of operations per second, the number
of runs sampled, min...max, and enabled plugins.

**Example Output**:

```
single with matcher                           x 710,248 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(1.40us...1.42us)
multiple replaces                             x 604,713 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(1.64us...1.70us)
```

Here’s how you can explicitly pass it as a reporter:

```cjs
const { Suite, textReport } = require('bench-node');

const suite = new Suite({
  reporter: textReport, // Optional, since this is the default
});
```

### `chartReport`

The `chartReport` reporter provides a graphical representation of benchmark
results in the form of a bar chart, making it easier to visualize the relative
performance of each benchmark. It scales the bars based on the highest operations
per second (ops/sec) value, and displays the results incrementally as they are collected.

Example output:

```
Node.js version: v23.6.1
Platform: darwin arm64
CPU Cores: 8 vCPUs | 16.0GB Mem

single with matcher                           | ██████████████████████████████ | 709,321 ops/sec | 10 samples
multiple replaces                             | ██████████████████████████---- | 606,401 ops/sec | 11 samples
```

Usage:

```cjs
const { Suite, chartReport } = require('bench-node');

const suite = new Suite({
  reporter: chartReport,
  // Optionally control header display
  reporterOptions: {
    printHeader: true // Set to false to hide system info header
  }
});
```

The `reporterOptions.printHeader` setting controls whether the system information (Node.js version, platform, and CPU cores) appears at the top of the output. This is useful when running multiple suites in sequence and you want to avoid duplicate headers.

### `htmlReport`

The `htmlReport` generates an interactive HTML visualization of benchmark results.
It transforms benchmark data into a visual format, such as speed circle animations,
making it easier to interpret and share performance insights.

Example output:

https://github.com/user-attachments/assets/b2b98175-6648-4af4-8319-63f3ebbc729e

Usage:

```cjs
const { Suite, htmlReport } = require('bench-node');

const suite = new Suite({
  reporter: htmlReport,
});
```

### `jsonReport`

The `jsonReport` plugin provides benchmark results in **JSON format**.  
It includes key performance metrics—such as `opsSec`, `runsSampled`, `min`
and `max` times, and any reporter data from your **plugins**—so you can easily
store, parse, or share the information.

Example output:

```json
[
  {
    "name": "single with matcher",
    "opsSec": 180000,
    "runsSampled": 50,
    "min": "13.20μs",
    "max": "82.57μs",
    "plugins": []
  },
  {
    "name": "Multiple replaces",
    "opsSec": 170000,
    "runsSampled": 50,
    "min": "15.31μs",
    "max": "77.49μs",
    "plugins": []
  }
]
```

**Usage:**

```cjs
const { Suite, jsonReport } = require('bench-node');

const suite = new Suite({
  reporter: jsonReport,
});
```

### CSV Reporter

The `csvReport` plugin generates benchmark results in CSV format.
It includes columns for key performance metrics like `ops/sec`, `samples`, `min` and `max` times,
as well as any reporter data provided by your plugins.

Example output:

```csv
name,ops/sec,samples,plugins,min,max
Using delete property,"7,732,517",10,v8-never-optimize=true,127.91ns,129.95ns
Using delete property (proto: null),"24,636,631",10,v8-never-optimize=true,39.57ns,40.91ns
Using delete property (cached proto: null),"7,497,893",11,v8-never-optimize=true,132.25ns,134.89ns
Using undefined assignment,"132,093,600",11,v8-never-optimize=true,7.53ns,7.64ns
Using undefined assignment (proto: null),"28,231,374",9,v8-never-optimize=true,35.27ns,35.42ns
Using undefined property (cached proto: null),"60,843,193",10,v8-never-optimize=true,16.24ns,16.65ns
[Managed] Using undefined property (cached proto: null),"35,394,060",10,v8-never-optimize=true,27.90ns,28.54ns
```

**Usage:**

```cjs
const { Suite, csvReport } = require('bench-node');

const suite = new Suite({
  reporter: csvReport,
});
```

### Pretty Reporter

The `prettyReport` provides a beautiful, hierarchical view of your benchmark results.

**Usage:**

```javascript
const { Suite } = require('bench-node');

// You can either pass the reporter function directly...
const suiteWithReporter = new Suite({
  reporter: prettyReport,
});

// ...or use the `pretty` option for convenience.
const suiteWithPrettyOption = new Suite({
  pretty: true,
});

suite
  .add('my-group/my-benchmark', () => {
    //...
  })
  .add('my-group/my-benchmark-2', () => {
    //...
  })
  .add('second-group/baseline', () => {
    //...
  })
  .run();
```

**Sample Output:**

```
System Information:
  Node.js: v22.15.0
  OS: darwin 24.5.0
  CPU: Apple M2

Benchmark results (3 total):
Plugins enabled: V8NeverOptimizePlugin
├─ my-group
│ ├─ my-benchmark                                      1,461,380 ops/sec (10 runs sampled) min..max=(682.30ns...685.79ns)
│ └─ my-benchmark-2                                    2,270,973 ops/sec (10 runs sampled) min..max=(437.22ns...444.12ns)
└─ second-group
  └─ baseline                                          637,787 ops/sec (11 runs sampled) min..max=(1.54us...1.59us)
```

### Custom Reporter

Customize data reporting by providing a `reporter` function when creating the `Suite`:

```js
const { Suite } = require('bench-node');

function reporter(results) {
  for (const result of results) {
    console.log(`Benchmark: ${result.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();
```

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

## Setup and Teardown

Control the benchmark function's setup and teardown using the timer argument:

```js
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:

```js
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](./examples/deleting-properties/node.js).

Ensure you call `.start()` and `.end()` methods when using the timer argument, or an `ERR_BENCHMARK_MISSING_OPERATION` error will be thrown.

### Managed Benchmarks

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:

```cjs
suite.add('Using includes', () => {
  const text = 'text/html,...';
  const r = text.includes('application/json');
});
```

Here, `DoNotOptimize` is called inside the generated loop for regular benchmarks
(assuming `V8NeverOptimizePlugin` is being used), and the benchmark function is
also marked with `%NeverOptimizeFunction`.
Together, these prevent V8 from optimizing the benchmark function and from
treating the returned value as irrelevant.

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:

```cjs
suite.add('[Managed] Using includes', (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 applied to the benchmark function's return value,
outside the user-managed loop. It does not consume the local `r` value from each
iteration. That's why `assert.ok(r)` has been used: it makes the per-iteration
result observable inside the timed block.

> [!NOTE]
> V8 assumptions can change any time soon. Therefore, it's crucial to investigate
> results between versions of V8/Node.js.

### Worker Threads

> Stability: 1.0 (Experimental)

`bench-node` provides experimental support for **Worker Threads**. When you set `useWorkers: true`,
the library runs each benchmark in a separate worker thread, ensuring that one benchmark
does not affect another. Usage is straightforward:

```cjs
const suite = new Suite({
  useWorkers: true,
});
```

## Benchmark Modes

`bench-node` supports multiple benchmarking modes to measure code performance in different ways.

### Operations Mode

Operations mode (default) measures how many operations can be performed in a given timeframe. 
This is the traditional benchmarking approach that reports results in operations per second (ops/sec).

This mode is best for:
- Comparing relative performance between different implementations
- Measuring throughput of small, fast operations
- Traditional microbenchmarking

Example output:
```
String concatenation x 12,345,678 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(81ns...85ns)
```

### Time Mode

Time mode measures the actual time taken to execute a function exactly once. 
This mode is useful when you want to measure the real execution time for operations that have a known, fixed duration.

This mode is best for:
- Costly operations where multiple instructions are executed in a single run 
- Benchmarking operations with predictable timing
- Verifying performance guarantees for time-sensitive functions

To use time mode, set the `benchmarkMode` option to `'time'` when creating a Suite:

```js
const { Suite } = require('bench-node');

const timeSuite = new Suite({
    benchmarkMode: 'time' // Enable time mode
});

// Create a function that takes a predictable amount of time
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

timeSuite.add('Async Delay 100ms', async () => {
    await delay(100);
});

timeSuite.add('Sync Busy Wait 50ms', () => {
    const start = Date.now();
    while (Date.now() - start < 50);
});

// Optional: Run the benchmark multiple times with repeatSuite
timeSuite.add('Quick Operation with 5 repeats', { repeatSuite: 5 }, () => {
    // This will run exactly once per repeat (5 times total)
    // and report the average time
    let x = 1 + 1;
});

(async () => {
    await timeSuite.run();
})();
```

In time mode, results include `totalTime` (in seconds) instead of `opsSec`.

Example output:
```
Async Delay 100ms x 0.1003s (1 sample) v8-never-optimize=true
Sync Busy Wait 50ms x 0.0502s (1 sample) v8-never-optimize=true
Quick Operation with 5 repeats x 0.0000s (5 samples) v8-never-optimize=true
```

See [examples/time-mode.js](./examples/time-mode.js) for a complete example.

## Baseline Comparisons

You can mark one benchmark as a baseline to compare all other benchmarks against it:

```js
const { Suite } = require('bench-node');

const suite = new Suite();

suite
  .add('baseline', { baseline: true }, () => {
    // baseline implementation
    const arr = [1, 2, 3];
    arr.includes(2);
  })
  .add('alternative', () => {
    // alternative implementation
    const arr = [1, 2, 3];
    arr.indexOf(2) !== -1;
  });

suite.run();
```

Example output with baseline:
```
baseline     x 52,832,865 ops/sec (10 runs sampled) min..max=(18.50ns...19.22ns)
alternative  x 53,550,219 ops/sec (11 runs sampled) min..max=(18.26ns...18.89ns)

Summary (vs. baseline):
  baseline     (baseline)
  alternative  (1.01x faster)
```

## Statistical Significance Testing (T-Test)

> Stability: 1.0 (Experimental)

When comparing benchmarks, especially on machines with high variance (cloud VMs, shared environments),
raw ops/sec differences may not be meaningful. `bench-node` provides **Welch's t-test** to determine
if performance differences are statistically significant.

Welch's t-test is preferred over Student's t-test because it doesn't assume equal variances between
the two samples, which is common in benchmark scenarios.

### Enabling T-Test Mode

Enable t-test mode with `ttest: true`. This automatically sets `repeatSuite=30` to collect enough
independent samples for reliable statistical analysis (per the Central Limit Theorem):

```js
const { Suite } = require('bench-node');

const suite = new Suite({
  ttest: true,  // Enables t-test and auto-sets repeatSuite=30
});

suite
  .add('baseline', { baseline: true }, () => {
    let sum = 0;
    for (let i = 0; i < 100; i++) sum += i;
  })
  .add('optimized', () => {
    let sum = (99 * 100) / 2; // Gauss formula
  });

suite.run();
```

Example output:
```
T-Test Mode: Enabled (repeatSuite=30)

baseline   x 1,234,567 ops/sec (300 runs sampled) min..max=(810.05ns...812.45ns)
optimized  x 9,876,543 ops/sec (305 runs sampled) min..max=(101.23ns...102.87ns)

Summary (vs. baseline):
  baseline   (baseline)
  optimized  (8.00x faster) ***

  Significance: * p<0.05, ** p<0.01, *** p<0.001
```

The asterisks indicate significance level:
- `***` = p < 0.001 (0.1% risk of false positive)
- `**` = p < 0.01 (1% risk of false positive)
- `*` = p < 0.05 (5% risk of false positive)
- (no stars) = not statistically significant

This helps identify when a benchmark shows a difference due to random variance vs. a real performance improvement.

**How it works**: With `ttest: true`, each benchmark runs 30 times independently (via `repeatSuite=30`). The t-test compares the 30 ops/sec values from the baseline against the 30 ops/sec values from each test benchmark. This accounts for run-to-run variance within that benchmark session.

**Note**: Running the entire benchmark suite multiple times may still show variance in absolute numbers due to system-level factors (CPU frequency scaling, thermal throttling, background processes). The t-test helps determine if differences are statistically significant within each benchmark session, but results can vary between separate benchmark runs due to changing system conditions.

See also: [Fixing Inconclusive Tests](doc/Inconclusive.md).

### Direct API Usage

You can also use the t-test utilities directly for custom analysis:

```js
const { welchTTest, compareBenchmarks } = require('bench-node');

// Raw sample data from two benchmarks (e.g., timing samples in nanoseconds)
const baseline = [100, 102, 99, 101, 100, 98, 103, 99, 100, 101];
const optimized = [50, 51, 49, 52, 50, 48, 51, 49, 50, 51];

// High-level comparison
const result = compareBenchmarks(optimized, baseline, 0.05);
console.log(result);
// {
//   significant: true,
//   pValue: 0.00001,
//   confidence: '99.99%',
//   stars: '***',
//   difference: 'faster',
//   tStatistic: 45.2,
//   degreesOfFreedom: 17.8
// }

// Low-level Welch's t-test
const ttest = welchTTest(optimized, baseline);
console.log(ttest);
// {
//   tStatistic: 45.2,
//   degreesOfFreedom: 17.8,
//   pValue: 0.00001,
//   significant: true,
//   mean1: 50.1,
//   mean2: 100.3,
//   variance1: 1.43,
//   variance2: 2.23
// }
```

#### Interpreting Results

- **`significant: true`** - The performance difference is statistically significant at the given alpha level
- **`pValue`** - Probability that the observed difference occurred by chance (lower = more confident)
- **`confidence`** - Confidence level (e.g., "99.95%" means 99.95% confident the difference is real)
- **`stars`** - Visual indicator of significance: `'***'` (p<0.001), `'**'` (p<0.01), `'*'` (p<0.05), or `''` (not significant)
- **`difference`** - Whether the first sample is `'faster'`, `'slower'`, or `'same'` as the second

A common threshold is `alpha = 0.05` (95% confidence). If `pValue < alpha`, the difference is significant.

## Writing JavaScript Mistakes

When working on JavaScript micro-benchmarks, it’s easy to forget that modern engines use
multiple tiers of Just-In-Time (JIT) compilation and sometimes even entirely different
optimizations. The results you get from a simple timing loop often aren’t representative
of how your code will behave under real-world conditions, especially once the browser or
runtime has adjusted for frequent function calls. Caching, tail call optimizations,
and hidden class transformations can all distort your measurements, leading to overblown
claims about performance improvements that might never materialize in production.

That’s why **bench-node** was created—to provide a stable and consistent way to compare
small snippets of code. By default, it tells V8 to never optimize the benchmark
function with `%NeverOptimizeFunction(bench.fn)` and consumes the returned value
with a non-optimized `DoNotOptimize` helper so the JIT compiler doesn’t remove
dead code. However, even this approach can’t fully replicate real-world scenarios
in which V8 optimizations and unpredictable workloads impact performance. Think of
bench-node as a helpful tool for quick comparisons rather than a guarantee of what you’ll
see in production.


[build-img]:https://github.com/RafaelGSS/bench-node/actions/workflows/release.yml/badge.svg

[build-url]:https://github.com/RafaelGSS/bench-node/actions/workflows/release.yml

[downloads-img]:https://img.shields.io/npm/dt/bench-node

[downloads-url]:https://www.npmtrends.com/bench-node

[npm-img]:https://img.shields.io/npm/v/bench-node

[npm-url]:https://www.npmjs.com/package/bench-node

[issues-img]:https://img.shields.io/github/issues/RafaelGSS/bench-node

[issues-url]:https://github.com/RafaelGSS/bench-node/issues


================================================
FILE: assets/README.md
================================================
# "Branding"

## Logo

| Logo | Description |
| --- | --- |
| ![Logo](./logo.svg) | simple logo for readme |
| ![Logo](./logo-text-light.svg) | logo with text for light backgrounds |
| ![Logo](./logo-text-dark.svg) | logo with text for dark backgrounds |

## Other

- **Font**: [Geist](https://fonts.google.com/specimen/Geist)
- **Light Green**: `#84BA64`
- **Dark Green**: `#2C682C`

> The design of the assets was created by [@AugustinMauroy](https://github.com/AugustinMauroy).


================================================
FILE: biome.json
================================================
{
	"$schema": "https://biomejs.dev/schemas/1.8.3/schema.json",
	"organizeImports": {
		"enabled": true
	},
	"linter": {
		"enabled": true,
		"rules": {
			"recommended": true,
			"suspicious": {
				"noExplicitAny": "off"
			},
			"style": {
				"noParameterAssign": "off",
				"noUselessElse": "off"
			}
		}
	},
	"formatter": {
		"enabled": true
	},
	"files": {
		"ignore": [
			"examples/*",
			"coverage/*",
			"test/plugin-api-doc.js",
			"package.json"
		]
	}
}


================================================
FILE: doc/Inconclusive.md
================================================
# Fixing Inconclusive Tests

t-tests are looking at the distribution of both sets of results and trying to determine if they overlap in a way that
makes the average value significant or just noise in the results. A run with a bimodal distribution for instance, caused
by problems with the machine the tests are running on or the NodeJS runtime doing things in the background. Here are a
few causes.

## Random Input Data

Variability in the inputs between runs can lead to big changes in the runtime of an algorithm. Particularly with code
that sorts, filters, or conditionally operates on input data, feeding them certain combinations of data will result in
wildly different run times from one loop to the next or occasionally from one sample to the next. The Central Limit
Theorem (that over a long enough time a situation will revert to the mean), does not invalidate the existence of the
Gambler's Paradox (that it will revert to the mean before I become bankrupt).

It is better to do your fuzzing in fuzz tests and pick representative data for your benchmarks. Partially informed by
the results of your fuzz tests, and other bug reports.

## Underprovisioned VM, Oversubscribed hardware

For a clean micro benchmark, we generally want to be the only one using the machine at the time. There are a number of
known issues running benchmarks on machines that are thermally throttling, or on cheap VMs that use best-effort to
allocate CPU time to the running processes. In particular, docker images with `cpu-shares` are especially poor targets
for running benchmarks because the quota might expire for one timeslice in the middle of one test or between benchmarks
in a single Suite. This creates an unfair advantage for the first test, and/or lots of noise in the results. We are
currently investigating ways to detect this sort of noise, and analyzing if the t-tests are sufficient to do so.

## Epicycles in GC or JIT compilation

If the warmup time is insufficient to get V8 to optimize the code, it may kick in during the middle of a sample, which
will introduce a bimodal distribution of answers (before, and after). There is currently not a way to adjust the warmup
time of `bench-node`, but should be added as a feature.

One of the nastiest performance issues to detect in garbage collected code is allocation epicycles. This happens when
early parts of a calculation create lots of temporary data but not sufficient to cross the incremental or full GC
threshold, so that the next function in a call sequence routinely gets hit with exceeding the threshold. This is
especially common in code that generates a JSON or HTML response to a series of calculations - it is the single biggest
allocation in the sequence, but it gets blamed in the performance report for the lion's share of the CPU time.

If you change the `minTime` up or down, that will alter the number of iterations per sample which may smooth out the
results. You can also try increasing `minSamples` to get more samples. But also take this as a suggestion that your code
may have a performance bug that is worth prioritizing.

Forcing GC in the teardown or setup methods between subsequent tests in a single Suite may help with some situations
when reordering the tests results in differences in runtime, but for the more general case, you may need to review the
code under test to make it 'play well' both with benchmarking and in production systems.

In production code, particularly where p9# values are used as a fitness test, it is sometimes better to chose the
algorithm with more consistent runtime over the one with supposedly better average runtime. This can also be true where
DDOS scenarios are possible - the attacker will always chose the worst, most assymetric request to send to your machine,
and mean response time will not matter one whit. If `bench-node` is complaining, the problem may not be `bench-node`.


================================================
FILE: doc/Plugins.md
================================================
# 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.

To observe how a plugin is used, see the `plugin-api-doc.js` file in tests and explore its results.

## 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({ bench }) {
  let code = '';

  code += `
function DoNotOptimize(x) {}
// Prevent the benchmark function and result consumer from optimizing or being inlined.
%NeverOptimizeFunction(${bench}.fn);
%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 result. The benchmark
function itself is marked with `%NeverOptimizeFunction(${bench}.fn)`, while the
`DoNotOptimize` wrapper consumes the returned value so the benchmark expression
does not become observationally irrelevant.

These two protections address different parts of the generated code:
`%NeverOptimizeFunction(${bench}.fn)` targets the function under test, and
`DoNotOptimize(bench.fn())` targets the value returned by each call.

### `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
the benchmark function. It also wraps the benchmark result in a non-optimized
`DoNotOptimize` helper so V8 cannot treat an unused return value as irrelevant.

### Class: `V8GetOptimizationStatus`

The `V8GetOptimizationStatus` plugin collects the V8 engine's optimization
status for a given function after it has been benchmarked.


================================================
FILE: examples/.gitignore
================================================


================================================
FILE: examples/benchmark-comparison/README.md
================================================
# Benchmark Comparison Framework

This directory contains a framework for comparing `bench-node` against other popular benchmark libraries:

- [Benchmark.js](https://benchmarkjs.com/)
- [Mitata](https://github.com/evanwashere/mitata)
- [Tinybench](https://github.com/tinylibs/tinybench)

## Test Cases

The comparison focuses on four key test scenarios:

1. **JIT Optimizable** - Simple operations that the JavaScript JIT compiler might optimize away
2. **Regex Test** - Regular expression pattern matching operations
3. **Fibonacci** - CPU-bound recursive calculation

## Running the Comparisons

To run any of the comparison scripts, use:

```bash
node --allow-natives-syntax examples/benchmark-comparison/comparison.js
```

> **Note:** All bench-node scripts must be run with the `--allow-natives-syntax` flag.


================================================
FILE: examples/benchmark-comparison/comparison.js
================================================

const { Suite } = require('../../lib');
const Benchmark = require('benchmark');
const { bench, run: mitataRun } = require('mitata');
const { Bench } = require('tinybench');

const testSuites = {
  'simple-operations': {
    name: 'Simple Operations',
    tests: {
      'jit-optimizable': {
        name: 'JIT Optimizable',
        fn: function() {
          const x = 1;
          const y = 2;
          return x + y;
        }
      }
    }
  },
  
  'string-processing': {
    name: 'String Processing',
    tests: {
      'regex-test': {
        name: 'Regex Test',
        fn: function() {
          const pattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
          const emails = [
            'test@example.com',
            'invalid-email',
            'another.test@example.co.uk',
            'john.doe123@sub.domain.com'
          ];
          return emails.map(email => pattern.test(email));
        }
      }
    }
  },
  
  'cpu-intensive': {
    name: 'CPU Intensive',
    tests: {
      'fibonacci-10': {
        name: 'Fibonacci(10)',
        fn: function() {
          const n = 10;
          let a = 0, b = 1;
          for (let i = 2; i <= n; i++) {
            [a, b] = [b, a + b];
          }
          return b;
        }
      },
      
      'fibonacci-30': {
        name: 'Fibonacci(30)',
        fn: function() {
          const n = 30;
          let a = 0, b = 1;
          for (let i = 2; i <= n; i++) {
            [a, b] = [b, a + b];
          }
          return b;
        }
      },
      
      'fibonacci-40': {
        name: 'Fibonacci(40)',
        fn: function() {
          const n = 40;
          let a = 0, b = 1;
          for (let i = 2; i <= n; i++) {
            [a, b] = [b, a + b];
          }
          return b;
        }
      },
      
      'fibonacci-recursive-10': {
        name: 'Fibonacci Recursive(10)',
        fn: function() {
          function fibRecursive(n) {
            if (n <= 1) return n;
            return fibRecursive(n - 1) + fibRecursive(n - 2);
          }
          return fibRecursive(10);
        }
      }
    }
  }
};

function formatNumber(num) {
  return new Intl.NumberFormat().format(Math.round(num));
}

async function runBenchNode() {
  console.log('\n🔍 Running bench-node tests... (detailed output hidden)');
  
  // Save original console.log
  const originalConsoleLog = console.log;
  // Replace with no-op function
  console.log = () => {};
  
  const results = [];
  
  try {
    for (const [suiteKey, suite] of Object.entries(testSuites)) {
      const benchSuite = new Suite({ name: suite.name });
      
      Object.entries(suite.tests).forEach(([testKey, test]) => {
        benchSuite.add(test.name, test.fn);
      });
      
      try {
        const suiteResults = await benchSuite.run();
        
        // Collect results
        suiteResults.forEach(result => {
          // Extract ops/sec from the bench-node result object
          // The opsSec field contains the operations per second value
          let opsPerSec = 0;
          
          if (typeof result.opsSec === 'number') {
            // Direct extraction from the opsSec field
            opsPerSec = result.opsSec;
          } else if (typeof result.hz === 'number') {
            // Fallback to hz if available
            opsPerSec = result.hz;
          } else if (result.stats && typeof result.stats.mean === 'number') {
            // Mean is in nanoseconds, convert to ops/sec
            opsPerSec = 1_000_000_000 / result.stats.mean;
          } else if (typeof result.avg === 'number') {
            // Avg is in seconds, convert to ops/sec
            opsPerSec = 1 / result.avg;
          }
          
          results.push({
            tool: 'bench-node',
            suite: suite.name,
            test: result.name,
            opsPerSec: opsPerSec,
            margin: result.rme || 0
          });
        });
      } catch (error) {
        // Temporarily restore console.log for error reporting
        const tempConsole = console.log;
        console.log = originalConsoleLog;
        console.log(`Error running benchmark suite ${suite.name}: ${error.message}`);
        console.log = tempConsole;
        
        // Add placeholder results for this suite so we don't lose the comparison
        Object.entries(suite.tests).forEach(([testKey, test]) => {
          results.push({
            tool: 'bench-node',
            suite: suite.name,
            test: test.name,
            opsPerSec: 0,
            margin: 0
          });
        });
      }
    }
  } catch (error) {
    // Temporarily restore console.log for error reporting
    const tempConsole = console.log;
    console.log = originalConsoleLog;
    console.log(`Error in bench-node benchmarks: ${error.message}`);
    console.log = tempConsole;
  }
  
  // Restore original console.log
  console.log = originalConsoleLog;
  return results;
}


async function runBenchmarkJS() {
  console.log('\n🔍 Running benchmark.js tests... (detailed output hidden)');
  
  // Save original console.log
  const originalConsoleLog = console.log;
  // Replace with no-op function
  console.log = () => {};
  
  const results = [];
  
  try {
    for (const [suiteKey, suite] of Object.entries(testSuites)) {
      await new Promise((resolve) => {
        const benchSuite = new Benchmark.Suite(suite.name);
        
        Object.entries(suite.tests).forEach(([testKey, test]) => {
          benchSuite.add(test.name, test.fn);
        });
        
        benchSuite
          .on('cycle', (event) => {
            // Collect result for each test
            results.push({
              tool: 'benchmark.js',
              suite: suite.name,
              test: event.target.name,
              opsPerSec: event.target.hz,
              margin: event.target.stats.rme
            });
          })
          .on('complete', function() {
            resolve();
          })
          .run();
      });
    }
  } catch (error) {
    // Temporarily restore console.log for error reporting
    const tempConsole = console.log;
    console.log = originalConsoleLog;
    console.log(`Error in benchmark.js benchmarks: ${error.message}`);
    console.log = tempConsole;
  }
  
  // Restore original console.log
  console.log = originalConsoleLog;
  return results;
}

async function runMitata() {
  console.log('\n🔍 Running mitata tests... (detailed output hidden)');
  
  // Save original console.log
  const originalConsoleLog = console.log;
  // Replace with no-op function
  console.log = () => {};

  // Create a results collection
  const results = [];
  
  try {
    // Store test to name mappings for result collection
    const testMap = new Map();
    
    for (const [suiteKey, suite] of Object.entries(testSuites)) {
      // Estimate performance based on test function execution time
      Object.entries(suite.tests).forEach(([testKey, test]) => {
        const fullName = `${suite.name}: ${test.name}`;
        bench(fullName, test.fn);
        
        // Create a test mapping
        testMap.set(fullName, { suite: suite.name, test: test.name });
        
        // Do a simple performance estimate (not as accurate as real benchmark)
        // This is a fallback since we can't easily extract mitata results
        const start = process.hrtime.bigint();
        const iterations = 1000;
        for (let i = 0; i < iterations; i++) {
          test.fn();
        }
        const end = process.hrtime.bigint();
        const avgNs = Number(end - start) / iterations;
        const estOpsPerSec = 1_000_000_000 / avgNs;
        
        // Add estimated result
        results.push({
          tool: 'mitata',
          suite: suite.name,
          test: test.name,
          opsPerSec: estOpsPerSec,
          margin: 5 // Rough estimate of margin
        });
      });
    }
    
    // Run mitata benchmarks silently
    await mitataRun();
  } catch (error) {
    // Temporarily restore console.log for error reporting
    const tempConsole = console.log;
    console.log = originalConsoleLog;
    console.log(`Error in mitata benchmarks: ${error.message}`);
    console.log = tempConsole;
  }
  
  // Restore original console.log
  console.log = originalConsoleLog;
  return results;
}


async function runTinyBench() {
  console.log('\n🔍 Running tinybench tests... (detailed output hidden)');
  
  // Save original console.log
  const originalConsoleLog = console.log;
  // Replace with no-op function
  console.log = () => {};
  
  const allResults = [];
  
  try {
    // Create benchmarks for each suite
    for (const [suiteKey, suite] of Object.entries(testSuites)) {
      const benchmark = new Bench();
      
      // Add tests to suite
      Object.entries(suite.tests).forEach(([testKey, test]) => {
        benchmark.add(test.name, test.fn);
      });
      
      // Run benchmarks
      await benchmark.run();
      
      // Format and collect results
      const suiteResults = benchmark.tasks.map(({ name, result }) => ({
        name,
        ops: result?.hz || 0,
        margin: result?.rme ? `±${result?.rme.toFixed(2)}%` : 'N/A'
      }));
      suiteResults.forEach(result => {
        // Extract numeric margin value from the margin string (e.g., '±1.20%' -> 1.20)
        let marginValue = 0;
        if (result.margin && result.margin !== 'N/A') {
          const match = result.margin.match(/[0-9.]+/);
          if (match) {
            marginValue = parseFloat(match[0]);
          }
        }
        
        allResults.push({
          tool: 'tinybench',
          suite: suite.name,
          test: result.name,
          opsPerSec: result.ops,
          margin: marginValue
        });
      });
    }
  } catch (error) {
    // Temporarily restore console.log for error reporting
    const tempConsole = console.log;
    console.log = originalConsoleLog;
    console.log(`Error in tinybench benchmarks: ${error.message}`);
    console.log = tempConsole;
  }
  
  // Restore original console.log
  console.log = originalConsoleLog;
  return allResults;
}


function compareResults(results) {
  console.log('\n📈 BENCHMARK COMPARISON SUMMARY');
  console.log('============================');
  
  // Group results by suite and test
  const resultsBySuiteAndTest = {};
  
  results.forEach(result => {
    // Ensure we have valid ops/sec values for comparison
    if (isNaN(result.opsPerSec) || result.opsPerSec === undefined || result.opsPerSec === null) {
      result.opsPerSec = 0;
    }
    
    const key = `${result.suite} - ${result.test}`;
    if (!resultsBySuiteAndTest[key]) {
      resultsBySuiteAndTest[key] = [];
    }
    resultsBySuiteAndTest[key].push(result);
  });
  
  // For each test case, compare across tools
  Object.entries(resultsBySuiteAndTest).forEach(([testCase, testResults]) => {
    console.log(`\n📏 Test Case: ${testCase}`);
    
    const comparisonTable = testResults.map(result => ({
      'Tool': result.tool,
      'ops/sec': formatNumber(result.opsPerSec || 0),
      'margin': result.margin ? `±${result.margin.toFixed(2)}%` : 'N/A',
      'relative': '1x'
    }));
    
    // Find the fastest tool for this test (with valid non-zero result)
    const validResults = testResults.filter(r => r.opsPerSec > 0);
    const fastest = validResults.length > 0 ?
      validResults.reduce((max, result) => result.opsPerSec > max.opsPerSec ? result : max, validResults[0]) :
      { opsPerSec: 1 };
    
    // Calculate relative performance
    comparisonTable.forEach(row => {
      const result = testResults.find(r => r.tool === row['Tool']);
      if (result && result.opsPerSec > 0 && fastest.opsPerSec > 0) {
        const relative = result.opsPerSec / fastest.opsPerSec;
        row['relative'] = `${relative.toFixed(2)}x`;
      } else {
        row['relative'] = 'N/A';
      }
    });
    
    // Sort by performance (descending)
    comparisonTable.sort((a, b) => {
      const aResult = testResults.find(r => r.tool === a['Tool']);
      const bResult = testResults.find(r => r.tool === b['Tool']);
      const aSpeed = aResult && aResult.opsPerSec > 0 ? aResult.opsPerSec : 0;
      const bSpeed = bResult && bResult.opsPerSec > 0 ? bResult.opsPerSec : 0;
      return bSpeed - aSpeed;
    });
    
    console.table(comparisonTable);
  });
}

async function main() {
  console.log('🚀 BENCHMARK COMPARISON');
  console.log('======================');
  console.log('Comparing: bench-node, benchmark.js, mitata, tinybench\n');

  try {
    const results = [];
    
    // Run all benchmarks and collect results
    const benchNodeResults = await runBenchNode();
    const benchmarkJsResults = await runBenchmarkJS();
    const mitataResults = await runMitata();
    const tinyBenchResults = await runTinyBench();
    
    // Combine all results
    results.push(...benchNodeResults);
    results.push(...benchmarkJsResults);
    results.push(...mitataResults);
    results.push(...tinyBenchResults);
    
    // Compare results across all tools
    compareResults(results);
    
    console.log('\n✅ All benchmarks completed successfully!');
  } catch (error) {
    console.error('❌ Error running benchmarks:', error);
  }
}

main();


================================================
FILE: examples/chart-report/node.js
================================================
const { Suite, chartReport } = require('../../lib');
const assert = require('node:assert');

async function runSuiteOne() {
  const suite = new Suite({
    reporter: chartReport,
  });

  await suite
    .add('test 1', function () {
      const pattern = /[123]/g
    })
    .add('test 2', function () {
      const subject = '123123123123123123123123123123123123123123123123'
      const r = subject.replace(/1/g, 'a').replace(/2/g, 'b').replace(/3/g, 'c')
    })
    .run();
}

async function runSuiteTwo() {
  const suite = new Suite({
    reporter: chartReport,
    reporterOptions: {
      printHeader: false
    }
  });

  await suite
    .add('test 3', function () {
      const pattern = /[123]/g
    })
    .add('test 4', function () {
      const subject = '123123123123123123123123123123123123123123123123'
      const r = subject.replace(/1/g, 'a').replace(/2/g, 'b').replace(/3/g, 'c')
      assert.ok(r)
    })
    .run();
}

async function main() {
  await runSuiteOne()
  process.stdout.write('\n\n')
  await runSuiteTwo()
}

main()


================================================
FILE: examples/create-uint32array/node.js
================================================
const { Suite } = require('../../lib');

const suite = new Suite();

suite
  .add(`new Uint32Array(1024)`, { baseline: true }, function () {
    return new Uint32Array(1024);
  })
  .add(`new Uint32Array(1024) with 10 repetitions`,  {repeatSuite: 10}, function () {
    return new Uint32Array(1024);
  })
  .add(`new Uint32Array(1024) with min samples of 50`, {minSamples: 50}, function() {
    return new Uint32Array(1024);
  })
  .add(`[Managed] new Uint32Array(1024)`, function (timer) {
    const assert = require('node:assert');

    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = new Uint32Array(1024);
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .run();


================================================
FILE: examples/create-uint32array/node.js.log
================================================
new Uint32Array(1024) x 2,930,763 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(332.08ns ... 355.52ns) p75=344.36ns p99=355.52ns
[Managed] new Uint32Array(1024) x 2,934,651 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(335.94ns ... 357.76ns) p75=340.16ns p99=357.76ns
----------------------------------------------------------------------------
new Uint32Array(1024) x 2,967,727 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(330.75ns ... 337.55ns) p75=334.98ns p99=337.55ns
[Managed] new Uint32Array(1024) x 3,029,150 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(326.51ns ... 341.28ns) p75=331.01ns p99=341.28ns
----------------------------------------------------------------------------
new Uint32Array(1024) x 2,920,851 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(332.88ns ... 363.08ns) p75=348.19ns p99=363.08ns
[Managed] new Uint32Array(1024) x 3,032,256 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(327.13ns ... 343.75ns) p75=329.19ns p99=343.75ns
----------------------------------------------------------------------------


================================================
FILE: examples/crypto-verify/node.js
================================================
const crypto = require('node:crypto');
const { readFileSync } = require('fs');
const { Suite } = require('../../lib');

const rsaPrivateKey = readFileSync(`${__dirname}/private-key.pem`, 'utf-8');
const rsaPublicKey = readFileSync(`${__dirname}/public-key.pem`, 'utf-8');

const thing = 'hello world';
const algorithm = 'RSA-SHA256';
const signature = crypto.createSign(algorithm).update(thing).sign(rsaPrivateKey, 'base64');

const suite = new Suite();

suite
  .add(`crypto.createVerify('${algorithm}')`, function () {
    var verifier = crypto.createVerify(algorithm);
    verifier.update(thing);
    verifier.verify(rsaPublicKey, signature, 'base64');
  })
  .add(`crypto.verify('${algorithm}')`, function () {
    crypto.verify(algorithm, thing, rsaPublicKey, Buffer.from(signature, 'base64'));
  })
  .add(`[Managed] crypto.createVerify('RSA-SHA256')`, function (timer) {
    const crypto = require('node:crypto');
    const { readFileSync } =require('node:fs');
    const assert = require('node:assert');

    const rsaPrivateKey = readFileSync(`${__dirname}/private-key.pem`, 'utf-8');
    const rsaPublicKey = readFileSync(`${__dirname}/public-key.pem`, 'utf-8');

    const thing = 'hello world'
    const signature = crypto.createSign('RSA-SHA256').update(thing).sign(rsaPrivateKey, 'base64')

    let verifier;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      verifier = crypto.createVerify('RSA-SHA256')
      verifier.update(thing)
      verifier.verify(rsaPublicKey, signature, 'base64')
    }
    timer.end(timer.count);

    assert.ok(verifier);
  })
  .add(`[Managed] crypto.verify('RSA-SHA256')`, function (timer) {
    const crypto = require('node:crypto');
    const { readFileSync } = require('node:fs');
    const assert = require('node:assert');

    const rsaPrivateKey = readFileSync(`${__dirname}/private-key.pem`, 'utf-8');
    const rsaPublicKey = readFileSync(`${__dirname}/public-key.pem`, 'utf-8');

    const thing = 'hello world'
    const signature = crypto.createSign('RSA-SHA256').update(thing).sign(rsaPrivateKey, 'base64')

    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = crypto.verify('RSA-SHA256', thing, rsaPublicKey, Buffer.from(signature, 'base64'));
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .run();


================================================
FILE: examples/crypto-verify/node.js.log
================================================
crypto.createVerify('RSA-SHA256') x 10,925 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(88.50us ... 93.51us) p75=91.54us p99=93.51us
crypto.verify('RSA-SHA256') x 10,988 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(90.93us ... 91.84us) p75=91.58us p99=91.84us
[Managed] crypto.createVerify('RSA-SHA256') x 10,520 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(88.44us ... 92.23us) p75=91.47us p99=92.23us
[Managed] crypto.verify('RSA-SHA256') x 10,948 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(89.98us ... 92.36us) p75=91.49us p99=92.36us
----------------------------------------------------------------------------
crypto.createVerify('RSA-SHA256') x 10,807 ops/sec (8 runs sampled) v8-never-optimize=true min..max=(91.66us ... 92.58us) p75=92.23us p99=92.58us
crypto.verify('RSA-SHA256') x 10,964 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(88.95us ... 92.46us) p75=91.83us p99=92.46us
[Managed] crypto.createVerify('RSA-SHA256') x 10,954 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(90.08us ... 92.88us) p75=91.72us p99=92.88us
[Managed] crypto.verify('RSA-SHA256') x 10,990 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(90.31us ... 92.43us) p75=91.43us p99=92.43us
----------------------------------------------------------------------------
crypto.createVerify('RSA-SHA256') x 10,890 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(87.88us ... 94.08us) p75=92.96us p99=94.08us
crypto.verify('RSA-SHA256') x 10,906 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(91.03us ... 92.45us) p75=91.66us p99=92.45us
[Managed] crypto.createVerify('RSA-SHA256') x 11,050 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(87.94us ... 92.09us) p75=91.88us p99=92.09us
[Managed] crypto.verify('RSA-SHA256') x 10,990 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(90.29us ... 92.13us) p75=91.92us p99=92.13us
----------------------------------------------------------------------------


================================================
FILE: examples/crypto-verify/private-key.pem
================================================
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAz7QweYwr7puNtc8/6jf4pADXfY2/HVq7LgI7JXkAwW5HTEjU
Rvu02SYC7n/ylr86Da4hcAEAFBC2baVh7J0EnLo6D4FA3yV4s5zj7tqL+p2CdniY
MDEny+uxS/9eRuLf1RIYHjSVB6wOoU4lg9FtDOQA8W09ZDLvc3/4ZSwEf9O2J5Vm
qcSGaPt35eIEBS0iIMiOUCGqbUcVMZkp4JO7I65HOK/g0Scvb1LLY6f4qDsThqyi
ID/NXM5LtjnztRP+9dCLT9DdwC+LeU2te6vcEwC2bPYs3nUwkZL4qqIWO6GHaavn
gFKSmbmc9muVAPmYW/ffMtznKZaWCp9Li0JGuQIDAQABAoIBAQC7OI7hYSpQgEKy
eUgBlcY3/tI/SD/W8+v5QuWRl4rI0ODPsG44NbcEbbECzq4al/B6WFWnoh8x9waZ
uxOTts1rgKnJRBb3jc1JCcijirfWhZgNthJojkZzF9bOzDds6iAc7Zxzza3wJnVh
jRFfyqzji7oV5QQLh6YzlEyQ1aaQmOKTkCDV1UDetI8iItUvq3i8EwsFmtfvXjTl
aymL/xSd3R6w3WDEd8PS5ZPDoFmkt2h/4IhOo6bVXLwWBWqcopRAvzGQrc806c2l
jjePwk9fddIG+vIHc8DHqaC/WzMR6iBt3K7Q9Eyu4k97qeOxB5TIEVlhxg2DJON9
DlGtInXpAoGBAPje3L0xL441i7kh7GqiWtXiDgxVwdPmN5p7n755MddSxvu8894h
T9/LxwAVcpolXANgyRtrl5bu/gXgznKefmVr976BzG2DY33PESf5FnHZAmixWSfz
VOdfVlz+Bk/BI+nVwmeT0+8NSHJ6TJ/9NOSzI9ctUceszIHG5/Gfc2wHAoGBANWn
bHNT7aphFqyUMfWyc6+h8Radq/RVMrOGeD2wRRqUTeb2Ydbx2OwB+gcwnlbsQjfS
BYAa3kn1z5K5kOigB9qu6x7zuM9SMReKIlMg3NpYVyKKj+JaNF3YArFa5TWy0B26
wNJ0FiiZyPq4eP5hPwM+Bed4ytIRWa54P5GeRYc/AoGAWT8ijb4rvaW6G4Ps0jiy
tmzAeO/v+FtgqUeX+6helUccEH6sPYZYrHrZPFB0ro6jNprow6qLzBacheMeZcAs
t5ZGW80UUFmDvkQZdOpAgEdAM+cVf9wlIGvx/psiDEvI4zxC4P4ETH/I8TSmceFN
rI4JVkrsPtza4ddAqkdyDtUCgYAaoMs7dHJikccpqy6u2JbihORvVSdhRF0VUuUZ
iyaRsXokFwEKsQnAIF7xFnYljzyRiHN3C+I4hZJhTw9obsmLz9EuAmI+NJg5vtWY
Vrgv3mK9w1c7dtKf/5QWVqXKk4asreHqWN2KIeCSnvs1eRlJZimGN9/PXqo2vHXv
yDISMQKBgE22EhVB99rEsLXDCXOUHIFGpW46ZavQc4DLXg+uIQm3y0WWyc0oyNF8
9kr1luu5QI5PV9mWpSKa3SKmc74biyxhlUp/DYuMyuSXpdDegMAKheAHVXP9ToU/
5qhq4HBcISN3CwSAYcFcbqC3cB07T+IwX6NTEz4zel4gty8t/tsM
-----END RSA PRIVATE KEY-----

================================================
FILE: examples/crypto-verify/public-key.pem
================================================
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz7QweYwr7puNtc8/6jf4
pADXfY2/HVq7LgI7JXkAwW5HTEjURvu02SYC7n/ylr86Da4hcAEAFBC2baVh7J0E
nLo6D4FA3yV4s5zj7tqL+p2CdniYMDEny+uxS/9eRuLf1RIYHjSVB6wOoU4lg9Ft
DOQA8W09ZDLvc3/4ZSwEf9O2J5VmqcSGaPt35eIEBS0iIMiOUCGqbUcVMZkp4JO7
I65HOK/g0Scvb1LLY6f4qDsThqyiID/NXM5LtjnztRP+9dCLT9DdwC+LeU2te6vc
EwC2bPYs3nUwkZL4qqIWO6GHaavngFKSmbmc9muVAPmYW/ffMtznKZaWCp9Li0JG
uQIDAQAB
-----END PUBLIC KEY-----

================================================
FILE: examples/csv-report/node.js
================================================
const { Suite } = require('../../lib');
const assert = require('node:assert');

const suite = new Suite();

suite
  .add('single with matcher', function () {
    const pattern = /[123]/g
    const replacements = { 1: 'a', 2: 'b', 3: 'c' }
    const subject = '123123123123123123123123123123123123123123123123'
    const r = subject.replace(pattern, m => replacements[m])
    assert.ok(r);
  })
  .add('multiple replaces', function () {
    const subject = '123123123123123123123123123123123123123123123123'
    const r = subject.replace(/1/g, 'a').replace(/2/g, 'b').replace(/3/g, 'c')
    assert.ok(r);
  })
  .run();


================================================
FILE: examples/dce-detection/example.js
================================================
const { Suite } = require("../../lib/index");

// Enable DCE detection to catch benchmarks that may be optimized away
const suite = new Suite({
	detectDeadCodeElimination: true,
});

// Example 1: Likely to trigger DCE warning - result not used
suite.add("simple addition (likely DCE)", () => {
	const result = 1 + 1;
	// result is never used - JIT might optimize this away
});

// Example 2: Result is used - should not trigger warning
suite.add("simple addition (used)", () => {
	const result = 1 + 1;
	if (result !== 2) throw new Error("Unexpected result");
});

// Example 3: Array creation without use - likely DCE
suite.add("array creation (likely DCE)", () => {
	const arr = new Array(100);
	// arr is never accessed - might be optimized away
});

// Example 4: Array creation with access - should not trigger warning
suite.add("array creation (accessed)", () => {
	const arr = new Array(100);
	arr[0] = 1; // Using the array
});

// Example 5: Object creation without use - likely DCE
suite.add("object creation (likely DCE)", () => {
	const obj = { x: 1, y: 2, z: 3 };
	// obj is never accessed
});

// Example 6: More realistic computation
suite.add("string operations", () => {
	const str1 = "hello";
	const str2 = "world";
	const result = str1 + " " + str2;
	if (!result.includes("hello")) throw new Error("Missing hello");
});

suite.run();


================================================
FILE: examples/dce-detection/with-dce-disabled.js
================================================
const { Suite } = require("../../lib/index");

// Default behavior - DCE detection is disabled, V8NeverOptimizePlugin is used
// You don't need to set detectDeadCodeElimination: false explicitly
const suite = new Suite();

// These benchmarks will run with V8NeverOptimizePlugin, so they'll be slower
// but more deterministic and won't be optimized away
suite.add("simple addition", () => {
	const result = 1 + 1;
});

suite.add("array creation", () => {
	const arr = new Array(100);
});

suite.run();


================================================
FILE: examples/dce-detection/without-never-optimize.js
================================================
const { Suite } = require("../../lib/index");

// Enable DCE detection - this automatically disables V8NeverOptimizePlugin
// In this mode, V8 optimizations occur naturally and DCE warnings help identify issues
const suite = new Suite({
	detectDeadCodeElimination: true,
});

// Example 1: Likely to trigger DCE warning - result not used
suite.add("simple addition (likely DCE)", () => {
	const result = 1 + 1;
	// result is never used - JIT will optimize this away
});

// Example 2: Result is used - should not trigger warning
suite.add("simple addition (used)", () => {
	const result = 1 + 1;
	if (result !== 2) throw new Error("Unexpected result");
});

// Example 3: Array creation without use - likely DCE
suite.add("array creation (likely DCE)", () => {
	const arr = new Array(100);
	// arr is never accessed - will be optimized away
});

// Example 4: Array creation with access - should not trigger warning
suite.add("array creation (accessed)", () => {
	const arr = new Array(100);
	arr[0] = 1; // Using the array
});

// Example 5: More realistic computation that takes time
suite.add("actual work", () => {
	let sum = 0;
	for (let i = 0; i < 100; i++) {
		sum += Math.sqrt(i);
	}
	if (sum < 0) throw new Error("Impossible");
});

suite.run();


================================================
FILE: examples/deleting-properties/node.js
================================================
const { Suite } = require('../../lib');

const suite = new Suite();

const NullObject = function NullObject() { }
NullObject.prototype = Object.create(null);
%NeverOptimizeFunction(NullObject);

suite
  .add('Using delete property', function () {
    const data = { x: 1, y: 2, z: 3 }
    delete data.y

    data.x
    data.y
    data.z
  })
  .add('Using delete property (proto: null)', function () {
    const data = { __proto__: null, x: 1, y: 2, z: 3 }
    delete data.y

    data.x
    data.y
    data.z
  })
  .add('Using delete property (cached proto: null)', function () {
    const data = new NullObject()

    data.x = 1
    data.y = 2
    data.z = 3

    delete data.y

    data.x
    data.y
    data.z
  })
  .add('Using undefined assignment', function () {
    const data = { x: 1, y: 2, z: 3 }
    data.y = undefined

    data.x
    data.y
    data.z
  })
  .add('Using undefined assignment (proto: null)', function () {
    const data = { __proto__: null, x: 1, y: 2, z: 3 }
    data.y = undefined

    data.x
    data.y
    data.z
  })
  .add('Using undefined property (cached proto: null)', function () {
    const data = new NullObject()

    data.x = 1
    data.y = 2
    data.z = 3

    data.y = undefined

    data.x
    data.y
    data.z
  })
  .add('[Managed] Using undefined property (cached proto: null)', function (t) {
    const NullObject = function () { }
    NullObject.prototype = Object.create(null)

    t.start();
    for (let i = 0; i < t.count; i++) {
      const data = new NullObject()

      data.x = 1
      data.y = 2
      data.z = 3

      data.y = undefined

      data.x
      data.y
      data.z
    }
    t.end(t.count);
  })
  .run();


================================================
FILE: examples/deleting-properties/node.js.log
================================================
Using delete property x 7,763,866 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(128.11ns ... 129.99ns) p75=129.03ns p99=129.99ns
Using delete property (proto: null) x 22,946,068 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(43.13ns ... 44.11ns) p75=43.74ns p99=44.11ns
Using delete property (cached proto: null) x 7,331,951 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(135.64ns ... 137.39ns) p75=136.52ns p99=137.39ns
Using undefined assignment x 133,449,849 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(7.45ns ... 7.56ns) p75=7.53ns p99=7.56ns
Using undefined assignment (proto: null) x 25,432,632 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(38.72ns ... 40.06ns) p75=39.60ns p99=40.06ns
Using undefined property (cached proto: null) x 58,871,059 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(16.92ns ... 17.12ns) p75=17.01ns p99=17.12ns
[Managed] Using undefined property (cached proto: null) x 35,463,712 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(28.05ns ... 28.43ns) p75=28.25ns p99=28.43ns
----------------------------------------------------------------------------
Using delete property x 6,669,856 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(149.14ns ... 151.02ns) p75=150.12ns p99=151.02ns
Using delete property (proto: null) x 15,242,131 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(64.77ns ... 66.38ns) p75=66.25ns p99=66.38ns
Using delete property (cached proto: null) x 5,920,843 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(167.87ns ... 170.33ns) p75=169.07ns p99=170.33ns
Using undefined assignment x 78,647,245 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(12.62ns ... 12.83ns) p75=12.70ns p99=12.83ns
Using undefined assignment (proto: null) x 16,278,910 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(60.79ns ... 62.25ns) p75=61.57ns p99=62.25ns
Using undefined property (cached proto: null) x 27,262,884 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(36.54ns ... 36.65ns) p75=36.62ns p99=36.65ns
[Managed] Using undefined property (cached proto: null) x 28,068,785 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(35.07ns ... 35.79ns) p75=35.67ns p99=35.79ns
----------------------------------------------------------------------------
Using delete property x 7,632,095 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(129.63ns ... 132.85ns) p75=131.19ns p99=132.85ns
Using delete property (proto: null) x 23,040,357 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(43.06ns ... 44.20ns) p75=43.56ns p99=44.20ns
Using delete property (cached proto: null) x 7,222,103 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(137.05ns ... 139.88ns) p75=139.18ns p99=139.88ns
Using undefined assignment x 133,133,677 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(7.49ns ... 7.53ns) p75=7.52ns p99=7.53ns
Using undefined assignment (proto: null) x 25,217,884 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(39.24ns ... 40.48ns) p75=39.89ns p99=40.48ns
Using undefined property (cached proto: null) x 58,899,972 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(16.94ns ... 17.03ns) p75=16.99ns p99=17.03ns
[Managed] Using undefined property (cached proto: null) x 34,904,120 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(28.34ns ... 29.89ns) p75=28.84ns p99=29.89ns
----------------------------------------------------------------------------


================================================
FILE: examples/empty/node.js
================================================
const { Suite } = require('../../lib');

const suite = new Suite();

suite
  .add(`empty`, function () {})
  .add(`empty async`, async function () {})
  .run();


================================================
FILE: examples/empty/node.js.log
================================================
empty x 218,984,985 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(4.53ns ... 4.66ns) p75=4.58ns p99=4.66ns
empty async x 20,898,403 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(47.46ns ... 48.57ns) p75=48.04ns p99=48.57ns
----------------------------------------------------------------------------
empty x 220,571,877 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(4.49ns ... 4.61ns) p75=4.58ns p99=4.61ns
empty async x 20,925,022 ops/sec (14 runs sampled) v8-never-optimize=true min..max=(37.43ns ... 48.60ns) p75=48.03ns p99=48.60ns
----------------------------------------------------------------------------
empty x 218,923,690 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(4.52ns ... 4.64ns) p75=4.59ns p99=4.64ns
empty async x 20,792,931 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(42.94ns ... 49.45ns) p75=48.54ns p99=49.45ns
----------------------------------------------------------------------------


================================================
FILE: examples/fs-read-async/node.js
================================================
const { Suite } = require('../../lib');
const { readFile } = require('node:fs/promises');
const { resolve } = require('node:path');

const suite = new Suite();

const sampleFile = resolve(__dirname, 'sample-file.txt');

suite
  .add('readFile', async function () {
    const r = await readFile(sampleFile);
  })
  .add('readFile utf-8', async function () {
    const r = await readFile(sampleFile, 'utf-8');
  })
  .add('[managed] readFile', async function (timer) {
    const { readFile } = require('node:fs/promises');
    const { resolve } = require('node:path');
    const assert = require('node:assert');

    const sampleFile = resolve(__dirname, 'sample-file.txt');
    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = await readFile(sampleFile);
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .add('[managed] readFile utf-8', async function (timer) {
    const { readFile } = require('node:fs/promises');
    const { resolve } = require('node:path');
    const assert = require('node:assert');

    const sampleFile = resolve(__dirname, 'sample-file.txt');
    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = await readFile(sampleFile, 'utf-8');
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .run();


================================================
FILE: examples/fs-read-async/node.js.log
================================================
readFile x 23,167 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(42.59us ... 43.59us) p75=43.42us p99=43.59us
readFile utf-8 x 23,021 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(43.14us ... 43.92us) p75=43.64us p99=43.92us
[managed] readFile x 23,386 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(42.63us ... 43.04us) p75=42.89us p99=43.04us
[managed] readFile utf-8 x 23,302 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(42.76us ... 43.30us) p75=43.01us p99=43.30us
----------------------------------------------------------------------------
readFile x 23,177 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(42.70us ... 43.54us) p75=43.31us p99=43.54us
readFile utf-8 x 23,155 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(42.34us ... 43.53us) p75=43.15us p99=43.53us
[managed] readFile x 23,538 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(42.22us ... 42.82us) p75=42.59us p99=42.82us
[managed] readFile utf-8 x 23,458 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(42.11us ... 43.20us) p75=42.86us p99=43.20us
----------------------------------------------------------------------------
readFile x 23,235 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(42.73us ... 43.41us) p75=43.17us p99=43.41us
readFile utf-8 x 23,130 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(42.90us ... 44.40us) p75=43.62us p99=44.40us
[managed] readFile x 23,490 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(42.40us ... 42.89us) p75=42.66us p99=42.89us
[managed] readFile utf-8 x 23,553 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(41.99us ... 42.81us) p75=42.58us p99=42.81us
----------------------------------------------------------------------------


================================================
FILE: examples/fs-read-async/node.managed.js
================================================
const { Suite } = require('../../lib');

const suite = new Suite();

suite
  .add('readFile', async function (timer) {
    const { readFile } = require('node:fs/promises');
    const { resolve } = require('node:path');
    const assert = require('node:assert');

    const sampleFile = resolve(__dirname, 'sample-file.txt');
    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = await readFile(sampleFile);
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .add('readFile utf-8', async function (timer) {
    const { readFile } = require('node:fs/promises');
    const { resolve } = require('node:path');
    const assert = require('node:assert');

    const sampleFile = resolve(__dirname, 'sample-file.txt');
    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = await readFile(sampleFile, 'utf-8');
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .run();


================================================
FILE: examples/fs-read-async/node.managed.js.log
================================================
readFile x 23,066 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(42.59us ... 43.63us) p75=43.20us p99=43.63us
readFile utf-8 x 23,334 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(42.21us ... 43.70us) p75=42.96us p99=43.70us
----------------------------------------------------------------------------
readFile x 23,145 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(42.64us ... 43.18us) p75=43.04us p99=43.18us
readFile utf-8 x 23,324 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(42.54us ... 43.80us) p75=42.93us p99=43.80us
----------------------------------------------------------------------------
readFile x 23,124 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(42.36us ... 43.30us) p75=42.99us p99=43.30us
readFile utf-8 x 23,277 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(41.50us ... 43.88us) p75=42.98us p99=43.88us
----------------------------------------------------------------------------


================================================
FILE: examples/fs-read-async/sample-file.txt
================================================
hello

================================================
FILE: examples/fs-read-sync/node.js
================================================
const { Suite } = require('../../lib');
const { readFileSync } = require('node:fs');
const { resolve } = require('node:path');

const suite = new Suite();

const sampleFile = resolve(__dirname, 'sample-file.txt');

suite
  .add('readFileSync', function () {
    const r = readFileSync(sampleFile);
  })
  .add('readFileSync utf-8', function () {
    const r = readFileSync(sampleFile, 'utf-8');
  })
  .add('[Managed] readFileSync', function (timer) {
    const { readFileSync } = require('node:fs');
    const { resolve } = require('node:path');
    const assert = require('node:assert');

    const sampleFile = resolve(__dirname, 'sample-file.txt');
    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = readFileSync(sampleFile);
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .add('[Managed] readFileSync utf-8', function (timer) {
    const { readFileSync } = require('node:fs');
    const { resolve } = require('node:path');
    const assert = require('node:assert');

    const sampleFile = resolve(__dirname, 'sample-file.txt');
    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = readFileSync(sampleFile, 'utf-8');
    }
    timer.end(timer.count);

    assert.ok(r);
  })

  .run();


================================================
FILE: examples/fs-read-sync/node.js.log
================================================
readFileSync x 198,828 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(5.01us ... 5.06us) p75=5.04us p99=5.06us
readFileSync utf-8 x 203,828 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(4.88us ... 4.94us) p75=4.92us p99=4.94us
[Managed] readFileSync x 196,632 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(5.05us ... 5.08us) p75=5.07us p99=5.08us
[Managed] readFileSync utf-8 x 203,265 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(4.89us ... 4.92us) p75=4.91us p99=4.92us
----------------------------------------------------------------------------
readFileSync x 198,461 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(5.00us ... 5.05us) p75=5.02us p99=5.05us
readFileSync utf-8 x 205,171 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(4.82us ... 4.86us) p75=4.86us p99=4.86us
[Managed] readFileSync x 193,061 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(5.05us ... 5.48us) p75=5.30us p99=5.48us
[Managed] readFileSync utf-8 x 204,046 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(4.86us ... 4.92us) p75=4.91us p99=4.92us
----------------------------------------------------------------------------
readFileSync x 196,533 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(5.02us ... 5.20us) p75=5.10us p99=5.20us
readFileSync utf-8 x 205,213 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(4.83us ... 4.89us) p75=4.86us p99=4.89us
[Managed] readFileSync x 183,333 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(5.06us ... 6.46us) p75=5.28us p99=6.46us
[Managed] readFileSync utf-8 x 201,593 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(4.90us ... 5.07us) p75=5.06us p99=5.07us
----------------------------------------------------------------------------


================================================
FILE: examples/fs-read-sync/sample-file.txt
================================================
hello

================================================
FILE: examples/html-report/node.js
================================================
const { Suite, htmlReport } = require('../../lib');
const assert = require('node:assert');

const suite = new Suite({
  reporter: htmlReport,
});

suite
  .add('single with matcher', function () {
    const pattern = /[123]/g
    const replacements = { 1: 'a', 2: 'b', 3: 'c' }
    const subject = '123123123123123123123123123123123123123123123123'
    const r = subject.replace(pattern, m => replacements[m])
    assert.ok(r);
  })
  .add('Multiple replaces', function () {
    const subject = '123123123123123123123123123123123123123123123123'
    const r = subject.replace(/1/g, 'a').replace(/2/g, 'b').replace(/3/g, 'c')
    assert.ok(r);
  })
  .run();


================================================
FILE: examples/html-report/result.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Benchmark Visualizer</title>
  <style>
    body {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      height: 100vh;
      margin: 0;
      background: #f4f4f4;
      font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
    }
    .env {
      width: 400px;
    }

    .container {
      position: relative;
      width: 400px; /* Reduced width */
      height: 200px;
      border: 2px solid #000;
      background: #fff;
    }

    .label {
      position: absolute;
      left: -130px; /* Place labels outside the box */
      width: 100px;
      text-align: right;
      font-size: 14px;
    }

    .circle {
      width: 40px;
      height: 40px;
      border-radius: 50%;
      position: absolute;
    }

    .number {
      font-family: 'Times New Roman', Times, serif;
    }

    .made-with {
      position: fixed;
      bottom: 10px;
      right: 10px;
      padding: 10px;
      font-size: 12px;
    }
    .made-with a {
      color: #2C682C;
    }
    .made-with a:hover {
      text-decoration: none;
    }

    
      #label-single-with-matcher {
        top: 20px;
      }

      #circle-single-with-matcher {
        background-color: blue;
        top: 20px;
      }
    
      #label-Multiple-replaces {
        top: 100px;
      }

      #circle-Multiple-replaces {
        background-color: orange;
        top: 100px;
      }
    

    /* Dark theme */
    @media (prefers-color-scheme: dark) {
      body {
        background: #333;
        color: #fff;
      }

      .container {
        border-color: #fff;
        background: #444;
      }

      .made-with a {
        color: #84BA64;
      }
    }
  </style>
</head>
<body>
  <div class="env">
    <p>Node.js version: <span class="number">v20.18.1</span></p>
	<p>Platform: <span class="number">darwin arm64</span></p>
	<p>CPU Cores: <span class="number">8</span> vCPUs | <span class="number">16.0GB Mem</span></p>
  </div>  

  <div class="container">
    
      <div id="circle-single-with-matcher" class="circle"></div>
    
      <div id="circle-Multiple-replaces" class="circle"></div>
    

    
      <div id="label-single-with-matcher" class="label">
	  single-with-matcher(<span class="number">660,788.4</span> ops/sec)
	  </div>
    
      <div id="label-Multiple-replaces" class="label">
	  Multiple-replaces(<span class="number">578,527</span> ops/sec)
	  </div>
    
  </div>

  <div class="made-with">
    <p>Benchmark done with <a href="https://github.com/RafaelGSS/bench-node">bench-node</a></p>
  </div>

  </div>

  <script>
    const durations = [{"name":"single-with-matcher","duration":10,"opsSecFormatted":"660,788.4"},{"name":"Multiple-replaces","duration":11.421911109342416,"opsSecFormatted":"578,527"}];

    const animateCircles = () => {
      const boxWidth = 400; // Width of the container box
      const circles = durations.map((d) => ({
        id: "circle-" + d.name,
        duration: d.duration,
        position: 0,
        direction: 1,
      }));

      const update = () => {
        circles.forEach(circle => {
          const element = document.getElementById(circle.id);

          circle.position += circle.direction * (boxWidth / circle.duration) * 0.5;

          if (circle.position >= boxWidth - 20 || circle.position <= 0) {
            circle.direction *= -1; // Reverse direction on collision
          }

          element.style.transform = `translateX(${circle.position}px)`;
        });

        setTimeout(() => {
          requestAnimationFrame(update);
        }, 1000 / 120); // "60 FPS"
      };

      update();
    };

    animateCircles();
  </script>
</body>
</html>


================================================
FILE: examples/json-report/node.js
================================================
const { Suite, jsonReport } = require('../../lib');
const assert = require('node:assert');

const suite = new Suite({
  reporter: jsonReport,
});

suite
  .add('single with matcher', function () {
    const pattern = /[123]/g
    const replacements = { 1: 'a', 2: 'b', 3: 'c' }
    const subject = '123123123123123123123123123123123123123123123123'
    const r = subject.replace(pattern, m => replacements[m])
    assert.ok(r);
  })
  .add('Multiple replaces', function () {
    const subject = '123123123123123123123123123123123123123123123123'
    const r = subject.replace(/1/g, 'a').replace(/2/g, 'b').replace(/3/g, 'c')
    assert.ok(r);
  })
  .run();


================================================
FILE: examples/plugins/all.js
================================================
const {
  Suite,
  V8GetOptimizationStatus,
  V8NeverOptimizePlugin,
  V8OptimizeOnNextCallPlugin,
  MemoryPlugin,
} = require('../../lib');

const suite = new Suite({
  plugins: [
    new V8GetOptimizationStatus(),
    new V8NeverOptimizePlugin(),
    new MemoryPlugin(),
    new V8OptimizeOnNextCallPlugin(),
  ],
});

suite
  .add(`new Uint32Array(1024)`, function () {
    return new Uint32Array(1024);
  })
  .add(`[Managed] new Uint32Array(1024)`, function (timer) {
    const assert = require('node:assert');

    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = new Uint32Array(1024);
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .run();


================================================
FILE: examples/plugins/all.js.log
================================================
new Uint32Array(1024) x 2,395,395 ops/sec (14 runs sampled) v8-opt-status="Optimized, Interpreted, Marked for Optimization, Concurrently Optimizing" v8-never-optimize=true min..max=(302.80ns ... 435.20ns) p75=420.50ns p99=435.20ns
[Managed] new Uint32Array(1024) x 1,878,469 ops/sec (12 runs sampled) v8-opt-status="Optimized, Interpreted, Marked for Optimization, Concurrently Optimizing" v8-never-optimize=true min..max=(217.82ns ... 577.91ns) p75=430.46ns p99=577.91ns
----------------------------------------------------------------------------
new Uint32Array(1024) x 2,282,799 ops/sec (13 runs sampled) v8-opt-status="Optimized, Interpreted, Marked for Optimization, Concurrently Optimizing" v8-never-optimize=true min..max=(339.06ns ... 479.78ns) p75=449.29ns p99=479.78ns
[Managed] new Uint32Array(1024) x 2,219,660 ops/sec (10 runs sampled) v8-opt-status="Optimized, Interpreted, Marked for Optimization, Concurrently Optimizing" v8-never-optimize=true min..max=(383.40ns ... 548.65ns) p75=461.81ns p99=548.65ns
----------------------------------------------------------------------------
new Uint32Array(1024) x 2,362,479 ops/sec (11 runs sampled) v8-opt-status="Optimized, Interpreted, Marked for Optimization, Concurrently Optimizing" v8-never-optimize=true min..max=(384.64ns ... 456.35ns) p75=440.57ns p99=456.35ns
[Managed] new Uint32Array(1024) x 2,272,352 ops/sec (10 runs sampled) v8-opt-status="Optimized, Interpreted, Marked for Optimization, Concurrently Optimizing" v8-never-optimize=true min..max=(421.95ns ... 451.89ns) p75=443.17ns p99=451.89ns
----------------------------------------------------------------------------


================================================
FILE: examples/plugins/memory.js
================================================
const { Suite, MemoryPlugin} = require('../../lib');

const suite = new Suite({
    plugins: [new MemoryPlugin()],
});

suite
    .add(`new Uint32Array(1024)`, function () {
        return new Uint32Array(1024);
    })
    .add(`[Managed] new Uint32Array(1024)`, function (timer) {
        const assert = require('node:assert');

        let r;

        timer.start();
        for (let i = 0; i < timer.count; i++) {
            r = new Uint32Array(1024);
        }
        timer.end(timer.count);

        assert.ok(r);
    })
    .run();


================================================
FILE: examples/plugins/v8-get-opt-status.js
================================================
const { Suite, V8GetOptimizationStatus } = require('../../lib');

const suite = new Suite({
  plugins: [new V8GetOptimizationStatus()],
});

suite
  .add(`new Uint32Array(1024)`, function () {
    return new Uint32Array(1024);
  })
  .add(`[Managed] new Uint32Array(1024)`, function (timer) {
    const assert = require('node:assert');

    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = new Uint32Array(1024);
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .run();


================================================
FILE: examples/plugins/v8-get-opt-status.js.log
================================================
new Uint32Array(1024) x 2,353,498 ops/sec (10 runs sampled) v8-opt-status="Optimized, Interpreted, Marked for Optimization, Concurrently Optimizing" min..max=(387.20ns ... 435.11ns) p75=426.25ns p99=435.11ns
[Managed] new Uint32Array(1024) x 2,295,396 ops/sec (12 runs sampled) v8-opt-status="Optimized, Interpreted, Marked for Optimization, Concurrently Optimizing" min..max=(346.78ns ... 471.27ns) p75=450.57ns p99=471.27ns
----------------------------------------------------------------------------
new Uint32Array(1024) x 2,206,492 ops/sec (11 runs sampled) v8-opt-status="Optimized, Interpreted, Marked for Optimization, Concurrently Optimizing" min..max=(413.34ns ... 498.95ns) p75=457.27ns p99=498.95ns
[Managed] new Uint32Array(1024) x 2,308,235 ops/sec (10 runs sampled) v8-opt-status="Optimized, Interpreted, Marked for Optimization, Concurrently Optimizing" min..max=(410.95ns ... 472.38ns) p75=444.99ns p99=472.38ns
----------------------------------------------------------------------------
new Uint32Array(1024) x 2,765,470 ops/sec (11 runs sampled) v8-opt-status="Optimized, Interpreted, Marked for Optimization, Concurrently Optimizing" min..max=(343.99ns ... 396.13ns) p75=386.55ns p99=396.13ns
[Managed] new Uint32Array(1024) x 2,773,144 ops/sec (11 runs sampled) v8-opt-status="Optimized, Interpreted, Marked for Optimization, Concurrently Optimizing" min..max=(351.75ns ... 377.92ns) p75=369.54ns p99=377.92ns
----------------------------------------------------------------------------


================================================
FILE: examples/plugins/v8-never-optimize.js
================================================
const { Suite, V8NeverOptimizePlugin } = require('../../lib');

const suite = new Suite({
  plugins: [new V8NeverOptimizePlugin()],
});

suite
  .add(`new Uint32Array(1024)`, function () {
    return new Uint32Array(1024);
  })
  .add(`[Managed] new Uint32Array(1024)`, function (timer) {
    const assert = require('node:assert');

    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = new Uint32Array(1024);
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .run();


================================================
FILE: examples/plugins/v8-never-optimize.js.log
================================================
new Uint32Array(1024) x 2,535,349 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(357.30ns ... 442.55ns) p75=416.14ns p99=442.55ns
[Managed] new Uint32Array(1024) x 2,646,454 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(356.81ns ... 405.88ns) p75=382.20ns p99=405.88ns
----------------------------------------------------------------------------
new Uint32Array(1024) x 2,785,937 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(350.61ns ... 368.86ns) p75=360.60ns p99=368.86ns
[Managed] new Uint32Array(1024) x 2,535,974 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(353.44ns ... 462.38ns) p75=447.16ns p99=462.38ns
----------------------------------------------------------------------------
new Uint32Array(1024) x 2,336,195 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(380.49ns ... 453.11ns) p75=431.40ns p99=453.11ns
[Managed] new Uint32Array(1024) x 2,624,328 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(341.92ns ... 432.82ns) p75=411.22ns p99=432.82ns
----------------------------------------------------------------------------


================================================
FILE: examples/plugins/v8-optimize-next-call.js
================================================
const { Suite, V8OptimizeOnNextCallPlugin } = require('../../lib');

const suite = new Suite({
  plugins: [new V8OptimizeOnNextCallPlugin()],
});

suite
  .add(`new Uint32Array(1024)`, function () {
    return new Uint32Array(1024);
  })
  .add(`[Managed] new Uint32Array(1024)`, function (timer) {
    const assert = require('node:assert');

    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = new Uint32Array(1024);
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .run();


================================================
FILE: examples/plugins/v8-optimize-next-call.js.log
================================================
new Uint32Array(1024) x 2,812,339 ops/sec (13 runs sampled) v8-optimize-next-call=enabled min..max=(314.34ns ... 373.62ns) p75=359.22ns p99=373.62ns
[Managed] new Uint32Array(1024) x 2,763,965 ops/sec (11 runs sampled) v8-optimize-next-call=enabled min..max=(348.80ns ... 381.77ns) p75=373.99ns p99=381.77ns
----------------------------------------------------------------------------
new Uint32Array(1024) x 2,827,020 ops/sec (11 runs sampled) v8-optimize-next-call=enabled min..max=(298.24ns ... 365.66ns) p75=354.33ns p99=365.66ns
[Managed] new Uint32Array(1024) x 2,775,090 ops/sec (12 runs sampled) v8-optimize-next-call=enabled min..max=(349.78ns ... 378.17ns) p75=360.17ns p99=378.17ns
----------------------------------------------------------------------------
new Uint32Array(1024) x 2,793,090 ops/sec (9 runs sampled) v8-optimize-next-call=enabled min..max=(342.17ns ... 352.58ns) p75=350.66ns p99=352.58ns
[Managed] new Uint32Array(1024) x 2,751,982 ops/sec (10 runs sampled) v8-optimize-next-call=enabled min..max=(352.72ns ... 385.30ns) p75=367.30ns p99=385.30ns
----------------------------------------------------------------------------


================================================
FILE: examples/pretty-report/node.js
================================================
const { Suite, prettyReport } = require('../../lib');
const assert = require('node:assert');

const suite = new Suite({
  reporter: prettyReport,
});

suite
  .add('my-group/my-benchmark', () => {
    // A slower benchmark
    for (let i = 0; i < 10000; i++) {}
  })
  .add('my-group/my-benchmark-2', { baseline: true }, function () {
    // The baseline
    for (let i = 0; i < 1000; i++) {}
  })
  .add('second-group/another-benchmark', function () {
    // A faster benchmark
    for (let i = 0; i < 100; i++) {}
  })
  .run();


================================================
FILE: examples/run.sh
================================================
#!/bin/bash

# clean previous logs
rm -f ./**/*.log

for filename in ./**/*.*js; do
    echo "[1] Running $filename"
    node --allow-natives-syntax "./$filename" | sed "s,\x1B\[[0-9;]*m,,g" >>"$filename.log"
    echo -e "----------------------------------------------------------------------------" >>"$filename.log"

    echo "[2] Running $filename"
    node --allow-natives-syntax "./$filename" | sed "s,\x1B\[[0-9;]*m,,g" >>"$filename.log"
    echo -e "----------------------------------------------------------------------------" >>"$filename.log"

    echo "[3] Running $filename"
    node --allow-natives-syntax "./$filename" | sed "s,\x1B\[[0-9;]*m,,g" >>"$filename.log"
    echo -e "----------------------------------------------------------------------------" >>"$filename.log"
done


================================================
FILE: examples/statistical-significance/README.md
================================================
# Statistical Significance Testing (T-Test)

This example demonstrates how to use Welch's t-test to determine if benchmark differences are statistically significant.

## The Problem

When running benchmarks on shared or cloud environments, results can vary due to:
- CPU throttling
- Background processes
- Memory pressure
- Cache effects

A benchmark might show one implementation as "1.05x faster", but is that a real improvement or just noise?

## The Solution

Enable t-test mode with `ttest: true`:

```js
const { Suite } = require('bench-node');

const suite = new Suite({
  ttest: true,  // Automatically sets repeatSuite=30
});

suite.add('baseline', { baseline: true }, () => {
  // ...
});

suite.add('alternative', () => {
  // ...
});
```

When `ttest: true` is set, the suite automatically:
1. Sets `repeatSuite=30` for all benchmarks (can be overridden)
2. Runs Welch's t-test to compare results against baseline
3. Displays significance stars in the output

## Understanding the Output

The output will show significance stars next to comparisons:

```
Summary (vs. baseline):
  baseline/for-loop  (baseline)
  forEach            (1.80x slower) ***
  for-of-loop        (1.09x slower) ***
  reduce             (1.06x faster) **

  Significance: * p<0.05, ** p<0.01, *** p<0.001
```

- `***` = p < 0.001 - Very high confidence (99.9%) the difference is real
- `**` = p < 0.01 - High confidence (99%) the difference is real  
- `*` = p < 0.05 - Moderate confidence (95%) the difference is real
- (no stars) = Not statistically significant - difference may be noise

## When to Use

1. **Comparing similar implementations** - Is the "optimization" actually faster?
2. **CI/CD pipelines** - Detect real regressions vs. flaky results
3. **Cloud/shared environments** - High variance requires statistical validation
4. **Small differences** - 5% faster could be noise or real

## Run the Example

```bash
node --allow-natives-syntax node.js
```

## Sample Output

```
baseline/for-loop   x 85,009,221 ops/sec (311 runs sampled)
reduce              x 89,853,937 ops/sec (321 runs sampled)
for-of-loop         x 78,268,434 ops/sec (302 runs sampled)
forEach             x 47,249,597 ops/sec (334 runs sampled)

Summary (vs. baseline):
  baseline/for-loop  (baseline)
  forEach            (1.80x slower) ***
  for-of-loop        (1.09x slower) ***
  reduce             (1.06x faster) **

  Significance: * p<0.05, ** p<0.01, *** p<0.001
```


================================================
FILE: examples/statistical-significance/node.js
================================================
/**
 * Statistical Significance Example
 *
 * This example demonstrates how to use Welch's t-test to determine
 * if benchmark differences are statistically significant.
 *
 * When running benchmarks, especially on shared/cloud environments,
 * small performance differences may just be random noise. The t-test
 * helps identify when a difference is real vs. just variance.
 *
 * Run with: node --allow-natives-syntax node.js
 */

const { Suite } = require('../../lib');

// Enable t-test mode - this automatically sets repeatSuite=30 for all benchmarks
const suite = new Suite({
  ttest: true,
});

// Baseline: Simple array sum using for loop
suite.add('baseline/for-loop', { baseline: true }, () => {
  const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  let sum = 0;
  for (let i = 0; i < arr.length; i++) {
    sum += arr[i];
  }
  return sum;
});

// Alternative 1: Using reduce (typically slower due to function call overhead)
suite.add('reduce', () => {
  const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  return arr.reduce((acc, val) => acc + val, 0);
});

// Alternative 2: for-of loop (similar performance to for loop)
suite.add('for-of-loop', () => {
  const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  let sum = 0;
  for (const val of arr) {
    sum += val;
  }
  return sum;
});

// Alternative 3: forEach (slower due to function call per element)
suite.add('forEach', () => {
  const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  let sum = 0;
  arr.forEach((val) => {
    sum += val;
  });
  return sum;
});

suite.run();


================================================
FILE: examples/string-replace/node.js
================================================
const { Suite } = require('../../lib');

const suite = new Suite();

const pattern = /[123]/g
const replacements = { 1: 'a', 2: 'b', 3: 'c' }

const subject = '123123123123123123123123123123123123123123123123'

suite
  .add('single with matcher', function () {
    const r = subject.replace(pattern, m => replacements[m])
  })
  .add('multiple replaces', function () {
    const r = subject.replace(/1/g, 'a').replace(/2/g, 'b').replace(/3/g, 'c')
  })
  .add('[Managed] single with matcher', function (timer) {
    const assert = require('node:assert');

    const pattern = /[123]/g
    const replacements = { 1: 'a', 2: 'b', 3: 'c' }

    const subject = '123123123123123123123123123123123123123123123123'

    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = subject.replace(pattern, m => replacements[m]);
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .add('[Managed] multiple replaces', function (timer) {
    const assert = require('node:assert');

    const subject = '123123123123123123123123123123123123123123123123'

    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = subject.replace(/1/g, 'a').replace(/2/g, 'b').replace(/3/g, 'c');
    }
    timer.end(timer.count);
    assert.ok(r);
  })
  .run()


================================================
FILE: examples/string-replace/node.js.log
================================================
single with matcher x 752,020 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(1.32us ... 1.34us) p75=1.33us p99=1.34us
multiple replaces x 642,602 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(1.54us ... 1.55us) p75=1.55us p99=1.55us
[Managed] single with matcher x 774,049 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(1.28us ... 1.30us) p75=1.29us p99=1.30us
[Managed] multiple replaces x 645,958 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(1.54us ... 1.58us) p75=1.55us p99=1.58us
----------------------------------------------------------------------------
single with matcher x 748,221 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(1.33us ... 1.35us) p75=1.35us p99=1.35us
multiple replaces x 639,390 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(1.55us ... 1.57us) p75=1.56us p99=1.57us
[Managed] single with matcher x 765,396 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(1.30us ... 1.32us) p75=1.31us p99=1.32us
[Managed] multiple replaces x 644,492 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(1.55us ... 1.55us) p75=1.55us p99=1.55us
----------------------------------------------------------------------------
single with matcher x 742,699 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(1.32us ... 1.34us) p75=1.33us p99=1.34us
multiple replaces x 640,209 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(1.54us ... 1.57us) p75=1.56us p99=1.57us
[Managed] single with matcher x 774,824 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(1.29us ... 1.30us) p75=1.29us p99=1.30us
[Managed] multiple replaces x 642,062 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(1.54us ... 1.60us) p75=1.57us p99=1.60us
----------------------------------------------------------------------------


================================================
FILE: examples/string-searching/node.js
================================================
const { Suite } = require('../../lib');

const suite = new Suite();

const text = 'text/html,application/xhtml+xml,application/xml;application/json;q=0.9,image/avif,image/webp,*/*;q=0.8'
const regex = /application\/json/

suite
  .add('Using includes', function () {
    const r = text.includes('application/json')
  })
  .add('Using indexof', function () {
    const r = text.indexOf('application/json') !== -1
  })
  .add('Using cached RegExp.test', function () {
    const r = regex.test(text)
  })
  .add('[Managed] Using includes', function (timer) {
    const assert = require('node:assert');

    const text = 'text/html,application/xhtml+xml,application/xml;application/json;q=0.9,image/avif,image/webp,*/*;q=0.8';

    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = text.includes('application/json');
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .add('[Managed] Using indexof', function (timer) {
    const assert = require('node:assert');

    const text = 'text/html,application/xhtml+xml,application/xml;application/json;q=0.9,image/avif,image/webp,*/*;q=0.8';

    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = text.indexOf('application/json') !== -1;
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .add('[Managed] Using cached RegExp.test', function (timer) {
    const assert = require('node:assert');

    const regex = /application\/json/;
    const text = 'text/html,application/xhtml+xml,application/xml;application/json;q=0.9,image/avif,image/webp,*/*;q=0.8';

    let r;

    timer.start();
    for (let i = 0; i < timer.count; i++) {
      r = regex.test(text);
    }
    timer.end(timer.count);

    assert.ok(r);
  })
  .run();


================================================
FILE: examples/string-searching/node.js.log
================================================
Using includes x 131,465,887 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(7.53ns ... 7.61ns) p75=7.59ns p99=7.61ns
Using indexof x 130,628,503 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(7.62ns ... 7.67ns) p75=7.65ns p99=7.67ns
Using cached RegExp.test x 19,855,444 ops/sec (9 runs sampled) v8-never-optimize=true min..max=(50.32ns ... 50.38ns) p75=50.37ns p99=50.38ns
[Managed] Using includes x 2,259,413,999 ops/sec (17 runs sampled) v8-never-optimize=true min..max=(0.50ns ... 0.50ns) p75=0.50ns p99=0.50ns
[Managed] Using indexof x 2,262,452,858 ops/sec (17 runs sampled) v8-never-optimize=true min..max=(0.50ns ... 0.50ns) p75=0.50ns p99=0.50ns
[Managed] Using cached RegExp.test x 24,771,962 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(40.11ns ... 40.43ns) p75=40.37ns p99=40.43ns
----------------------------------------------------------------------------
Using includes x 131,872,369 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(7.53ns ... 7.70ns) p75=7.63ns p99=7.70ns
Using indexof x 131,276,601 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(7.56ns ... 7.67ns) p75=7.59ns p99=7.67ns
Using cached RegExp.test x 19,684,556 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(50.51ns ... 51.39ns) p75=50.75ns p99=51.39ns
[Managed] Using includes x 2,279,136,862 ops/sec (17 runs sampled) v8-never-optimize=true min..max=(0.50ns ... 0.50ns) p75=0.50ns p99=0.50ns
[Managed] Using indexof x 2,259,877,221 ops/sec (17 runs sampled) v8-never-optimize=true min..max=(0.50ns ... 0.50ns) p75=0.50ns p99=0.50ns
[Managed] Using cached RegExp.test x 24,313,713 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(40.92ns ... 41.19ns) p75=41.19ns p99=41.19ns
----------------------------------------------------------------------------
Using includes x 132,464,212 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(7.52ns ... 7.56ns) p75=7.56ns p99=7.56ns
Using indexof x 132,177,669 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(7.52ns ... 7.67ns) p75=7.60ns p99=7.67ns
Using cached RegExp.test x 19,854,899 ops/sec (8 runs sampled) v8-never-optimize=true min..max=(50.28ns ... 50.36ns) p75=50.32ns p99=50.36ns
[Managed] Using includes x 2,259,179,846 ops/sec (17 runs sampled) v8-never-optimize=true min..max=(0.50ns ... 0.50ns) p75=0.50ns p99=0.50ns
[Managed] Using indexof x 2,181,069,609 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(0.50ns ... 0.50ns) p75=0.50ns p99=0.50ns
[Managed] Using cached RegExp.test x 23,308,043 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(40.23ns ... 41.24ns) p75=40.69ns p99=41.24ns
----------------------------------------------------------------------------


================================================
FILE: examples/time-mode.js
================================================
const { Suite } = require('../lib');

const timeSuite = new Suite({
    benchmarkMode: 'time' // Set mode for the entire suite
});

const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

timeSuite.add('Async Delay 100ms (time)', async () => {
    await delay(100);
});

timeSuite.add('Sync Busy Wait 50ms (time)', () => {
    const start = Date.now();
    while (Date.now() - start < 50);
});

timeSuite.add('Quick Sync Op with 5 repeats (time)', { repeatSuite: 5 }, () => {
    // This will run exactly once per repeat (5 times total)
    // and report the average time
    let x = 1 + 1;
});


(async () => {
    console.log('\nRunning benchmark suite in TIME mode...');
    await timeSuite.run();
})();


================================================
FILE: examples/worker-threads/node.js
================================================
const { Suite } = require('../../lib');

const suite = new Suite({
  useWorkers: true,
});

suite
  .add('Using import without node: prefix', function () {
    return import('fs');
  })
  .add('Using import with node: prefix', function () {
    return import('node:fs');
  })
	.add('async test', async function (timer) {
		timer.start();
		let i = 0;
		while (i++ < timer.count) {
			await import("node:fs");
		}
		timer.end(timer.count);
	})
  .run();


================================================
FILE: index.d.ts
================================================
// Type definitions for bench-node

/// <reference types="node" />
import type { Histogram } from "node:perf_hooks";

export declare namespace BenchNode {
	class Benchmark {
		name: string;
		fn: any;
		minTime: number;
		maxTime: number;
		plugins: Plugin[];
		repeatSuite: number;
		minSamples: number;
		baseline: boolean;

		constructor(
			name: string,
			fn: any,
			minTime: number,
			maxTime: number,
			plugins: Plugin[],
			repeatSuite: number,
			minSamples: number,
			baseline?: boolean,
		);

		serializeBenchmark(): void;
	}

	interface PluginHookVarNames {
		awaitOrEmpty: string;
		bench: string;
		context: string;
		timer: string;
		managed: boolean;
	}

	interface BenchmarkResult {
		name: string;
		opsSec?: number; // Only in 'ops' mode
		opsSecPerRun?: number[]; // Useful when repeatSuite > 1
		totalTime?: number; // Total execution time in seconds (Only in 'time' mode)
		iterations: number;
		histogram: Histogram;
		plugins?: Record<string, any>; // Object with plugin results
	}

	type ReporterFunction = (results: BenchmarkResult[]) => void;

	interface ReporterOptions {
		printHeader?: boolean;
		labelWidth?: number;
		ttest?: boolean; // Passed automatically when Suite ttest option is enabled
		alpha?: number; // Significance level for t-test (default: 0.05)
	}

	interface SuiteOptions {
		reporter?: ReporterFunction | false | null;
		benchmarkMode?: "ops" | "time";
		useWorkers?: boolean;
		plugins?: Plugin[];
		minSamples?: number; // Minimum number of samples per round for all benchmarks
		repeatSuite?: number; // Number of times to repeat each benchmark (default: 1, or 30 when ttest is enabled)
		ttest?: boolean; // Enable t-test mode for statistical significance (auto-sets repeatSuite=30)
		reporterOptions?: ReporterOptions;
		detectDeadCodeElimination?: boolean; // Enable DCE detection, default: false
		dceThreshold?: number; // DCE detection threshold multiplier, default: 10
	}

	interface BenchmarkOptions {
		minTime?: number; // Minimum duration in seconds
		maxTime?: number; // Maximum duration in seconds
		repeatSuite?: number; // Number of times to repeat benchmark
		minSamples?: number; // Minimum number of samples per round
	}

	type BenchmarkFunction = (timer?: {
		start: () => void;
		end: (iterations?: number) => void;
		count: number;
	}) => void | Promise<void>;

	type OnCompleteBenchmarkResult = [
		duration: number,
		count: number,
		context: Record<string, any>,
	];
	type PluginResult = {
		type: string;
		[key: string]: any;
	};

	interface Plugin {
		isSupported?(): boolean;
		beforeClockTemplate?(varNames: PluginHookVarNames): string[];
		afterClockTemplate?(varNames: PluginHookVarNames): string[];
		onCompleteBenchmark?(
			result: OnCompleteBenchmarkResult,
			bench: Benchmark,
		): void;
		toString?(): string;
		getReport?(benchmarkName: string): string;
		getResult?(benchmarkName: string): PluginResult;
		reset?(): void;
	}

	class Suite {
		constructor(options?: SuiteOptions);
		add(name: string, fn: BenchmarkFunction): this;
		add(name: string, options: BenchmarkOptions, fn: BenchmarkFunction): this;
		run(): Promise<BenchmarkResult[]>;
	}

	class V8NeverOptimizePlugin implements Plugin {
		isSupported(): boolean;
		beforeClockTemplate(varNames: PluginHookVarNames): string[];
		toString(): string;
		getReport(benchmarkName: string): string;
	}

	class V8GetOptimizationStatus implements Plugin {
		isSupported(): boolean;
		afterClockTemplate(varNames: PluginHookVarNames): string[];
		onCompleteBenchmark(result: OnCompleteBenchmarkResult): void;
		toString(): string;
		getReport(benchmarkName: string): string;
		getResult?(benchmarkName: string): PluginResult;
	}

	class V8OptimizeOnNextCallPlugin implements Plugin {
		isSupported(): boolean;
		beforeClockTemplate(varNames: PluginHookVarNames): string[];
		toString(): string;
		getReport(): string;
	}

	class MemoryPlugin implements Plugin {
		isSupported(): boolean;
		beforeClockTemplate(varNames: PluginHookVarNames): string[];
		afterClockTemplate(varNames: PluginHookVarNames): string[];
		onCompleteBenchmark(result: OnCompleteBenchmarkResult): void;
		getReport(benchmarkName: string): string;
		getResult(benchmarkName: string): PluginResult;
		toString(): string;
	}

	class DeadCodeEliminationDetectionPlugin implements Plugin {
		constructor(options?: { threshold?: number });
		isSupported(): boolean;
		setBaseline(timePerOp: number): void;
		onCompleteBenchmark(
			result: OnCompleteBenchmarkResult,
			bench: Benchmark,
		): void;
		getWarning(
			benchmarkName: string,
		): { timePerOp: number; baselineTime: number; ratio: number } | undefined;
		getAllWarnings(): Array<{
			name: string;
			timePerOp: number;
			baselineTime: number;
			ratio: number;
		}>;
		hasWarning(benchmarkName: string): boolean;
		emitWarnings(): void;
		toString(): string;
		reset(): void;
	}
}

export declare const textReport: BenchNode.ReporterFunction;
export declare const chartReport: BenchNode.ReporterFunction;
export declare const prettyReport: BenchNode.ReporterFunction;
export declare const htmlReport: BenchNode.ReporterFunction;
export declare const jsonReport: BenchNode.ReporterFunction;
export declare const csvReport: BenchNode.ReporterFunction;

export declare class Suite extends BenchNode.Suite {}
export declare class V8NeverOptimizePlugin extends BenchNode.V8NeverOptimizePlugin {}
export declare class V8GetOptimizationStatus extends BenchNode.V8GetOptimizationStatus {}
export declare class V8OptimizeOnNextCallPlugin extends BenchNode.V8OptimizeOnNextCallPlugin {}
export declare class MemoryPlugin extends BenchNode.MemoryPlugin {}

// Statistical T-Test utilities
export declare namespace TTest {
	interface WelchTTestResult {
		tStatistic: number;
		degreesOfFreedom: number;
		pValue: number;
		significant: boolean;
		mean1: number;
		mean2: number;
		variance1: number;
		variance2: number;
	}

	interface CompareBenchmarksResult {
		significant: boolean;
		pValue: number;
		confidence: string;
		stars: "***" | "**" | "*" | "";
		difference: "faster" | "slower" | "same";
		tStatistic: number;
		degreesOfFreedom: number;
	}
}

/**
 * Returns significance stars based on p-value thresholds.
 * @param pValue - The p-value from statistical test
 * @returns Stars indicating significance level ('***', '**', '*', or '')
 */
export declare function getSignificanceStars(
	pValue: number,
): "***" | "**" | "*" | "";

/**
 * Performs Welch's t-test for two independent samples.
 * Does not assume equal variances between the samples.
 * @param sample1 - First sample array
 * @param sample2 - Second sample array
 * @returns Test results including t-statistic, degrees of freedom, p-value, and significance
 */
export declare function welchTTest(
	sample1: number[],
	sample2: number[],
): TTest.WelchTTestResult;

/**
 * Determines if two benchmark results are statistically different
 * using Welch's t-test at a given significance level.
 * @param sample1 - Sample data from first benchmark
 * @param sample2 - Sample data from second benchmark
 * @param alpha - Significance level (default 0.05 for 95% confidence)
 * @returns Comparison result with significance info
 */
export declare function compareBenchmarks(
	sample1: number[],
	sample2: number[],
	alpha?: number,
): TTest.CompareBenchmarksResult;

export declare class DeadCodeEliminationDetectionPlugin extends BenchNode.DeadCodeEliminationDetectionPlugin {}


================================================
FILE: lib/clock.js
================================================
const { debuglog } = require("node:util");
const { validateNumber } = require("./validators");

const debugBench = debuglog("benchmark");

const kUnmanagedTimerResult = Symbol("kUnmanagedTimerResult");

// If the smallest time measurement is 1ns
// the minimum resolution of this timer is 0.5
const MIN_RESOLUTION = 0.5;

class Timer {
	constructor() {
		this.now = process.hrtime.bigint;
	}

	get scale() {
		return 1e9;
	}

	get resolution() {
		return 1 / 1e9;
	}

	/**
	 * @param {number} timeInNs
	 * @returns {string}
	 */
	format(timeInNs) {
		validateNumber(timeInNs, "timeInNs", 0);

		if (timeInNs > 1e9) {
			return `${(timeInNs / 1e9).toFixed(2)}s`;
		}

		if (timeInNs > 1e6) {
			return `${(timeInNs / 1e6).toFixed(2)}ms`;
		}

		if (timeInNs > 1e3) {
			return `${(timeInNs / 1e3).toFixed(2)}us`;
		}

		return `${(timeInNs).toFixed(2)}ns`;
	}
}

const timer = new Timer();

class ManagedTimer {
	startTime;
	endTime;
	iterations;
	recommendedCount;

	/**
	 * @param {number} recommendedCount
	 */
	constructor(recommendedCount) {
		this.recommendedCount = recommendedCount;
	}

	/**
	 * Returns the recommended value to be used to benchmark your code
	 * @returns {number}
	 */
	get count() {
		return this.recommendedCount;
	}

	/**
	 * Starts the timer
	 */
	start() {
		this.startTime = timer.now();
	}

	/**
	 * Stops the timer
	 * @param {number} [iterations=1] The amount of iterations that run
	 */
	end(iterations = 1) {
		this.endTime = timer.now();
		validateNumber(iterations, "iterations", 1);
		this.iterations = iterations;
	}

	[kUnmanagedTimerResult](context) {
		if (this.startTime === undefined)
			throw new Error("You forgot to call .start()");

		if (this.endTime === undefined)
			throw new Error("You forgot to call .end(count)");

		return [Number(this.endTime - this.startTime), this.iterations, context];
	}
}

function createRunUnmanagedBenchmark(bench, awaitOrEmpty) {
	const varNames = {
		awaitOrEmpty,
		timer: "timer",
		context: "context",
		bench: "bench",
		managed: false,
	};

	let code = `
let i = 0;
let ${varNames.context} = {};
`;

	let benchFnCall = `${awaitOrEmpty}${varNames.bench}.fn()`;
	const wrapFunctions = [];
	for (const p of bench.plugins) {
		if (typeof p.beforeClockTemplate === "function") {
			const [newCode, functionToCall] = p.beforeClockTemplate(varNames);
			code += newCode;
			if (functionToCall) {
				wrapFunctions.push(functionToCall);
			}
		}
	}
	benchFnCall = wrapFunctions.reduce((prev, n) => {
		return `${n}(${prev})`;
	}, benchFnCall);

	code += `
const startedAt = ${varNames.timer}.now();

for (; i < count; i++)
  ${benchFnCall};

const duration = Number(${varNames.timer}.now() - startedAt);
`;

	for (const p of bench.plugins) {
		if (typeof p.afterClockTemplate === "function") {
			const [newCode] = p.afterClockTemplate(varNames);
			code += newCode;
		}
	}

	code += `return [duration, count, ${varNames.context}];`;
	return code;
}

function createRunManagedBenchmark(bench, awaitOrEmpty) {
	const varNames = {
		awaitOrEmpty,
		timer: "timer",
		context: "context",
		bench: "bench",
		managed: true,
	};

	let code = `
let i = 0;
let ${varNames.context} = {};
`;

	let benchFnCall = `${awaitOrEmpty}${varNames.bench}.fn(${varNames.timer})`;
	const wrapFunctions = [];
	for (const p of bench.plugins) {
		if (typeof p.beforeClockTemplate === "function") {
			const [newCode, functionToCall] = p.beforeClockTemplate(varNames);
			code += newCode;
			if (functionToCall) {
				wrapFunctions.push(functionToCall);
			}
		}
	}
	benchFnCall = wrapFunctions.reduce((prev, n) => {
		return `${n}(${prev})`;
	}, benchFnCall);

	code += `
${benchFnCall};
const result = ${varNames.timer}[kUnmanagedTimerResult](${varNames.context});
`;
	for (const p of bench.plugins) {
		if (typeof p.afterClockTemplate === "function") {
			const [newCode] = p.afterClockTemplate(varNames);
			code += newCode;
		}
	}

	code += "return result;";
	return code;
}

const AsyncFunction = (async () => {}).constructor;
const SyncFunction = (() => {}).constructor;

function createFnString(bench) {
	const { isAsync, hasArg } = bench;

	const compiledFnStringFactory = hasArg
		? createRunManagedBenchmark
		: createRunUnmanagedBenchmark;
	const compiledFnString = compiledFnStringFactory(
		bench,
		isAsync ? "await " : "",
	);
	return compiledFnString;
}

function createRunner(bench, recommendedCount) {
	const { isAsync, hasArg } = bench;
	const compiledFnString = bench.fnStr;

	const createFnPrototype = isAsync ? AsyncFunction : SyncFunction;
	const compiledFn = createFnPrototype(
		"bench",
		"timer",
		"count",
		"kUnmanagedTimerResult",
		compiledFnString,
	);
	const selectedTimer = hasArg ? new ManagedTimer(recommendedCount) : timer;
	const runner = compiledFn.bind(
		globalThis,
		bench,
		selectedTimer,
		recommendedCount,
		kUnmanagedTimerResult,
	);
	debugBench(`Compiled Code: ${compiledFnString}`);
	debugBench(
		`Created compiled benchmark, hasArg=${hasArg}, isAsync=${isAsync}, recommendedCount=${recommendedCount}`,
	);

	return runner;
}

/**
 * Executes a benchmark and returns the time taken and number of iterations
 * @param {import('./index').Benchmark} bench - The benchmark to execute
 * @param {number} recommendedCount - The recommended number of iterations
 * @param {Object} [options] - Additional options
 * @param {boolean} [options.timeMode=false] - If true, runs the benchmark exactly once
 * @returns {Promise<[number, number]>} - Returns [duration, iterations]
 */
async function clockBenchmark(bench, recommendedCount, options = {}) {
	const runner = createRunner(bench, recommendedCount);
	const result = await runner();

	// Just to avoid issues with empty fn
	result[0] = Math.max(MIN_RESOLUTION, result[0]);

	for (const p of bench.plugins) {
		if (typeof p.onCompleteBenchmark === "function") {
			// TODO: this won't work when useWorkers=true
			p.onCompleteBenchmark(result, bench);
		}
	}

	debugBench(
		`Took ${timer.format(result[0])} to execute ${result[1]} iterations${options.timeMode ? " (time mode)" : ""}`,
	);
	return result;
}

module.exports = {
	clockBenchmark,
	createFnString,
	timer,
	MIN_RESOLUTION,
	debugBench,
};


================================================
FILE: lib/histogram.js
================================================
const { validateNumber } = require("./validators");

/**
 * A class that calculates and maintains statistical measurements for a set of numeric samples.
 * Handles outlier removal, and calculates various statistical measures like mean, standard deviation,
 * coefficient of variation, and percentiles.
 */
class StatisticalHistogram {
	all = [];
	min;
	max;
	mean;
	cv;
	stddev;
	finished = false;

	/**
	 * @returns {number[]}
	 */
	get samples() {
		return this.all.slice();
	}

	/**
	 * @param {number} percentile
	 * @returns {number}
	 */
	percentile(percentile) {
		validateNumber(percentile, "percentile");

		if (Number.isNaN(percentile) || percentile < 0 || percentile > 100)
			throw new Error(
				"Invalid percentile value. Must be a number between 0 and 100.",
			);

		if (this.all.length === 0) return 0;

		if (percentile === 0) return this.all[0];

		return this.all[Math.ceil(this.all.length * (percentile / 100)) - 1];
	}

	/**
	 * @param {number} value
	 */
	record(value) {
		validateNumber(value, "value", 0);

		this.all.push(value);
	}

	finish() {
		if (this.finished) return;

		this.finished = true;
		this.removeOutliers();

		this.calculateMinMax();
		this.calculateMean();
		this.calculateStd();
		this.calculateCv();
	}

	/**
	 * References:
	 * - https://gist.github.com/rmeissn/f5b42fb3e1386a46f60304a57b6d215a
	 * - https://en.wikipedia.org/wiki/Interquartile_range
	 */
	removeOutliers() {
		this.all.sort((a, b) => a - b);

		const size = this.all.length;

		if (size < 4) return;

		let q1;
		let q3;

		if (((size - 1) / 4) % 1 === 0 || (size / 4) % 1 === 0) {
			q1 =
				(1 / 2) *
				(this.all[Math.floor(size / 4) - 1] + this.all[Math.floor(size / 4)]);
			q3 =
				(1 / 2) *
				(this.all[Math.ceil((size * 3) / 4) - 1] +
					this.all[Math.ceil((size * 3) / 4)]);
		} else {
			q1 = this.all[Math.floor(size / 4)];
			q3 = this.all[Math.floor((size * 3) / 4)];
		}

		const iqr = q3 - q1;
		const minValue = q1 - iqr * 1.5;
		const maxValue = q3 + iqr * 1.5;

		this.all = this.all.filter(
			(value) => value <= maxValue && value >= minValue,
		);
	}

	calculateMinMax() {
		this.min = Number.POSITIVE_INFINITY;
		this.max = Number.NEGATIVE_INFINITY;

		for (let i = 0; i < this.all.length; i++) {
			this.min = Math.min(this.all[i], this.min);
			this.max = Math.max(this.all[i], this.max);
		}
	}

	calculateMean() {
		if (this.all.length === 0) {
			this.mean = 0;
			return;
		}

		if (this.all.length === 1) {
			this.mean = this.all[0];
			return;
		}

		this.mean =
			this.all.reduce(
				(acc, value) => Math.min(Number.MAX_SAFE_INTEGER, acc + value),
				0,
			) / this.all.length;
	}

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

	/**
	 * References:
	 * - https://en.wikipedia.org/wiki/Coefficient_of_variation
	 * - https://github.com/google/benchmark/blob/159eb2d0ffb85b86e00ec1f983d72e72009ec387/src/statistics.ccL81-L88
	 */
	calculateCv() {
		if (this.all.length < 2 || this.mean === 0) {
			this.cv = 0;
			return;
		}

		this.cv = (this.stddev / this.mean) * 100;
	}
}

module.exports = {
	StatisticalHistogram,
};


================================================
FILE: lib/index.js
================================================
const { Worker } = require("node:worker_threads");
const { types } = require("node:util");
const path = require("node:path");

const {
	textReport,
	chartReport,
	htmlReport,
	jsonReport,
	csvReport,
	prettyReport,
} = require("./report");
const {
	getInitialIterations,
	runBenchmark,
	runWarmup,
} = require("./lifecycle");
const { debugBench, timer, createFnString } = require("./clock");
const {
	validatePlugins,
	V8NeverOptimizePlugin,
	V8GetOptimizationStatus,
	V8OptimizeOnNextCallPlugin,
	MemoryPlugin,
	DeadCodeEliminationDetectionPlugin,
} = require("./plugins");
const {
	validateFunction,
	validateNumber,
	validateObject,
	validateString,
	validateArray,
	validateBenchmarkMode,
	validateBoolean,
} = require("./validators");
const {
	welchTTest,
	compareBenchmarks,
	getSignificanceStars,
} = require("./utils/ttest");

const getFunctionBody = (string) =>
	string.substring(string.indexOf("{") + 1, string.lastIndexOf("}"));

class Benchmark {
	name = "Benchmark";
	fn;
	minTime;
	maxTime;
	plugins;
	repeatSuite;
	minSamples;
	baseline = false;

	constructor(
		name,
		fn,
		minTime,
		maxTime,
		plugins,
		repeatSuite,
		minSamples,
		baseline = false,
	) {
		this.name = name;
		this.fn = fn;
		this.minTime = minTime;
		this.maxTime = maxTime;
		this.plugins = plugins;
		this.repeatSuite = repeatSuite;
		this.minSamples = minSamples;
		this.baseline = baseline;

		this.hasArg = this.fn.length >= 1;
		if (this.fn.length > 1) {
			process.emitWarning(
				`The benchmark "${this.name}" function should not have more than 1 argument.`,
			);
		}

		this.isAsync = types.isAsyncFunction(this.fn);

		this.fnStr = createFnString(this);
	}

	serializeBenchmark() {
		// Regular functions can't be passed to worker.postMessage
		// So we pass the string and deserialize fnStr into a new Function
		// on worker
		this.fn = getFunctionBody(this.fn.toString());
	}
}

const defaultBenchOptions = {
	// 0.05s - Arbitrary number used in some benchmark tools
	minTime: 0.05,
	// 0.5s - Arbitrary number used in some benchmark tools
	maxTime: 0.5,
	// Number of times the benchmark will be repeated
	repeatSuite: 1,
	// Number minimum of samples the each round
	minSamples: 10,
};

// Minimum repeatSuite runs required for reliable t-test results
const MIN_REPEAT_FOR_TTEST = 30;

function throwIfNoNativesSyntax() {
	if (process.execArgv.includes("--allow-natives-syntax") === false) {
		throw new Error(
			"bench-node module must be run with --allow-natives-syntax argument",
		);
	}
}

class Suite {
	#benchmarks;
	#reporter;
	#plugins;
	#useWorkers;
	#benchmarkMode;
	#reporterOptions;
	#minSamples;
	#repeatSuite;
	#ttest;
	#dceDetector;

	constructor(options = {}) {
		this.#benchmarks = [];
		validateObject(options, "options");

		if (options?.reporter !== undefined) {
			if (options?.reporter !== false && options?.reporter !== null) {
				validateFunction(options.reporter, "reporter");
			}
			this.#reporter = options.reporter;
		} else if (options?.pretty === true) {
			this.#reporter = prettyReport;
		} else {
			this.#reporter = textReport;
		}

		this.#useWorkers = options.useWorkers || false;

		// DCE detection is opt-in to avoid breaking changes
		const dceEnabled = options.detectDeadCodeElimination === true;
		if (dceEnabled) {
			this.#dceDetector = new DeadCodeEliminationDetectionPlugin(
				options.dceThreshold ? { threshold: options.dceThreshold } : {},
			);
		}

		// Plugin setup: If DCE detection is enabled, default to no plugins (allow optimization)
		// Otherwise, use V8NeverOptimizePlugin as the default
		if (options?.plugins) {
			validateArray(options.plugins, "plugin");
			validatePlugins(options.plugins);
			this.#plugins = options.plugins;
		} else if (dceEnabled) {
			// DCE detection requires optimization to be enabled, so no default plugins
			this.#plugins = [];
		} else {
			// Default behavior - use V8NeverOptimizePlugin
			this.#plugins = [new V8NeverOptimizePlugin()];
		}

		this.#benchmarkMode = options.benchmarkMode || "ops";
		validateBenchmarkMode(this.#benchmarkMode, "options.benchmarkMode");

		this.#reporterOptions = options.reporterOptions || {
			printHeader: true,
		};

		if (options.ttest !== undefined) {
			validateBoolean(options.ttest, "options.ttest");
		}
		this.#ttest = options.ttest ?? false;

		let repeatSuite = defaultBenchOptions.repeatSuite;
		if (options.repeatSuite !== undefined) {
			validateNumber(options.repeatSuite, "options.repeatSuite", 1);
			repeatSuite = options.repeatSuite;
		} else if (this.#ttest) {
			repeatSuite = MIN_REPEAT_FOR_TTEST;
		}
		this.#repeatSuite = repeatSuite;

		if (this.#ttest) {
			this.#reporterOptions.ttest = true;
		}
		let minSamples = defaultBenchOptions.minSamples;
		if (options.minSamples !== undefined) {
			validateNumber(options.minSamples, "options.minSamples", 1);
			minSamples = options.minSamples;
		}

		this.#minSamples = minSamples;
	}

	add(name, options, fn) {
		validateString(name, "name");
		if (typeof options === "function") {
			fn = options;
			options = {
				...defaultBenchOptions,
				minSamples: this.#minSamples,
				repeatSuite: this.#repeatSuite,
			};
		} else {
			validateObject(options, "options");
			options = {
				...defaultBenchOptions,
				minSamples: this.#minSamples,
				repeatSuite: this.#repeatSuite,
				...options,
			};
			// Enforce strict minimum (> 1e-6s). Using EPSILON to make boundary exclusive.
			validateNumber(
				options.minTime,
				"options.minTime",
				timer.resolution * 1e3 + Number.EPSILON,
			);
			validateNumber(options.maxTime, "options.maxTime", options.minTime);
			validateNumber(options.repeatSuite, "options.repeatSuite", 1);
			validateNumber(options.minSamples, "options.minSamples", 1);
		}
		validateFunction(fn, "fn");

		const { baseline = false } = options || {};
		if (baseline && this.#benchmarks.some((b) => b.baseline)) {
			throw new Error("There is already a baseline benchmark");
		}

		const benchmark = new Benchmark(
			name,
			fn,
			options.minTime,
			options.maxTime,
			this.#plugins,
			options.repeatSuite,
			options.minSamples,
			baseline,
		);
		this.#benchmarks.push(benchmark);
		return this;
	}

	async run() {
		throwIfNoNativesSyntax();
		const results = new Array(this.#benchmarks.length);

		// Measure baseline for DCE detection (only in ops mode, not in worker mode)
		if (
			this.#dceDetector &&
			!this.#useWorkers &&
			this.#benchmarkMode === "ops"
		) {
			await this.#measureBaseline();
		}

		// It doesn't make sense to warmup a fresh new instance of Worker.
		// TODO: Should this be folded into the main loop?
		if (!this.#useWorkers) {
			// This is required to avoid variance on first benchmark run
			for (let i = 0; i < this.#benchmarks.length; ++i) {
				const benchmark = this.#benchmarks[i];
				debugBench(
					`Warmup ${benchmark.name} with minTime=${benchmark.minTime}, maxTime=${benchmark.maxTime}`,
				);
				const initialIteration = await getInitialIterations(benchmark);
				await runWarmup(benchmark, initialIteration, {
					minTime: 0.005,
					maxTime: 0.05,
				});
			}
		}

		for (let i = 0; i < this.#benchmarks.length; ++i) {
			const benchmark = this.#benchmarks[i];

			// Add DCE detector to benchmark plugins if enabled
			if (this.#dceDetector && this.#benchmarkMode === "ops") {
				const originalPlugins = benchmark.plugins;
				benchmark.plugins = [...benchmark.plugins, this.#dceDetector];
				// Regenerate function string with new plugins
				benchmark.fnStr = createFnString(benchmark);
			}

			// Warmup is calculated to reduce noise/bias on the results
			const initialIterations = await getInitialIterations(benchmark);
			debugBench(
				`Starting ${benchmark.name} with mode=${this.#benchmarkMode}, minTime=${benchmark.minTime}, maxTime=${benchmark.maxTime}, repeatSuite=${benchmark.repeatSuite}, minSamples=${benchmark.minSamples}`,
			);

			let result;
			if (this.#useWorkers) {
				if (this.#benchmarkMode === "time") {
					console.warn(
						"Warning: Worker mode currently doesn't fully support 'time' benchmarkMode.",
					);
				}
				result = await this.runWorkerBenchmark(benchmark, initialIterations);
			} else {
				result = await runBenchmark(
					benchmark,
					initialIterations,
					this.#benchmarkMode,
					benchmark.repeatSuite,
					benchmark.minSamples,
				);
			}
			results[i] = result;
		}

		if (this.#reporter) {
			this.#reporter(results, this.#reporterOptions);
		}

		// Emit DCE warnings after reporting
		if (this.#dceDetector) {
			this.#dceDetector.emitWarnings();
		}

		return results;
	}

	async #measureBaseline() {
		debugBench("Measuring baseline for DCE detection...");

		// Create a minimal baseline benchmark (empty function)
		const baselineBench = new Benchmark(
			"__baseline__",
			() => {},
			0.01, // minTime
			0.05, // maxTime
			this.#plugins,
			1, // repeatSuite
			10, // minSamples
		);

		const initialIterations = await getInitialIterations(baselineBench);
		const result = await runBenchmark(
			baselineBench,
			initialIterations,
			"ops",
			1,
			10,
		);

		const baselineTimePerOp = (1 / result.opsSec) * 1e9; // Convert to ns
		debugBench(`DCE baseline: ${timer.format(baselineTimePerOp)}/iter`);

		this.#dceDetector.setBaseline(baselineTimePerOp);
	}

	async runWorkerBenchmark(benchmark, initialIterations) {
		return new Promise((resolve, reject) => {
			const workerPath = path.resolve(__dirname, "./worker-runner.js");
			const worker = new Worker(workerPath);

			benchmark.serializeBenchmark();
			worker.postMessage({
				benchmark,
				initialIterations,
				benchmarkMode: this.#benchmarkMode, // Pass suite mode
				repeatSuite: benchmark.repeatSuite,
				minSamples: benchmark.minSamples,
			});

			worker.on("message", (result) => {
				resolve(result);
				worker.terminate();
			});
			worker.on("error", (error) => {
				reject(error);
				worker.terminate();
			});
			worker.on("exit", (code) => {
				if (code !== 0)
					reject(new Error(`Worker stopped with exit code ${code}`));
			});
		});
	}
}

module.exports = {
	Suite,
	V8NeverOptimizePlugin,
	V8GetOptimizationStatus,
	V8OptimizeOnNextCallPlugin,
	MemoryPlugin,
	DeadCodeEliminationDetectionPlugin,
	chartReport,
	textReport,
	prettyReport,
	htmlReport,
	jsonReport,
	csvReport,
	// Statistical utilities
	welchTTest,
	compareBenchmarks,
	getSignificanceStars,
};


================================================
FILE: lib/lifecycle.js
================================================
const {
	clockBenchmark,
	debugBench,
	MIN_RESOLUTION,
	timer,
} = require("./clock");
const { StatisticalHistogram } = require("./histogram");

/**
 * @param {number} durationPerOp The amount of time each operation takes, in timer.scale
 * @param {number} targetTime The amount of time we want the benchmark to execute, in seconds
 * @return {number} - a suggested iteration count >= 1
 */
function getItersForOpDuration(durationPerOp, targetTime) {
	const secondsPerOp = durationPerOp / timer.scale;
	const opsForTargetTime = Math.round(targetTime / secondsPerOp);

	return Math.min(Number.MAX_SAFE_INTEGER, Math.max(1, opsForTargetTime));
}

function parsePluginsResult(plugins, name) {
	const result = [];
	for (const p of plugins) {
		result.push({
			name: p.toString(),
			result: p.getResult?.(name) ?? "enabled",
			report: p.getReport?.(name) ?? "",
		});
	}
	return result;
}

/**
 * Calculates and returns the initial number of iterations for a benchmark
 * @param {import('./index').Benchmark} bench - The benchmark object to be executed
 * @returns {Promise<number>} The calculated number of initial iterations
 */
async function getInitialIterations(bench) {
	const { 0: duration, 1: realIterations } = await clockBenchmark(bench, 30);

	// Just to avoid issues with empty fn
	const durationPerOp = Math.max(MIN_RESOLUTION, duration / realIterations);
	debugBench(
		`Duration per operation on initial count: ${timer.format(durationPerOp)}`,
	);

	// TODO: is this a correct assumpion?
	if (durationPerOp > bench.maxTime * timer.scale)
		process.emitWarning(
			`The benchmark "${bench.name}" has a duration per operation greater than the maxTime.`,
		);

	return getItersForOpDuration(durationPerOp, bench.minTime);
}

/**
 * Executes the warmup phase of a benchmark
 * @param {import('./index').Benchmark} bench - The benchmark object to be executed
 * @param {number} initialIterations - The initial number of iterations to run
 * @param {Object} options - Warmup options
 * @param {number} [options.minTime] - Minimum time for warmup, in seconds. Defaults to bench.minTime
 * @param {number} [options.maxTime] - Maximum time for warmup, in seconds. Defaults to bench.minTime
 * @returns {Promise<void>}
 */
async function runWarmup(bench, initialIterations, { minTime, maxTime }) {
	minTime = minTime ?? bench.minTime;
	maxTime = maxTime ?? bench.minTime;

	const maxDuration = maxTime * timer.scale;
	const minSamples = 10;

	let iterations = 0;
	let timeSpent = 0;
	let samples = 0;

	while (timeSpent < maxDuration || samples <= minSamples) {
		const { 0: duration, 1: realIterations } = await clockBenchmark(
			bench,
			initialIterations,
		);
		timeSpent += duration;

		iterations += realIterations;
		iterations = Math.min(Number.MAX_SAFE_INTEGER, iterations);

		// Just to avoid issues with empty fn
		const durationPerOp = Math.max(MIN_RESOLUTION, duration / realIterations);
		const remainingTime = Math.max(0, (maxDuration - timeSpent) / timer.scale);
		const targetTime = Math.min(remainingTime, minTime);

		initialIterations = getItersForOpDuration(durationPerOp, targetTime);
		samples++;
	}
}

async function runBenchmarkOnce(
	bench,
	histogram,
	{ initialIterations, maxDuration, minSamples },
	benchmarkMode = "ops",
) {
	let iterations = 0;
	let timeSpent = 0;

	// For time mode, we want to run the benchmark exactly once
	if (benchmarkMode === "time") {
		const { 0: duration, 1: realIterations } = await clockBenchmark(bench, 1);
		timeSpent = duration;
		iterations = realIterations;

		// Record the duration in the histogram
		histogram.record(duration);

		return { iterations, timeSpent };
	}

	// Ops mode - run the sampling loop
	while (timeSpent < maxDuration || histogram.samples.length <= minSamples) {
		const { 0: duration, 1: realIterations } = await clockBenchmark(
			bench,
			initialIterations,
		);
		timeSpent += duration;

		iterations = Math.min(Number.MAX_SAFE_INTEGER, iterations + realIterations);

		// Just to avoid issues with empty fn
		const durationPerOp = Math.max(MIN_RESOLUTION, duration / realIterations);

		histogram.record(durationPerOp);

		const remainingTime = Math.max(0, (maxDuration - timeSpent) / timer.scale);
		const targetTime = Math.min(remainingTime, bench.minTime);
		initialIterations = getItersForOpDuration(durationPerOp, targetTime);
	}

	return { iterations, timeSpent };
}

/**
 * Executes a benchmark with the specified parameters
 * @param {import('./index').Benchmark} bench - The benchmark object to be executed
 * @param {number} initialIterations - The initial number of iterations to run
 * @param {string} benchmarkMode - The benchmark mode ('ops' or 'time')
 * @param {number} repeatSuite - Number of times to repeat the benchmark suite
 * @param {number} minSamples - Minimum number of samples to collect
 * @returns {Promise<Object>} The benchmark results containing operations per second or total time, iterations, histogram data and plugin results
 */
async function runBenchmark(
	bench,
	initialIterations,
	benchmarkMode,
	repeatSuite,
	minSamples,
) {
	const histogram = new StatisticalHistogram();
	const maxDuration = bench.maxTime * timer.scale;

	let totalIterations = 0;
	let totalTimeSpent = 0;
	const opsSecPerRun = [];

	for (let i = 0; i < repeatSuite; ++i) {
		const { iterations, timeSpent } = await runBenchmarkOnce(
			bench,
			histogram,
			{
				initialIterations,
				maxDuration,
				minSamples,
			},
			benchmarkMode,
		);

		const runOpsSec = iterations / (timeSpent / timer.scale);
		opsSecPerRun.push(runOpsSec);

		totalTimeSpent += timeSpent;
		totalIterations += iterations;
	}
	histogram.finish();

	const totalTime = totalTimeSpent / timer.scale; // Convert ns to seconds
	const opsSec = totalIterations / totalTime;

	const sampleData = histogram.samples;

	const result = {
		iterations: totalIterations,
		// StatisticalHistogram is not a serializable object, keep raw ns for min/max
		histogram: {
			samples: sampleData.length,
			min: histogram.min,
			max: histogram.max,
			sampleData,
		},
		name: bench.name,
		plugins: parsePluginsResult(bench.plugins, bench.name),
		baseline: bench.baseline,
	};

	// Add the appropriate metric based on the benchmark mode
	if (benchmarkMode === "time") {
		result.totalTime = totalTime / repeatSuite; // Average time per repeat
		debugBench(
			`${bench.name} completed ${repeatSuite} repeats with average time ${result.totalTime.toFixed(6)} seconds`,
		);
	} else {
		result.opsSec = opsSec;
		result.opsSecPerRun = opsSecPerRun;
		debugBench(
			`${bench.name} completed ${sampleData.length} samples with ${opsSec.toFixed(2)} ops/sec`,
		);
	}

	// since the instance is shared across benchmarks, reset it after use
	for (const plugin of bench.plugins) {
		plugin.reset?.();
	}

	return result;
}

module.exports = {
	getInitialIterations,
	runBenchmark,
	runWarmup,
};


================================================
FILE: lib/plugins/dce-detection.js
================================================
const { timer } = require("../clock");

/**
 * Plugin that detects potential dead code elimination (DCE) in benchmarks.
 * Compares benchmark timings against a baseline (empty function) to identify
 * suspiciously fast benchmarks that may have been optimized away by the JIT.
 *
 * This helps educate users about benchmark quality and potential issues.
 */
class DeadCodeEliminationDetectionPlugin {
	#baselineTimePerOp = null;
	#warnings = new Map();
	#threshold = 10; // Warn if benchmark is less than 10x slower than baseline

	constructor(options = {}) {
		// Allow customizing the threshold
		if (options.threshold !== undefined) {
			this.#threshold = options.threshold;
		}
	}

	isSupported() {
		return true; // Works everywhere
	}

	/**
	 * Stores baseline measurement for comparison
	 * @param {number} timePerOp - Time per operation in nanoseconds
	 */
	setBaseline(timePerOp) {
		this.#baselineTimePerOp = timePerOp;
	}

	/**
	 * Called after each benchmark completes to check for DCE
	 */
	onCompleteBenchmark(result, bench) {
		if (this.#baselineTimePerOp === null) {
			// No baseline yet, skip detection
			return;
		}

		const [duration, iterations] = result;
		const timePerOp = duration / iterations;

		// Check if this benchmark is suspiciously fast compared to baseline
		if (timePerOp < this.#baselineTimePerOp * this.#threshold) {
			this.#warnings.set(bench.name, {
				timePerOp,
				baselineTime: this.#baselineTimePerOp,
				ratio: timePerOp / this.#baselineTimePerOp,
			});
		}
	}

	/**
	 * Get warning for a specific benchmark
	 */
	getWarning(benchmarkName) {
		return this.#warnings.get(benchmarkName);
	}

	/**
	 * Get all warnings
	 */
	getAllWarnings() {
		return Array.from(this.#warnings.entries()).map(([name, data]) => ({
			name,
			...data,
		}));
	}

	/**
	 * Check if a benchmark has a warning
	 */
	hasWarning(benchmarkName) {
		return this.#warnings.has(benchmarkName);
	}

	/**
	 * Emit warnings to console
	 */
	emitWarnings() {
		if (this.#warnings.size === 0) {
			return;
		}

		console.log("\n⚠️  Dead Code Elimination Warnings:");
		console.log(
			"The following benchmarks may have been optimized away by the JIT compiler:\n",
		);

		for (const [name, data] of this.#warnings.entries()) {
			console.log(`  • ${name}`);
			console.log(`    Benchmark: ${timer.format(data.timePerOp)}/iter`);
			console.log(`    Baseline:  ${timer.format(data.baselineTime)}/iter`);
			console.log(`    Ratio:     ${data.ratio.toFixed(2)}x of baseline`);
			console.log(
				"    Suggestion: Ensure the result is used or assign to a variable\n",
			);
		}

		console.log(
			"ℹ️  These benchmarks are running nearly as fast as an empty function,",
		);
		console.log(
			"   which suggests the JIT may have eliminated the actual work.\n",
		);
	}

	toString() {
		return "DeadCodeEliminationDetectionPlugin";
	}

	reset() {
		// Don't reset - we want to accumulate warnings across all benchmarks
		// They will be emitted once at the end of the suite run
	}
}

module.exports = {
	DeadCodeEliminationDetectionPlugin,
};


================================================
FILE: lib/plugins/memory.js
================================================
const { StatisticalHistogram } = require("../histogram");

/**
 * Formats a byte value into a human-readable string with appropriate units (B, Kb, MB, GB)
 * @param {number} bytes - The number of bytes to format
 * @returns {string} Formatted string with appropriate unit suffix
 */
function formatBytes(bytes) {
	if (bytes < 1024) return `${Math.round(bytes)}B`;

	const kbytes = bytes / 1024;
	if (kbytes < 1024) return `${kbytes.toFixed(2)}Kb`;

	const mbytes = kbytes / 1024;
	if (mbytes < 1024) return `${mbytes.toFixed(2)}MB`;

	const gbytes = mbytes / 1024;
	return `${gbytes.toFixed(2)}GB`;
}

/**
 * Plugin that measures memory usage during benchmark execution
 * Collects heap usage statistics and provides reporting capabilities
 */
class MemoryPlugin {
	static MEMORY_BEFORE_RUN = "memoryBeforeRun";
	static MEMORY_AFTER_RUN = "memoryAfterRun";
	static #WARNING_REPORTED = false;

	/**
	 * @type {StatisticalHistogram}
	 */
	#heapUsedHistogram = new StatisticalHistogram();

	isSupported() {
		return typeof globalThis.gc === "function";
	}

	beforeClockTemplate({ managed, context }) {
		if (managed && !MemoryPlugin.#WARNING_REPORTED) {
			MemoryPlugin.#WARNING_REPORTED = true;
			process.emitWarning(
				"The memory statistics can be inaccurate since it will include the tear-up and teardown of your benchmark.",
			);
		}

		let code = "";

		code += `${context}.${MemoryPlugin.MEMORY_BEFORE_RUN} = 0;\n`;
		code += `${context}.${MemoryPlugin.MEMORY_AFTER_RUN} = 0;\n`;
		code += "globalThis.gc();\n";
		code += `${context}.${MemoryPlugin.MEMORY_BEFORE_RUN} = globalThis.process.memoryUsage();\n`;

		return [code];
	}

	afterClockTemplate({ context }) {
		return [
			`${context}.${MemoryPlugin.MEMORY_AFTER_RUN} = globalThis.process.memoryUsage();\n`,
		];
	}

	onCompleteBenchmark([, realIterations, context]) {
		const heapUsed =
			context[MemoryPlugin.MEMORY_AFTER_RUN].heapUsed -
			context[MemoryPlugin.MEMORY_BEFORE_RUN].heapUsed;
		const externalUsed =
			context[MemoryPlugin.MEMORY_AFTER_RUN].external -
			context[MemoryPlugin.MEMORY_BEFORE_RUN].external;

		const memoryAllocated = (heapUsed + externalUsed) / realIterations;

		// below 0, we just coerce to be zero
		this.#heapUsedHistogram.record(Math.max(0, memoryAllocated));
	}

	toString() {
		return "MemoryPlugin";
	}

	getReport() {
		this.#heapUsedHistogram.finish();

		return `heap usage=${formatBytes(this.#heapUsedHistogram.mean)} (${formatBytes(this.#heapUsedHistogram.min)} ... ${formatBytes(this.#heapUsedHistogram.max
Download .txt
gitextract_nbr14g_8/

├── .devcontainer/
│   └── devcontainer.json
├── .github/
│   ├── FUNDING.yml
│   └── workflows/
│       ├── benchmark-comparison.yml
│       ├── commit-message-validation.yml
│       ├── release.yml
│       ├── runner_warmer.yml
│       └── test.yml
├── .gitignore
├── .npmignore
├── .release-please-manifest.json
├── BENCHMARK_COMPARISSON.md
├── CHANGELOG.md
├── Dockerfile
├── README.md
├── assets/
│   └── README.md
├── bench-node-0.14.0.tgz
├── biome.json
├── doc/
│   ├── Inconclusive.md
│   └── Plugins.md
├── examples/
│   ├── .gitignore
│   ├── benchmark-comparison/
│   │   ├── README.md
│   │   └── comparison.js
│   ├── chart-report/
│   │   └── node.js
│   ├── create-uint32array/
│   │   ├── node.js
│   │   └── node.js.log
│   ├── crypto-verify/
│   │   ├── node.js
│   │   ├── node.js.log
│   │   ├── private-key.pem
│   │   └── public-key.pem
│   ├── csv-report/
│   │   └── node.js
│   ├── dce-detection/
│   │   ├── example.js
│   │   ├── with-dce-disabled.js
│   │   └── without-never-optimize.js
│   ├── deleting-properties/
│   │   ├── node.js
│   │   └── node.js.log
│   ├── empty/
│   │   ├── node.js
│   │   └── node.js.log
│   ├── fs-read-async/
│   │   ├── node.js
│   │   ├── node.js.log
│   │   ├── node.managed.js
│   │   ├── node.managed.js.log
│   │   └── sample-file.txt
│   ├── fs-read-sync/
│   │   ├── node.js
│   │   ├── node.js.log
│   │   └── sample-file.txt
│   ├── html-report/
│   │   ├── node.js
│   │   └── result.html
│   ├── json-report/
│   │   └── node.js
│   ├── plugins/
│   │   ├── all.js
│   │   ├── all.js.log
│   │   ├── memory.js
│   │   ├── v8-get-opt-status.js
│   │   ├── v8-get-opt-status.js.log
│   │   ├── v8-never-optimize.js
│   │   ├── v8-never-optimize.js.log
│   │   ├── v8-optimize-next-call.js
│   │   └── v8-optimize-next-call.js.log
│   ├── pretty-report/
│   │   └── node.js
│   ├── run.sh
│   ├── statistical-significance/
│   │   ├── README.md
│   │   └── node.js
│   ├── string-replace/
│   │   ├── node.js
│   │   └── node.js.log
│   ├── string-searching/
│   │   ├── node.js
│   │   └── node.js.log
│   ├── time-mode.js
│   └── worker-threads/
│       └── node.js
├── index.d.ts
├── lib/
│   ├── clock.js
│   ├── histogram.js
│   ├── index.js
│   ├── lifecycle.js
│   ├── plugins/
│   │   ├── dce-detection.js
│   │   ├── memory.js
│   │   ├── v8-never-opt.js
│   │   ├── v8-opt.js
│   │   └── v8-print-status.js
│   ├── plugins.js
│   ├── report.js
│   ├── reporter/
│   │   ├── chart.js
│   │   ├── csv.js
│   │   ├── html.js
│   │   ├── json.js
│   │   ├── pretty.js
│   │   ├── template.html
│   │   └── text.js
│   ├── utils/
│   │   ├── analyze.js
│   │   ├── styleText.js
│   │   └── ttest.js
│   ├── validators.js
│   └── worker-runner.js
├── package.json
├── release-please-config.json
├── test/
│   ├── async.js
│   ├── basic.js
│   ├── env.js
│   ├── fixtures/
│   │   ├── bench.js
│   │   ├── copy.js
│   │   └── opt-managed.js
│   ├── managed.js
│   ├── plugin-api-doc.js
│   ├── plugins.js
│   ├── reporter.js
│   ├── time-mode.js
│   ├── ttest.js
│   └── worker.js
└── types/
    └── types.test-d.ts
Download .txt
SYMBOL INDEX (195 symbols across 29 files)

FILE: examples/benchmark-comparison/comparison.js
  function fibRecursive (line 83) | function fibRecursive(n) {
  function formatNumber (line 94) | function formatNumber(num) {
  function runBenchNode (line 98) | async function runBenchNode() {
  function runBenchmarkJS (line 180) | async function runBenchmarkJS() {
  function runMitata (line 229) | async function runMitata() {
  function runTinyBench (line 291) | async function runTinyBench() {
  function compareResults (line 353) | function compareResults(results) {
  function main (line 414) | async function main() {

FILE: examples/chart-report/node.js
  function runSuiteOne (line 4) | async function runSuiteOne() {
  function runSuiteTwo (line 20) | async function runSuiteTwo() {
  function main (line 40) | async function main() {

FILE: index.d.ts
  class Benchmark (line 7) | class Benchmark {
  type PluginHookVarNames (line 31) | interface PluginHookVarNames {
  type BenchmarkResult (line 39) | interface BenchmarkResult {
  type ReporterFunction (line 49) | type ReporterFunction = (results: BenchmarkResult[]) => void;
  type ReporterOptions (line 51) | interface ReporterOptions {
  type SuiteOptions (line 58) | interface SuiteOptions {
  type BenchmarkOptions (line 71) | interface BenchmarkOptions {
  type BenchmarkFunction (line 78) | type BenchmarkFunction = (timer?: {
  type OnCompleteBenchmarkResult (line 84) | type OnCompleteBenchmarkResult = [
  type PluginResult (line 89) | type PluginResult = {
  type Plugin (line 94) | interface Plugin {
  class Suite (line 108) | class Suite {
  class V8NeverOptimizePlugin (line 115) | class V8NeverOptimizePlugin implements Plugin {
  class V8GetOptimizationStatus (line 122) | class V8GetOptimizationStatus implements Plugin {
  class V8OptimizeOnNextCallPlugin (line 131) | class V8OptimizeOnNextCallPlugin implements Plugin {
  class MemoryPlugin (line 138) | class MemoryPlugin implements Plugin {
  class DeadCodeEliminationDetectionPlugin (line 148) | class DeadCodeEliminationDetectionPlugin implements Plugin {
  class Suite (line 179) | class Suite extends BenchNode.Suite {}
  class V8NeverOptimizePlugin (line 180) | class V8NeverOptimizePlugin extends BenchNode.V8NeverOptimizePlugin {}
  class V8GetOptimizationStatus (line 181) | class V8GetOptimizationStatus extends BenchNode.V8GetOptimizationStatus {}
  class V8OptimizeOnNextCallPlugin (line 182) | class V8OptimizeOnNextCallPlugin extends BenchNode.V8OptimizeOnNextCallP...
  class MemoryPlugin (line 183) | class MemoryPlugin extends BenchNode.MemoryPlugin {}
  type WelchTTestResult (line 187) | interface WelchTTestResult {
  type CompareBenchmarksResult (line 198) | interface CompareBenchmarksResult {
  class DeadCodeEliminationDetectionPlugin (line 244) | class DeadCodeEliminationDetectionPlugin extends BenchNode.DeadCodeElimi...

FILE: lib/clock.js
  constant MIN_RESOLUTION (line 10) | const MIN_RESOLUTION = 0.5;
  class Timer (line 12) | class Timer {
    method constructor (line 13) | constructor() {
    method scale (line 17) | get scale() {
    method resolution (line 21) | get resolution() {
    method format (line 29) | format(timeInNs) {
  class ManagedTimer (line 50) | class ManagedTimer {
    method constructor (line 59) | constructor(recommendedCount) {
    method count (line 67) | get count() {
    method start (line 74) | start() {
    method end (line 82) | end(iterations = 1) {
    method [kUnmanagedTimerResult] (line 88) | [kUnmanagedTimerResult](context) {
  function createRunUnmanagedBenchmark (line 99) | function createRunUnmanagedBenchmark(bench, awaitOrEmpty) {
  function createRunManagedBenchmark (line 148) | function createRunManagedBenchmark(bench, awaitOrEmpty) {
  function createFnString (line 195) | function createFnString(bench) {
  function createRunner (line 208) | function createRunner(bench, recommendedCount) {
  function clockBenchmark (line 244) | async function clockBenchmark(bench, recommendedCount, options = {}) {

FILE: lib/histogram.js
  class StatisticalHistogram (line 8) | class StatisticalHistogram {
    method samples (line 20) | get samples() {
    method percentile (line 28) | percentile(percentile) {
    method record (line 46) | record(value) {
    method finish (line 52) | finish() {
    method removeOutliers (line 69) | removeOutliers() {
    method calculateMinMax (line 101) | calculateMinMax() {
    method calculateMean (line 111) | calculateMean() {
    method calculateStd (line 129) | calculateStd() {
    method calculateCv (line 147) | calculateCv() {

FILE: lib/index.js
  class Benchmark (line 45) | class Benchmark {
    method constructor (line 55) | constructor(
    method serializeBenchmark (line 86) | serializeBenchmark() {
  constant MIN_REPEAT_FOR_TTEST (line 106) | const MIN_REPEAT_FOR_TTEST = 30;
  function throwIfNoNativesSyntax (line 108) | function throwIfNoNativesSyntax() {
  class Suite (line 116) | class Suite {
    method constructor (line 128) | constructor(options = {}) {
    method add (line 200) | add(name, options, fn) {
    method run (line 248) | async run() {
    method #measureBaseline (line 327) | async #measureBaseline() {
    method runWorkerBenchmark (line 356) | async runWorkerBenchmark(benchmark, initialIterations) {

FILE: lib/lifecycle.js
  function getItersForOpDuration (line 14) | function getItersForOpDuration(durationPerOp, targetTime) {
  function parsePluginsResult (line 21) | function parsePluginsResult(plugins, name) {
  function getInitialIterations (line 38) | async function getInitialIterations(bench) {
  function runWarmup (line 65) | async function runWarmup(bench, initialIterations, { minTime, maxTime }) {
  function runBenchmarkOnce (line 96) | async function runBenchmarkOnce(
  function runBenchmark (line 149) | async function runBenchmark(

FILE: lib/plugins.js
  function validatePlugins (line 18) | function validatePlugins(plugins) {

FILE: lib/plugins/dce-detection.js
  class DeadCodeEliminationDetectionPlugin (line 10) | class DeadCodeEliminationDetectionPlugin {
    method constructor (line 15) | constructor(options = {}) {
    method isSupported (line 22) | isSupported() {
    method setBaseline (line 30) | setBaseline(timePerOp) {
    method onCompleteBenchmark (line 37) | onCompleteBenchmark(result, bench) {
    method getWarning (line 59) | getWarning(benchmarkName) {
    method getAllWarnings (line 66) | getAllWarnings() {
    method hasWarning (line 76) | hasWarning(benchmarkName) {
    method emitWarnings (line 83) | emitWarnings() {
    method toString (line 111) | toString() {
    method reset (line 115) | reset() {

FILE: lib/plugins/memory.js
  function formatBytes (line 8) | function formatBytes(bytes) {
  class MemoryPlugin (line 25) | class MemoryPlugin {
    method isSupported (line 35) | isSupported() {
    method beforeClockTemplate (line 39) | beforeClockTemplate({ managed, context }) {
    method afterClockTemplate (line 57) | afterClockTemplate({ context }) {
    method onCompleteBenchmark (line 63) | onCompleteBenchmark([, realIterations, context]) {
    method toString (line 77) | toString() {
    method getReport (line 81) | getReport() {
    method getResult (line 87) | getResult() {
    method reset (line 95) | reset() {

FILE: lib/plugins/v8-never-opt.js
  class V8NeverOptimizePlugin (line 1) | class V8NeverOptimizePlugin {
    method isSupported (line 2) | isSupported() {
    method beforeClockTemplate (line 12) | beforeClockTemplate({ bench }) {
    method toString (line 24) | toString() {
    method getReport (line 28) | getReport() {

FILE: lib/plugins/v8-opt.js
  class V8OptimizeOnNextCallPlugin (line 1) | class V8OptimizeOnNextCallPlugin {
    method isSupported (line 2) | isSupported() {
    method beforeClockTemplate (line 12) | beforeClockTemplate({ awaitOrEmpty, bench, timer }) {
    method getReport (line 22) | getReport() {
    method toString (line 26) | toString() {

FILE: lib/plugins/v8-print-status.js
  function checkBitmap (line 1) | function checkBitmap(value, bit) {
  function translateStatus (line 5) | function translateStatus(optStatus) {
  class V8GetOptimizationStatus (line 54) | class V8GetOptimizationStatus {
    method isSupported (line 57) | isSupported() {
    method afterClockTemplate (line 67) | afterClockTemplate({ bench, context }) {
    method onCompleteBenchmark (line 73) | onCompleteBenchmark(result) {
    method toString (line 78) | toString() {
    method getReport (line 82) | getReport() {
    method getResult (line 90) | getResult() {
    method reset (line 101) | reset() {

FILE: lib/reporter/chart.js
  function drawBar (line 15) | function drawBar(label, value, total, samples, metric, width, comment = ...
  function chartReport (line 84) | function chartReport(results, options = { labelWidth: 45, printHeader: t...
  function toChart (line 94) | function toChart(

FILE: lib/reporter/csv.js
  function csvReport (line 12) | function csvReport(results) {
  function toCSV (line 21) | function toCSV(results) {

FILE: lib/reporter/html.js
  function htmlReport (line 80) | function htmlReport(results) {

FILE: lib/reporter/json.js
  function jsonReport (line 8) | function jsonReport(results) {
  function toJSON (line 17) | function toJSON(results) {

FILE: lib/reporter/pretty.js
  constant BOX_VERTICAL (line 10) | const BOX_VERTICAL = "│";
  constant BOX_HORIZONTAL (line 11) | const BOX_HORIZONTAL = "─";
  constant BOX_CORNER_BOTTOM_LEFT (line 12) | const BOX_CORNER_BOTTOM_LEFT = "└";
  constant BOX_TEE_RIGHT (line 13) | const BOX_TEE_RIGHT = "├";
  function prettyReport (line 19) | function prettyReport(results, options = {}) {
  function toPretty (line 28) | function toPretty(results, options = {}) {
  function buildTree (line 114) | function buildTree(results) {
  function formatTree (line 138) | function formatTree(node, prefix = "", isLast = true) {
  function resultLine (line 182) | function resultLine(result, prefixLength) {

FILE: lib/reporter/text.js
  function textReport (line 15) | function textReport(results, options = {}) {
  function toText (line 19) | function toText(results, options = {}) {
  function localize (line 114) | function localize(number) {

FILE: lib/utils/analyze.js
  function analyze (line 4) | function analyze(results, sorted = true, options = {}) {
  function summarize (line 111) | function summarize(results) {

FILE: lib/utils/ttest.js
  function mean (line 3) | function mean(arr) {
  function variance (line 9) | function variance(arr, arrMean) {
  function erf (line 16) | function erf(x) {
  function lnGamma (line 35) | function lnGamma(z) {
  function incompleteBeta (line 59) | function incompleteBeta(a, b, x) {
  function tDistCdf (line 111) | function tDistCdf(t, df) {
  function welchTTest (line 118) | function welchTTest(sample1, sample2) {
  function getSignificanceStars (line 182) | function getSignificanceStars(pValue) {
  function compareBenchmarks (line 189) | function compareBenchmarks(sample1, sample2, alpha = 0.05) {

FILE: lib/validators.js
  function ERR_INVALID_ARG_TYPE (line 6) | function ERR_INVALID_ARG_TYPE(message) {
  function ERR_INVALID_ARG_VALUE (line 17) | function ERR_INVALID_ARG_VALUE(message) {
  function validateNumber (line 31) | function validateNumber(value, name, min, max) {
  function validateObject (line 54) | function validateObject(value, name) {
  function validateFunction (line 74) | function validateFunction(value, name) {
  function validateString (line 87) | function validateString(value, name) {
  function validateBenchmarkMode (line 100) | function validateBenchmarkMode(value, name) {
  function validateArray (line 117) | function validateArray(value, name) {
  function validateBoolean (line 130) | function validateBoolean(value, name) {

FILE: lib/worker-runner.js
  function deserializeBenchmark (line 11) | function deserializeBenchmark(benchmark) {

FILE: test/basic.js
  function noop (line 7) | function noop() {}

FILE: test/env.js
  function assertMinBenchmarkDifference (line 7) | function assertMinBenchmarkDifference(
  function assertMaxBenchmarkDifference (line 18) | function assertMaxBenchmarkDifference(
  function assertBenchmarkDifference (line 29) | function assertBenchmarkDifference(

FILE: test/plugin-api-doc.js
  class ExamplePlugin (line 6) | class ExamplePlugin {
    method constructor (line 8) | constructor() { }
    method isSupported (line 10) | isSupported() {
    method beforeClockTemplate (line 14) | beforeClockTemplate() {
    method afterClockTemplate (line 18) | afterClockTemplate({ context }) {
    method onCompleteBenchmark (line 27) | onCompleteBenchmark([time, iterations, results], { name }) {
    method toString (line 34) | toString() {
    method getReport (line 38) | getReport(name) {
    method getResult (line 42) | getResult(name) {
  function record (line 94) | function record(name, args) {
  function printExcerptFromHistory (line 107) | function printExcerptFromHistory(n = 25) {
  function getSignatures (line 125) | function getSignatures() {
  function captureAll (line 143) | function captureAll(pluginInstance) {

FILE: test/plugins.js
  class InvalidPlugin (line 12) | class InvalidPlugin {}
  class ValidPlugin (line 14) | class ValidPlugin {
    method toString (line 15) | toString() {
    method isSupported (line 18) | isSupported() {
  class InvalidPlugin2 (line 48) | class InvalidPlugin2 {
    method beforeClockTemplate (line 49) | beforeClockTemplate() {
    method toString (line 52) | toString() {
    method isSupported (line 55) | isSupported() {
    method beforeClockTemplate (line 72) | beforeClockTemplate() {
    method afterClockTemplate (line 75) | afterClockTemplate() {
    method toString (line 78) | toString() {
    method isSupported (line 81) | isSupported() {
  class InvalidPlugin2 (line 71) | class InvalidPlugin2 {
    method beforeClockTemplate (line 49) | beforeClockTemplate() {
    method toString (line 52) | toString() {
    method isSupported (line 55) | isSupported() {
    method beforeClockTemplate (line 72) | beforeClockTemplate() {
    method afterClockTemplate (line 75) | afterClockTemplate() {
    method toString (line 78) | toString() {
    method isSupported (line 81) | isSupported() {

FILE: test/reporter.js
  function customReporter (line 608) | function customReporter(results) {

FILE: test/worker.js
  function noop (line 5) | function noop() {}
Condensed preview — 107 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (336K chars).
[
  {
    "path": ".devcontainer/devcontainer.json",
    "chars": 84,
    "preview": "{\n\t\"name\": \"Bench-node Container\",\n\t\"build\": {\n\t\t\"dockerfile\": \"../Dockerfile\"\n\t}\n}\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 933,
    "preview": "# These are supported funding model platforms\n\ngithub: [RafaelGSS] # Replace with up to 4 GitHub Sponsors-enabled userna"
  },
  {
    "path": ".github/workflows/benchmark-comparison.yml",
    "chars": 1276,
    "preview": "name: Benchmark Comparison\n\non:\n  push:\n    branches:\n      - main\n  workflow_dispatch:\n\npermissions:\n  issues: write\n  "
  },
  {
    "path": ".github/workflows/commit-message-validation.yml",
    "chars": 325,
    "preview": "name: Commit Message Validation\n\non:\n  pull_request:\n\njobs:\n  validate:\n    name: Validate\n    runs-on: ubuntu-latest\n  "
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 892,
    "preview": "name: Release\n\non:\n  push:\n    branches:\n      - main\n\npermissions:\n  contents: write\n  pull-requests: write\n  id-token:"
  },
  {
    "path": ".github/workflows/runner_warmer.yml",
    "chars": 969,
    "preview": "name: Cron - Keep Runners Active\n\non:\n  schedule:\n    # Runs this workflow every Sunday at 12:00 UTC. You can adjust the"
  },
  {
    "path": ".github/workflows/test.yml",
    "chars": 1144,
    "preview": "name: Test CI\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n\npermissions:\n  issues: write\n  contents: read\n  i"
  },
  {
    "path": ".gitignore",
    "chars": 53,
    "preview": "tags\n.idea\nnode_modules/\npackage-lock.json\n\ncoverage\n"
  },
  {
    "path": ".npmignore",
    "chars": 64,
    "preview": "# We don't want to publish the logo and others\nassets\n\ncoverage\n"
  },
  {
    "path": ".release-please-manifest.json",
    "chars": 19,
    "preview": "{\n\t\".\": \"0.15.0\"\n}\n"
  },
  {
    "path": "BENCHMARK_COMPARISSON.md",
    "chars": 4674,
    "preview": "# Benchmark Library Comparison\n\nThis document provides a comprehensive comparison between `bench-node` and other popular"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 28505,
    "preview": "# Changelog\n\n## [0.15.0](https://github.com/RafaelGSS/bench-node/compare/v0.14.0...v0.15.0) (2026-05-08)\n\n\n### Features\n"
  },
  {
    "path": "Dockerfile",
    "chars": 63,
    "preview": "FROM node:24-trixie-slim\n\nRUN apt update && apt install git -y\n"
  },
  {
    "path": "README.md",
    "chars": 31484,
    "preview": "<h1 align=\"center\">\n  <img\n    src=\"https://raw.githubusercontent.com/RafaelGSS/bench-node/refs/heads/main/assets/logo.s"
  },
  {
    "path": "assets/README.md",
    "chars": 481,
    "preview": "# \"Branding\"\n\n## Logo\n\n| Logo | Description |\n| --- | --- |\n| ![Logo](./logo.svg) | simple logo for readme |\n| ![Logo](."
  },
  {
    "path": "biome.json",
    "chars": 468,
    "preview": "{\n\t\"$schema\": \"https://biomejs.dev/schemas/1.8.3/schema.json\",\n\t\"organizeImports\": {\n\t\t\"enabled\": true\n\t},\n\t\"linter\": {\n"
  },
  {
    "path": "doc/Inconclusive.md",
    "chars": 3902,
    "preview": "# Fixing Inconclusive Tests\n\nt-tests are looking at the distribution of both sets of results and trying to determine if "
  },
  {
    "path": "doc/Plugins.md",
    "chars": 6083,
    "preview": "# Plugins\n\nThe benchmark module supports a flexible plugin system that\nallows you to extend its functionality by adding "
  },
  {
    "path": "examples/.gitignore",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "examples/benchmark-comparison/README.md",
    "chars": 814,
    "preview": "# Benchmark Comparison Framework\n\nThis directory contains a framework for comparing `bench-node` against other popular b"
  },
  {
    "path": "examples/benchmark-comparison/comparison.js",
    "chars": 13189,
    "preview": "\nconst { Suite } = require('../../lib');\nconst Benchmark = require('benchmark');\nconst { bench, run: mitataRun } = requi"
  },
  {
    "path": "examples/chart-report/node.js",
    "chars": 1049,
    "preview": "const { Suite, chartReport } = require('../../lib');\nconst assert = require('node:assert');\n\nasync function runSuiteOne("
  },
  {
    "path": "examples/create-uint32array/node.js",
    "chars": 711,
    "preview": "const { Suite } = require('../../lib');\n\nconst suite = new Suite();\n\nsuite\n  .add(`new Uint32Array(1024)`, { baseline: t"
  },
  {
    "path": "examples/create-uint32array/node.js.log",
    "chars": 1112,
    "preview": "new Uint32Array(1024) x 2,930,763 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(332.08ns ... 355.52ns) p75="
  },
  {
    "path": "examples/crypto-verify/node.js",
    "chars": 2321,
    "preview": "const crypto = require('node:crypto');\nconst { readFileSync } = require('fs');\nconst { Suite } = require('../../lib');\n\n"
  },
  {
    "path": "examples/crypto-verify/node.js.log",
    "chars": 2013,
    "preview": "crypto.createVerify('RSA-SHA256') x 10,925 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(88.50us ... 93.51u"
  },
  {
    "path": "examples/crypto-verify/private-key.pem",
    "chars": 1674,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAz7QweYwr7puNtc8/6jf4pADXfY2/HVq7LgI7JXkAwW5HTEjU\nRvu02SYC7n/ylr86Da4hcAE"
  },
  {
    "path": "examples/crypto-verify/public-key.pem",
    "chars": 450,
    "preview": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz7QweYwr7puNtc8/6jf4\npADXfY2/HVq7LgI7JXkAwW5HTEjU"
  },
  {
    "path": "examples/csv-report/node.js",
    "chars": 619,
    "preview": "const { Suite } = require('../../lib');\nconst assert = require('node:assert');\n\nconst suite = new Suite();\n\nsuite\n  .add"
  },
  {
    "path": "examples/dce-detection/example.js",
    "chars": 1354,
    "preview": "const { Suite } = require(\"../../lib/index\");\n\n// Enable DCE detection to catch benchmarks that may be optimized away\nco"
  },
  {
    "path": "examples/dce-detection/with-dce-disabled.js",
    "chars": 503,
    "preview": "const { Suite } = require(\"../../lib/index\");\n\n// Default behavior - DCE detection is disabled, V8NeverOptimizePlugin is"
  },
  {
    "path": "examples/dce-detection/without-never-optimize.js",
    "chars": 1255,
    "preview": "const { Suite } = require(\"../../lib/index\");\n\n// Enable DCE detection - this automatically disables V8NeverOptimizePlug"
  },
  {
    "path": "examples/deleting-properties/node.js",
    "chars": 1683,
    "preview": "const { Suite } = require('../../lib');\n\nconst suite = new Suite();\n\nconst NullObject = function NullObject() { }\nNullOb"
  },
  {
    "path": "examples/deleting-properties/node.js.log",
    "chars": 3513,
    "preview": "Using delete property x 7,763,866 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(128.11ns ... 129.99ns) p75="
  },
  {
    "path": "examples/empty/node.js",
    "chars": 161,
    "preview": "const { Suite } = require('../../lib');\n\nconst suite = new Suite();\n\nsuite\n  .add(`empty`, function () {})\n  .add(`empty"
  },
  {
    "path": "examples/empty/node.js.log",
    "chars": 977,
    "preview": "empty x 218,984,985 ops/sec (12 runs sampled) v8-never-optimize=true min..max=(4.53ns ... 4.66ns) p75=4.58ns p99=4.66ns\n"
  },
  {
    "path": "examples/fs-read-async/node.js",
    "chars": 1300,
    "preview": "const { Suite } = require('../../lib');\nconst { readFile } = require('node:fs/promises');\nconst { resolve } = require('n"
  },
  {
    "path": "examples/fs-read-async/node.js.log",
    "chars": 1791,
    "preview": "readFile x 23,167 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(42.59us ... 43.59us) p75=43.42us p99=43.59u"
  },
  {
    "path": "examples/fs-read-async/node.managed.js",
    "chars": 942,
    "preview": "const { Suite } = require('../../lib');\n\nconst suite = new Suite();\n\nsuite\n  .add('readFile', async function (timer) {\n "
  },
  {
    "path": "examples/fs-read-async/node.managed.js.log",
    "chars": 981,
    "preview": "readFile x 23,066 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(42.59us ... 43.63us) p75=43.20us p99=43.63u"
  },
  {
    "path": "examples/fs-read-async/sample-file.txt",
    "chars": 5,
    "preview": "hello"
  },
  {
    "path": "examples/fs-read-sync/node.js",
    "chars": 1270,
    "preview": "const { Suite } = require('../../lib');\nconst { readFileSync } = require('node:fs');\nconst { resolve } = require('node:p"
  },
  {
    "path": "examples/fs-read-sync/node.js.log",
    "chars": 1801,
    "preview": "readFileSync x 198,828 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(5.01us ... 5.06us) p75=5.04us p99=5.06"
  },
  {
    "path": "examples/fs-read-sync/sample-file.txt",
    "chars": 5,
    "preview": "hello"
  },
  {
    "path": "examples/html-report/node.js",
    "chars": 658,
    "preview": "const { Suite, htmlReport } = require('../../lib');\nconst assert = require('node:assert');\n\nconst suite = new Suite({\n  "
  },
  {
    "path": "examples/html-report/result.html",
    "chars": 3912,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, in"
  },
  {
    "path": "examples/json-report/node.js",
    "chars": 658,
    "preview": "const { Suite, jsonReport } = require('../../lib');\nconst assert = require('node:assert');\n\nconst suite = new Suite({\n  "
  },
  {
    "path": "examples/plugins/all.js",
    "chars": 693,
    "preview": "const {\n  Suite,\n  V8GetOptimizationStatus,\n  V8NeverOptimizePlugin,\n  V8OptimizeOnNextCallPlugin,\n  MemoryPlugin,\n} = r"
  },
  {
    "path": "examples/plugins/all.js.log",
    "chars": 1647,
    "preview": "new Uint32Array(1024) x 2,395,395 ops/sec (14 runs sampled) v8-opt-status=\"Optimized, Interpreted, Marked for Optimizati"
  },
  {
    "path": "examples/plugins/memory.js",
    "chars": 540,
    "preview": "const { Suite, MemoryPlugin} = require('../../lib');\n\nconst suite = new Suite({\n    plugins: [new MemoryPlugin()],\n});\n\n"
  },
  {
    "path": "examples/plugins/v8-get-opt-status.js",
    "chars": 513,
    "preview": "const { Suite, V8GetOptimizationStatus } = require('../../lib');\n\nconst suite = new Suite({\n  plugins: [new V8GetOptimiz"
  },
  {
    "path": "examples/plugins/v8-get-opt-status.js.log",
    "chars": 1509,
    "preview": "new Uint32Array(1024) x 2,353,498 ops/sec (10 runs sampled) v8-opt-status=\"Optimized, Interpreted, Marked for Optimizati"
  },
  {
    "path": "examples/plugins/v8-never-optimize.js",
    "chars": 509,
    "preview": "const { Suite, V8NeverOptimizePlugin } = require('../../lib');\n\nconst suite = new Suite({\n  plugins: [new V8NeverOptimiz"
  },
  {
    "path": "examples/plugins/v8-never-optimize.js.log",
    "chars": 1112,
    "preview": "new Uint32Array(1024) x 2,535,349 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(357.30ns ... 442.55ns) p75="
  },
  {
    "path": "examples/plugins/v8-optimize-next-call.js",
    "chars": 519,
    "preview": "const { Suite, V8OptimizeOnNextCallPlugin } = require('../../lib');\n\nconst suite = new Suite({\n  plugins: [new V8Optimiz"
  },
  {
    "path": "examples/plugins/v8-optimize-next-call.js.log",
    "chars": 1154,
    "preview": "new Uint32Array(1024) x 2,812,339 ops/sec (13 runs sampled) v8-optimize-next-call=enabled min..max=(314.34ns ... 373.62n"
  },
  {
    "path": "examples/pretty-report/node.js",
    "chars": 531,
    "preview": "const { Suite, prettyReport } = require('../../lib');\nconst assert = require('node:assert');\n\nconst suite = new Suite({\n"
  },
  {
    "path": "examples/run.sh",
    "chars": 793,
    "preview": "#!/bin/bash\n\n# clean previous logs\nrm -f ./**/*.log\n\nfor filename in ./**/*.*js; do\n    echo \"[1] Running $filename\"\n   "
  },
  {
    "path": "examples/statistical-significance/README.md",
    "chars": 2447,
    "preview": "# Statistical Significance Testing (T-Test)\n\nThis example demonstrates how to use Welch's t-test to determine if benchma"
  },
  {
    "path": "examples/statistical-significance/node.js",
    "chars": 1522,
    "preview": "/**\n * Statistical Significance Example\n *\n * This example demonstrates how to use Welch's t-test to determine\n * if ben"
  },
  {
    "path": "examples/string-replace/node.js",
    "chars": 1291,
    "preview": "const { Suite } = require('../../lib');\n\nconst suite = new Suite();\n\nconst pattern = /[123]/g\nconst replacements = { 1: "
  },
  {
    "path": "examples/string-replace/node.js.log",
    "chars": 1837,
    "preview": "single with matcher x 752,020 ops/sec (10 runs sampled) v8-never-optimize=true min..max=(1.32us ... 1.34us) p75=1.33us p"
  },
  {
    "path": "examples/string-searching/node.js",
    "chars": 1749,
    "preview": "const { Suite } = require('../../lib');\n\nconst suite = new Suite();\n\nconst text = 'text/html,application/xhtml+xml,appli"
  },
  {
    "path": "examples/string-searching/node.js.log",
    "chars": 2725,
    "preview": "Using includes x 131,465,887 ops/sec (11 runs sampled) v8-never-optimize=true min..max=(7.53ns ... 7.61ns) p75=7.59ns p9"
  },
  {
    "path": "examples/time-mode.js",
    "chars": 723,
    "preview": "const { Suite } = require('../lib');\n\nconst timeSuite = new Suite({\n    benchmarkMode: 'time' // Set mode for the entire"
  },
  {
    "path": "examples/worker-threads/node.js",
    "chars": 453,
    "preview": "const { Suite } = require('../../lib');\n\nconst suite = new Suite({\n  useWorkers: true,\n});\n\nsuite\n  .add('Using import w"
  },
  {
    "path": "index.d.ts",
    "chars": 7422,
    "preview": "// Type definitions for bench-node\n\n/// <reference types=\"node\" />\nimport type { Histogram } from \"node:perf_hooks\";\n\nex"
  },
  {
    "path": "lib/clock.js",
    "chars": 6158,
    "preview": "const { debuglog } = require(\"node:util\");\nconst { validateNumber } = require(\"./validators\");\n\nconst debugBench = debug"
  },
  {
    "path": "lib/histogram.js",
    "chars": 3293,
    "preview": "const { validateNumber } = require(\"./validators\");\n\n/**\n * A class that calculates and maintains statistical measuremen"
  },
  {
    "path": "lib/index.js",
    "chars": 10341,
    "preview": "const { Worker } = require(\"node:worker_threads\");\nconst { types } = require(\"node:util\");\nconst path = require(\"node:pa"
  },
  {
    "path": "lib/lifecycle.js",
    "chars": 6865,
    "preview": "const {\n\tclockBenchmark,\n\tdebugBench,\n\tMIN_RESOLUTION,\n\ttimer,\n} = require(\"./clock\");\nconst { StatisticalHistogram } = "
  },
  {
    "path": "lib/plugins/dce-detection.js",
    "chars": 3058,
    "preview": "const { timer } = require(\"../clock\");\n\n/**\n * Plugin that detects potential dead code elimination (DCE) in benchmarks.\n"
  },
  {
    "path": "lib/plugins/memory.js",
    "chars": 2754,
    "preview": "const { StatisticalHistogram } = require(\"../histogram\");\n\n/**\n * Formats a byte value into a human-readable string with"
  },
  {
    "path": "lib/plugins/v8-never-opt.js",
    "chars": 620,
    "preview": "class V8NeverOptimizePlugin {\n\tisSupported() {\n\t\ttry {\n\t\t\tnew Function(\"%NeverOptimizeFunction(() => {})\")();\n\n\t\t\treturn"
  },
  {
    "path": "lib/plugins/v8-opt.js",
    "chars": 607,
    "preview": "class V8OptimizeOnNextCallPlugin {\n\tisSupported() {\n\t\ttry {\n\t\t\tnew Function(\"%OptimizeFunctionOnNextCall(() => {})\")();\n"
  },
  {
    "path": "lib/plugins/v8-print-status.js",
    "chars": 2258,
    "preview": "function checkBitmap(value, bit) {\n\treturn (value & bit) === bit;\n}\n\nfunction translateStatus(optStatus) {\n\tif (optStatu"
  },
  {
    "path": "lib/plugins.js",
    "chars": 1697,
    "preview": "const { V8OptimizeOnNextCallPlugin } = require(\"./plugins/v8-opt\");\nconst { V8NeverOptimizePlugin } = require(\"./plugins"
  },
  {
    "path": "lib/report.js",
    "chars": 1412,
    "preview": "const textReport = require(\"./reporter/text\");\nconst prettyReport = require(\"./reporter/pretty\");\nconst chartReport = re"
  },
  {
    "path": "lib/reporter/chart.js",
    "chars": 5167,
    "preview": "const { platform, arch, availableParallelism, totalmem } = require(\"node:os\");\nconst { styleText } = require(\"../utils/s"
  },
  {
    "path": "lib/reporter/csv.js",
    "chars": 1298,
    "preview": "const { summarize } = require(\"../utils/analyze\");\n\nconst formatter = Intl.NumberFormat(undefined, {\n\tnotation: \"standar"
  },
  {
    "path": "lib/reporter/html.js",
    "chars": 3569,
    "preview": "const { platform, arch, availableParallelism, totalmem } = require(\"node:os\");\nconst fs = require(\"node:fs\");\nconst path"
  },
  {
    "path": "lib/reporter/json.js",
    "chars": 889,
    "preview": "const { summarize } = require(\"../utils/analyze\");\n\n/**\n * Outputs JSON formatted results the console\n * @param {Benchma"
  },
  {
    "path": "lib/reporter/pretty.js",
    "chars": 5371,
    "preview": "const { styleText } = require(\"../utils/styleText\");\nconst os = require(\"node:os\");\nconst { analyze, summarize } = requi"
  },
  {
    "path": "lib/reporter/template.html",
    "chars": 2872,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, in"
  },
  {
    "path": "lib/reporter/text.js",
    "chars": 3160,
    "preview": "const { styleText } = require(\"../utils/styleText\");\nconst { analyze, summarize } = require(\"../utils/analyze.js\");\n\ncon"
  },
  {
    "path": "lib/utils/analyze.js",
    "chars": 3455,
    "preview": "const { timer } = require(\"../clock\");\nconst { compareBenchmarks } = require(\"./ttest\");\n\nfunction analyze(results, sort"
  },
  {
    "path": "lib/utils/styleText.js",
    "chars": 148,
    "preview": "const util = require(\"node:util\");\n\nmodule.exports.styleText =\n\ttypeof util.styleText === \"function\"\n\t\t? util.styleText\n"
  },
  {
    "path": "lib/utils/ttest.js",
    "chars": 4795,
    "preview": "// Welch's t-test implementation for benchmark comparison\n\nfunction mean(arr) {\n\tif (arr.length === 0) return 0;\n\treturn"
  },
  {
    "path": "lib/validators.js",
    "chars": 4118,
    "preview": "/**\n * Creates an error object with ERR_INVALID_ARG_TYPE code\n * @param {string} message - The error message\n * @returns"
  },
  {
    "path": "lib/worker-runner.js",
    "chars": 1176,
    "preview": "const { parentPort } = require(\"node:worker_threads\");\nconst {\n\trunBenchmark,\n\tgetInitialIterations,\n\trunWarmup,\n} = req"
  },
  {
    "path": "package.json",
    "chars": 1171,
    "preview": "{\n\t\"name\": \"bench-node\",\n\t\"version\": \"0.15.0\",\n\t\"description\": \"\",\n\t\"main\": \"lib/index.js\",\n\t\"types\": \"index.d.ts\",\n\t\"sc"
  },
  {
    "path": "release-please-config.json",
    "chars": 1573,
    "preview": "{\n\t\"packages\": {\n\t\t\".\": {\n\t\t\t\"release-type\": \"node\",\n\t\t\t\"bump-minor-pre-major\": true,\n\t\t\t\"bump-patch-for-minor-pre-major"
  },
  {
    "path": "test/async.js",
    "chars": 113,
    "preview": "const { todo } = require(\"node:test\");\n\ntodo(\"async tasks should behave similar to sync tasks\", async () => {});\n"
  },
  {
    "path": "test/basic.js",
    "chars": 6437,
    "preview": "const { Suite } = require(\"../lib/index\");\nconst { describe, it, todo } = require(\"node:test\");\nconst assert = require(\""
  },
  {
    "path": "test/env.js",
    "chars": 3404,
    "preview": "const { describe, it, before } = require(\"node:test\");\nconst assert = require(\"node:assert\");\nconst { Suite } = require("
  },
  {
    "path": "test/fixtures/bench.js",
    "chars": 146,
    "preview": "const { Suite } = require(\"../../lib\");\n\nconst suite = new Suite();\n\nsuite\n\t.add(\"empty\", () => {})\n\t.add(\"empty async\","
  },
  {
    "path": "test/fixtures/copy.js",
    "chars": 805,
    "preview": "const { Suite } = require(\"../../lib\");\n\nconst suite = new Suite({ reporter: false });\n\nsuite\n\t.add(\"Using includes\", { "
  },
  {
    "path": "test/fixtures/opt-managed.js",
    "chars": 1394,
    "preview": "const { Suite } = require(\"../../lib\");\nconst assert = require(\"node:assert\");\n\nconst suite = new Suite({ reporter: fals"
  },
  {
    "path": "test/managed.js",
    "chars": 764,
    "preview": "const { describe, it } = require(\"node:test\");\nconst assert = require(\"node:assert\");\nconst { Suite } = require(\"../lib/"
  },
  {
    "path": "test/plugin-api-doc.js",
    "chars": 4292,
    "preview": "// @ts-check\nconst { Suite } = require(\"../lib/index.js\");\nconst { describe, it } = require(\"node:test\");\nconst assert ="
  },
  {
    "path": "test/plugins.js",
    "chars": 5345,
    "preview": "const {\n\tSuite,\n\tV8NeverOptimizePlugin,\n\tV8GetOptimizationStatus,\n\tV8OptimizeOnNextCallPlugin,\n\tMemoryPlugin,\n\tDeadCodeE"
  },
  {
    "path": "test/reporter.js",
    "chars": 23825,
    "preview": "const { describe, it, before } = require(\"node:test\");\nconst assert = require(\"node:assert\");\nconst fs = require(\"node:f"
  },
  {
    "path": "test/time-mode.js",
    "chars": 4124,
    "preview": "const { Suite } = require(\"../lib/index\");\nconst { describe, it } = require(\"node:test\");\nconst assert = require(\"node:a"
  },
  {
    "path": "test/ttest.js",
    "chars": 13274,
    "preview": "const { describe, it } = require(\"node:test\");\nconst assert = require(\"node:assert\");\nconst {\n\tmean,\n\tvariance,\n\twelchTT"
  },
  {
    "path": "test/worker.js",
    "chars": 1028,
    "preview": "const workerThreads = require(\"node:worker_threads\");\nconst { describe, it, before, after, mock } = require(\"node:test\")"
  },
  {
    "path": "types/types.test-d.ts",
    "chars": 6450,
    "preview": "import type { Histogram } from \"node:perf_hooks\";\nimport { expectAssignable, expectNotAssignable, expectType } from \"tsd"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the RafaelGSS/bench-node GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 107 files (299.9 KB), approximately 91.2k tokens, and a symbol index with 195 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!