iso-bench
Version:
Small benchmark library focused in avoiding optimization/deoptimization pollution between tests by isolating them.
146 lines (145 loc) • 4.61 kB
JavaScript
"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, map) {
let newName = name;
while (map.has(newName)) {
newName = `${name}_${IDs++}`;
}
return newName;
}
const BENCHES = new Map();
class IsoBench {
name;
processors = [];
tests = [];
currentTests = [];
options;
running = false;
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, BENCHES);
BENCHES.set(this.name, this);
}
static IfMaster(cb) {
if (!WorkerSetup_1.WorkerSetup) {
cb();
}
}
add(name, callback, setup, options) {
if (this.running) {
throw new Error("Can't add tests to a running bench");
}
if (setup && typeof setup === "object") {
options = setup;
setup = null;
}
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
}, {
callback: callback,
setup: typeof setup === "function" ? setup : null
});
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("");
if (WorkerSetup_1.WorkerSetup) {
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);
}
}
}
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;