Skip to content

Commit d507420

Browse files
authored
test: stable benchmark
1 parent 2278878 commit d507420

File tree

7 files changed

+131
-100
lines changed

7 files changed

+131
-100
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
"devDependencies": {
111111
"@babel/core": "^7.27.1",
112112
"@babel/preset-react": "^7.27.1",
113-
"@codspeed/tinybench-plugin": "^4.0.1",
113+
"@codspeed/core": "^4.0.1",
114114
"@eslint/js": "^9.29.0",
115115
"@eslint/markdown": "^7.0.0",
116116
"@stylistic/eslint-plugin": "^5.0.0",

test/BenchmarkTestCases.benchmark.mjs

Lines changed: 126 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { constants, writeFile } from "fs";
22
import fs from "fs/promises";
33
import path from "path";
44
import { fileURLToPath, pathToFileURL } from "url";
5-
import { withCodSpeed } from "@codspeed/tinybench-plugin";
65
import { simpleGit } from "simple-git";
76
import { Bench, hrtimeNow } from "tinybench";
87

@@ -277,11 +276,15 @@ function buildConfiguration(
277276
`baseline-${baseline.name}`
278277
);
279278
config.plugins = config.plugins || [];
280-
281279
if (config.cache) {
282280
config.cache.cacheDirectory = path.resolve(config.output.path, ".cache");
283281
}
284-
282+
if (watch) {
283+
config.cache = {
284+
type: "memory",
285+
maxGenerations: 1
286+
};
287+
}
285288
return config;
286289
}
287290

@@ -319,12 +322,120 @@ const scenarios = [
319322

320323
const baseOutputPath = path.join(__dirname, "js", "benchmark");
321324

322-
const bench = withCodSpeed(
325+
const withCodSpeed = async (/** @type {import("tinybench").Bench} */ bench) => {
326+
const { Measurement, getGitDir, mongoMeasurement, setupCore, teardownCore } =
327+
await import("@codspeed/core");
328+
329+
if (!Measurement.isInstrumented()) {
330+
const rawRun = bench.run;
331+
bench.run = async () => {
332+
console.warn(
333+
`[CodSpeed] ${bench.tasks.length} benches detected but no instrumentation found, falling back to tinybench`
334+
);
335+
return await rawRun.bind(bench)();
336+
};
337+
return bench;
338+
}
339+
340+
const getStackTrace = (belowFn) => {
341+
const oldLimit = Error.stackTraceLimit;
342+
Error.stackTraceLimit = Infinity;
343+
const dummyObject = {};
344+
const v8Handler = Error.prepareStackTrace;
345+
Error.prepareStackTrace = (dummyObject, v8StackTrace) => v8StackTrace;
346+
Error.captureStackTrace(dummyObject, belowFn || getStackTrace);
347+
const v8StackTrace = dummyObject.stack;
348+
Error.prepareStackTrace = v8Handler;
349+
Error.stackTraceLimit = oldLimit;
350+
return v8StackTrace;
351+
};
352+
353+
const getCallingFile = () => {
354+
const stack = getStackTrace();
355+
let callingFile = stack[2].getFileName(); // [here, withCodSpeed, actual caller]
356+
const gitDir = getGitDir(callingFile);
357+
if (gitDir === undefined) {
358+
throw new Error("Could not find a git repository");
359+
}
360+
if (callingFile.startsWith("file://")) {
361+
callingFile = fileURLToPath(callingFile);
362+
}
363+
return path.relative(gitDir, callingFile);
364+
};
365+
366+
const rawAdd = bench.add;
367+
bench.add = (name, fn, opts) => {
368+
const callingFile = getCallingFile();
369+
const uri = `${callingFile}::${name}`;
370+
const options = { ...opts, uri };
371+
return rawAdd.bind(bench)(name, fn, options);
372+
};
373+
const rootCallingFile = getCallingFile();
374+
bench.run = async function run() {
375+
const iterations = bench.opts.iterations - 1;
376+
console.log("[CodSpeed] running");
377+
setupCore();
378+
for (const task of bench.tasks) {
379+
await bench.opts.setup?.(task, "run");
380+
await task.fnOpts.beforeAll?.call(task);
381+
const samples = [];
382+
async function iteration() {
383+
try {
384+
await task.fnOpts.beforeEach?.call(task, "run");
385+
const start = bench.opts.now();
386+
await task.fn();
387+
samples.push(bench.opts.now() - start || 0);
388+
await task.fnOpts.afterEach?.call(this, "run");
389+
} catch (err) {
390+
if (bench.opts.throws) {
391+
throw err;
392+
}
393+
}
394+
}
395+
while (samples.length < iterations) {
396+
await iteration();
397+
}
398+
// Codspeed Measure
399+
const uri =
400+
task.opts && "uri" in task.options
401+
? task.opts.uri
402+
: `${rootCallingFile}::${task.name}`;
403+
await task.fnOpts.beforeEach?.call(task);
404+
await mongoMeasurement.start(uri);
405+
await (async function __codspeed_root_frame__() {
406+
Measurement.startInstrumentation();
407+
await task.fn();
408+
Measurement.stopInstrumentation(uri);
409+
})();
410+
await mongoMeasurement.stop(uri);
411+
await task.fnOpts.afterEach?.call(task);
412+
console.log(`[Codspeed] ✔ Measured ${uri}`);
413+
await task.fnOpts.afterAll?.call(task);
414+
415+
await bench.opts.teardown?.(task, "run");
416+
task.processRunResult({ latencySamples: samples });
417+
}
418+
teardownCore();
419+
console.log(`[CodSpeed] Done running ${bench.tasks.length} benches.`);
420+
return bench.tasks;
421+
};
422+
return bench;
423+
};
424+
425+
const bench = await withCodSpeed(
323426
new Bench({
324427
now: hrtimeNow,
325428
throws: true,
326429
warmup: true,
327-
time: 30000
430+
warmupIterations: 2,
431+
iterations: 8,
432+
setup(task, mode) {
433+
global.gc();
434+
console.log(`Setup (${mode} mode): ${task.name}`);
435+
},
436+
teardown(task, mode) {
437+
console.log(`Teardown (${mode} mode): ${task.name}`);
438+
}
328439
})
329440
);
330441

@@ -393,6 +504,8 @@ async function registerSuite(bench, test, baselines) {
393504
bench.add(
394505
benchName,
395506
async () => {
507+
console.time(`Time: ${benchName}`);
508+
396509
const watchingPromise = new Promise((res) => {
397510
watchingResolve = res;
398511
});
@@ -407,9 +520,11 @@ async function registerSuite(bench, test, baselines) {
407520
}
408521

409522
watchingPromise.then((stats) => {
523+
watchingResolve = undefined;
524+
410525
// Construct and print stats to be more accurate with real life projects
411526
stats.toString();
412-
527+
console.timeEnd(`Time: ${benchName}`);
413528
resolve();
414529
});
415530
}
@@ -463,6 +578,8 @@ async function registerSuite(bench, test, baselines) {
463578
benchName,
464579
async () => {
465580
await new Promise((resolve, reject) => {
581+
console.time(`Time: ${benchName}`);
582+
466583
const baseCompiler = webpack(config);
467584

468585
baseCompiler.run((err, stats) => {
@@ -483,7 +600,7 @@ async function registerSuite(bench, test, baselines) {
483600

484601
// Construct and print stats to be more accurate with real life projects
485602
stats.toString();
486-
603+
console.timeEnd(`Time: ${benchName}`);
487604
resolve();
488605
});
489606
});
@@ -625,7 +742,7 @@ bench.addEventListener("cycle", (event) => {
625742
const collectBy = task.collectBy;
626743
const allStats = statsByTests.get(collectBy);
627744

628-
console.log(`Done: ${task.name} ${confidence} (${runs} runs sampled)`);
745+
console.log(`Cycle: ${task.name} ${confidence} (${runs} runs sampled)`);
629746

630747
const info = { ...latency, text, minConfidence, maxConfidence };
631748

@@ -646,11 +763,4 @@ bench.addEventListener("cycle", (event) => {
646763
);
647764
});
648765

649-
// Fix for https://github.com/CodSpeedHQ/codspeed-node/issues/44
650-
for (const name of bench.tasks.map((task) => task.name)) {
651-
const task = bench.getTask(name);
652-
653-
task.opts = task.fnOpts;
654-
}
655-
656-
await bench.run();
766+
bench.run();

test/benchmarkCases/cache-filesystem/webpack.config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
module.exports = {
55
entry: "./index",
66
cache: {
7-
type: "filesystem"
7+
type: "filesystem",
8+
// For benchmark stability
9+
maxMemoryGenerations: 0,
10+
idleTimeoutForInitialStore: 0
811
}
912
};

test/benchmarkCases/md4-and-xxhash64-unit/index.bench.mjs

Lines changed: 0 additions & 62 deletions
This file was deleted.

test/benchmarkCases/minimal/index.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

test/benchmarkCases/minimal/webpack.config.js

Lines changed: 0 additions & 6 deletions
This file was deleted.

yarn.lock

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -350,14 +350,6 @@
350350
form-data "^4.0.0"
351351
node-gyp-build "^4.6.0"
352352

353-
"@codspeed/tinybench-plugin@^4.0.1":
354-
version "4.0.1"
355-
resolved "https://registry.yarnpkg.com/@codspeed/tinybench-plugin/-/tinybench-plugin-4.0.1.tgz#b0e27a963c03e6ca84c99685ee86abdbd3aa5c9f"
356-
integrity sha512-hga1xif6XU8p/FZqTHzUrDPrBSLqxc3NuxMX8m4P8AIdhORsPrvgSNe09uVYlVOtD6jG7kPsmx5DZscez4wKrQ==
357-
dependencies:
358-
"@codspeed/core" "^4.0.1"
359-
stack-trace "1.0.0-pre2"
360-
361353
"@cspell/cspell-bundled-dicts@9.1.3":
362354
version "9.1.3"
363355
resolved "https://registry.yarnpkg.com/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-9.1.3.tgz#ad26ab92489fb5ac45e3a967ba2afd71560d8aab"
@@ -7467,11 +7459,6 @@ ssri@^12.0.0:
74677459
dependencies:
74687460
minipass "^7.0.3"
74697461

7470-
stack-trace@1.0.0-pre2:
7471-
version "1.0.0-pre2"
7472-
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-1.0.0-pre2.tgz#46a83a79f1b287807e9aaafc6a5dd8bcde626f9c"
7473-
integrity sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==
7474-
74757462
stack-utils@^2.0.6:
74767463
version "2.0.6"
74777464
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f"

0 commit comments

Comments
 (0)