UNPKG

iso-bench

Version:

Small benchmark library focused in avoiding optimization/deoptimization pollution between tests by isolating them.

188 lines (187 loc) 5.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IsoBench = void 0; const Test_1 = require("./Test"); const Messager_1 = require("./Messager"); const WorkerSetup_1 = require("./WorkerSetup"); const processors_1 = require("./processors"); let IDs = 0; function getUniqueName(name, set) { let newName = name; while (set.has(newName)) { newName = `${name}_${IDs++}`; } return newName; } const BENCH_NAMES = new Set(); let lastBench = null; class IsoBench { name; processors = []; tests = []; currentTests = []; options; running = false; done = false; _waiting = []; constructor(name = "IsoBench", options) { this.name = name; this.options = { ...{ parallel: 1, samplesPerSpawn: 5, spawns: 10, customCycles: null, time: 100 }, ...options }; this.name = getUniqueName(this.name, BENCH_NAMES); BENCH_NAMES.add(this.name); } static IfMaster(cb) { if (!WorkerSetup_1.WorkerSetup) { cb(); } } addAsync(name, callback, setup, options) { if (setup && typeof setup === "object") { options = setup; setup = null; } this.#add(name, { async: true, callback: callback, setup: typeof setup === "function" ? setup : null }, options); return this; } add(name, callback, setup, options) { if (setup && typeof setup === "object") { options = setup; setup = null; } this.#add(name, { async: false, callback: callback, setup: typeof setup === "function" ? setup : null }, options); return this; } #add(name, testData, options) { if (this.running) { throw new Error("Can't add tests to a running bench"); } const filteredTestOptions = options && Object.fromEntries(Object.entries(options).filter(([_, v]) => v !== undefined)); const test = new Test_1.Test(name, this.tests.length, { ...this.options, ...filteredTestOptions }, testData); this.tests.push(test); this.currentTests.push(test); return this; } addProcessor(processorCallback) { if (WorkerSetup_1.WorkerSetup) { return this; } if (this.running) { throw new Error("Can't add processors to a running bench"); } this.processors.push(processorCallback()); return this; } consoleLog() { if (WorkerSetup_1.WorkerSetup) { return this; } return this.addProcessor(() => new processors_1.ConsoleLog()); } streamLog(streamCallback) { if (WorkerSetup_1.WorkerSetup) { return this; } return this.addProcessor(() => new processors_1.StreamLog(streamCallback())); } endGroup(name) { for (const test of this.currentTests.splice(0)) { test.setGroup(name); } return this; } async run() { if (this.running) { throw new Error("Already running"); } this.running = true; this.endGroup(""); const lastB = lastBench; lastBench = this; if (lastB != null) { await lastB.wait(); } if (WorkerSetup_1.WorkerSetup) { await this._start(WorkerSetup_1.WorkerSetup); } else { if (this.processors.length === 0) { this.consoleLog(); } let i = 0; const tests = this.tests.slice(); for (const processor of this.processors) { processor.initialize && processor.initialize(this, tests); } await Promise.all(new Array(this.options.parallel).fill(0).map(async () => { while (i < tests.length) { const test = tests[i++]; for (const processor of this.processors) { processor.start && processor.start(test); } await test.fork(this.name, this.processors, this.options); for (const processor of this.processors) { processor.end && processor.end(test); } } })); for (const processor of this.processors) { processor.completed && processor.completed(tests); } } this.done = true; if (lastBench === this) { lastBench = null; } for (const waiting of this._waiting) { waiting(); } } wait() { return new Promise((resolve) => { if (this.done) { resolve(); } else { this._waiting.push(resolve); } }); } async _start(setup) { if (this.name === setup.benchName) { try { const test = this.tests[setup.testIndex]; if (!test) { throw new Error("Test index " + setup.testIndex + " not found"); } await test.run(); await Messager_1.Messager.send({ done: true }); } catch (e) { await Messager_1.Messager.send({ error: String(e) }); } process.exit(); } } } exports.IsoBench = IsoBench;