src — benchmarks

Module: src-benchmarks Cohesion: 0.80 Members: 0

src — benchmarks

The src/benchmarks/performance-benchmarks.ts module provides a robust framework for defining, running, and analyzing performance benchmarks within the codebase. Its primary goal is to enable automated measurement and tracking of key performance indicators such as execution latency, memory usage, and throughput for various operations. This helps identify performance regressions and ensures the application remains performant as it evolves.

Purpose

This module serves as the central hub for performance testing. It allows developers to:

Core Concepts

The module defines several interfaces to structure benchmark data:

The BenchmarkRunner Class

The BenchmarkRunner is the central orchestrator for executing and managing benchmarks.

graph TD
    A[BenchmarkRunner] --> B{constructor(options?)}
    B --> C[benchmark(name, fn, options?)]
    B --> D[runSuite(name, benchmarks)]
    B --> E[saveResults(suite)]
    B --> F[formatResults(suite)]
    B --> G[compareWithBaseline(suite, baselinePath)]

    D --> C
    D --> H[getSystemInfo()]
    E -- uses --> I[fs-extra.ensureDir]
    E -- uses --> I[fs-extra.writeJson]
    G -- uses --> I[fs-extra.readJson]

constructor(options?: BenchmarkOptions)

Initializes the runner with default or provided options. These options dictate global behavior for benchmarks run by this instance, such as the number of iterations or whether to collect memory statistics.

benchmark(name: string, fn: () => Promise | void, options?: Partial): Promise

This is the core method for running a single benchmark. It executes the provided function fn multiple times, measures its execution time, and calculates various statistics.

Execution Flow:

  1. Warmup: fn is executed a few times without measurement to allow JIT compilers to optimize the code.
  2. Garbage Collection: If global.gc is available (requires --expose-gc Node.js flag), a garbage collection cycle is forced to ensure consistent memory measurements.
  3. Measurement: fn is executed for the specified number of iterations, and performance.now() is used to record the duration of each run.
  4. Memory Collection: If collectMemory is enabled, process.memoryUsage().heapUsed is captured before and after iterations to estimate memory consumption.
  5. Statistical Analysis: Calculates total time, average time, min/max times, standard deviation, and operations per second.
  6. Result: Returns a BenchmarkResult object.

runSuite(name: string, benchmarks: Array<{ name: string; fn: () => Promise | void }>): Promise

Orchestrates the execution of multiple individual benchmarks as a named suite. It iterates through the provided array of benchmark definitions, calling this.benchmark for each. It logs progress and aggregates all results into a BenchmarkSuite object.

private getSystemInfo(): SystemInfo

A private helper method that gathers system-level information using Node.js's os and process modules. This data is included in the BenchmarkSuite to provide context for the results.

saveResults(suite: BenchmarkSuite): Promise

Persists the entire BenchmarkSuite object to a JSON file. The file is named based on the suite's name and a timestamp, and stored in the outputDir specified in the runner's options (defaulting to .benchmarks). It uses fs-extra for file system operations.

formatResults(suite: BenchmarkSuite): string

Generates a human-readable, formatted string representation of the benchmark suite's results. This includes system information, a table of individual benchmark results (Avg, Min, Max, Ops/s), and a summary.

compareWithBaseline(suite: BenchmarkSuite, baselinePath: string): Promise

Compares the current BenchmarkSuite's results against a previously saved baseline JSON file. It generates a report showing the percentage change for each benchmark, highlighting significant deviations.

Benchmark Utilities (benchmarks object)

The benchmarks export provides a collection of helper functions useful for writing benchmark functions:

Pre-defined Benchmark Suites

The module also includes functions to run pre-configured benchmark suites:

runCoreEngineBenchmarks(runner: BenchmarkRunner): Promise

This function defines and runs a suite of benchmarks focused on core engine operations. It includes tests for:

It creates a temporary directory for file I/O tests and cleans it up afterwards.

runAllBenchmarks(options?: BenchmarkOptions): Promise

This is the main entry point for executing all defined benchmark suites. It initializes a BenchmarkRunner and then calls runCoreEngineBenchmarks (and potentially other suites if added in the future). It returns an array of BenchmarkSuite objects.

Usage and Integration

To run benchmarks, you would typically import runAllBenchmarks and execute it:

import { runAllBenchmarks, BenchmarkRunner } from &#39;./src/benchmarks/performance-benchmarks.js&#39;;
import { logger } from &#39;./src/utils/logger.js&#39;;

async function main() {
  const runner = new BenchmarkRunner({
    iterations: 50,
    collectMemory: true,
    outputDir: &#39;./benchmark-results&#39;,
  });

  logger.info(&#39;Starting all benchmarks...&#39;);
  const suites = await runAllBenchmarks(runner.options); class="hl-cmt">// Pass options to runAllBenchmarks

  for (const suite of suites) {
    const formattedResults = runner.formatResults(suite);
    logger.info(formattedResults);

    const filepath = await runner.saveResults(suite);
    logger.info(`Results saved to: ${filepath}`);

    class="hl-cmt">// Example: Compare with a baseline
    class="hl-cmt">// try {
    class="hl-cmt">//   const baselinePath = &#39;./benchmark-results/benchmark-core-engine-1678888888888.json&#39;;
    class="hl-cmt">//   const comparison = await runner.compareWithBaseline(suite, baselinePath);
    class="hl-cmt">//   logger.info(comparison);
    class="hl-cmt">// } catch (error) {
    class="hl-cmt">//   logger.warn(&#39;Could not compare with baseline:&#39;, error.message);
    class="hl-cmt">// }
  }
  logger.info(&#39;All benchmarks completed.&#39;);
}

main().catch(console.error);

This module is primarily consumed by tests/unit/performance-benchmarks.test.ts for automated testing and validation of the benchmarking framework itself, ensuring its accuracy and functionality. It's also intended for direct execution to gather performance metrics.