UNPKG

@jonahsnider/benchmark

Version:

A Node.js benchmarking library with support for multithreading and TurboFan optimization isolation.

108 lines 4.01 kB
var _Benchmark_suites, _Benchmark_multithreadedSuites; import { __classPrivateFieldGet } from "tslib"; import assert from 'node:assert/strict'; import { partition } from '@jonahsnider/util'; import { Thread } from './thread.js'; /** * A benchmark which has many {@link SuiteLike}s. * * @example * ```js * import { Benchmark, Suite } from '@jonahsnider/benchmark'; * * const benchmark = new Benchmark(); * * const suite = new Suite('concatenation', { warmup: { durationMs: 10_000 }, run: { durationMs: 10_000 } }) * .addTest('+', () => 'a' + 'b') * .addTest('templates', () => `${'a'}${'b'}`) * .addTest('.concat()', () => 'a'.concat('b')); * * benchmark.addSuite(suite); * * const results = await benchmark.run(); * * console.log(results); * ``` * * @public */ export class Benchmark { constructor() { _Benchmark_suites.set(this, new Map()); _Benchmark_multithreadedSuites.set(this, new Set()); /** * The {@link SuiteLike}s in this {@link (Benchmark:class)}. */ // eslint-disable-next-line @typescript-eslint/member-ordering this.suites = __classPrivateFieldGet(this, _Benchmark_suites, "f"); } addSuite(suiteLike, options) { assert.ok(!__classPrivateFieldGet(this, _Benchmark_suites, "f").has(suiteLike.name), new RangeError(`A suite with the name "${suiteLike.name}" already exists`)); if (options?.threaded) { assert.ok(suiteLike.filepath); return Thread.init(suiteLike.filepath).then(threadedSuite => { __classPrivateFieldGet(this, _Benchmark_suites, "f").set(threadedSuite.name, threadedSuite); __classPrivateFieldGet(this, _Benchmark_multithreadedSuites, "f").add(threadedSuite.name); return this; }); } __classPrivateFieldGet(this, _Benchmark_suites, "f").set(suiteLike.name, suiteLike); return this; } /** * Run all {@link (Suite:class)}s for this {@link (Benchmark:class)}. * * @example * ```js * const results = await benchmark.runSuites(); * ``` * * @example * Using an `AbortSignal` to cancel the benchmark: * ```js * const ac = new AbortController(); * const signal = ac.signal; * * benchmark * .runSuites(signal) * .then(console.log) * .catch(error => { * if (error.name === 'AbortError') { * console.log('The benchmark was aborted'); * } * }); * * ac.abort(); * ``` * * @param abortSignal - An optional `AbortSignal` that can be used to cancel the running suites * * @returns A {@link (Benchmark:namespace).Results} `Map` */ async runSuites(abortSignal, options) { const results = new Map(); const [multithreaded, singleThreaded] = partition(__classPrivateFieldGet(this, _Benchmark_suites, "f").values(), suite => __classPrivateFieldGet(this, _Benchmark_multithreadedSuites, "f").has(suite.name)); // Single-threaded suites are executed serially to avoid any interference for (const suite of singleThreaded) { // eslint-disable-next-line no-await-in-loop const suiteResults = await suite.run(abortSignal); results.set(suite.name, suiteResults); } if (options?.sequential) { for (const suite of multithreaded) { // eslint-disable-next-line no-await-in-loop const suiteResults = await suite.run(abortSignal); results.set(suite.name, suiteResults); } } else { await Promise.all(multithreaded.map(async (suite) => { const suiteResults = await suite.run(abortSignal); results.set(suite.name, suiteResults); })); } return results; } } _Benchmark_suites = new WeakMap(), _Benchmark_multithreadedSuites = new WeakMap(); //# sourceMappingURL=benchmark.js.map