fix/address flaky wall clock based test by doing best of 3

This commit is contained in:
M.Schmidt
2026-07-17 00:06:53 +02:00
parent 6215f37bf6
commit 494dcb8486
@@ -24,6 +24,7 @@ describe('worker-pool hashing (architecture gate)', () => {
// on the main thread, serially.
const nFiles = 24;
const size = 4 * 1024 * 1024;
const trials = 3;
const dir = await fs.mkdtemp(join(tmpdir(), 'hashbench-'));
const paths: string[] = [];
for (let i = 0; i < nFiles; i++) {
@@ -35,12 +36,14 @@ describe('worker-pool hashing (architecture gate)', () => {
}
// Sequential (old): read + hash on the calling thread.
const t0 = performance.now();
for (const p of paths) {
const b = await fs.readFile(p);
createHash('sha256').update(b).digest('hex');
}
const seqMs = performance.now() - t0;
const runSequential = async () => {
const t0 = performance.now();
for (const p of paths) {
const b = await fs.readFile(p);
createHash('sha256').update(b).digest('hex');
}
return performance.now() - t0;
};
// 3-lane pool (new): each worker reads + hashes its own files.
const lanes = 3;
@@ -53,35 +56,52 @@ describe('worker-pool hashing (architecture gate)', () => {
parentPort.postMessage(createHash('sha256').update(b).digest('hex'));
});
`;
const workers = Array.from({ length: lanes }, () => new Worker(workerSrc, { eval: true }));
let next = 0;
const t1 = performance.now();
await Promise.all(
workers.map(
(w) =>
new Promise<void>((resolve, reject) => {
const feed = () => {
if (next >= paths.length) {
resolve();
return;
}
const i = next++;
w.once('message', () => feed());
w.once('error', reject);
w.postMessage(paths[i]);
};
feed();
})
)
);
const poolMs = performance.now() - t1;
await Promise.all(workers.map((w) => w.terminate()));
const runPooled = async () => {
const workers = Array.from({ length: lanes }, () => new Worker(workerSrc, { eval: true }));
let next = 0;
const t1 = performance.now();
await Promise.all(
workers.map(
(w) =>
new Promise<void>((resolve, reject) => {
const feed = () => {
if (next >= paths.length) {
resolve();
return;
}
const i = next++;
w.once('message', () => feed());
w.once('error', reject);
w.postMessage(paths[i]);
};
feed();
})
)
);
const ms = performance.now() - t1;
await Promise.all(workers.map((w) => w.terminate()));
return ms;
};
// Best-of-`trials` wall-clock per strategy: a single sample is prone
// to scheduler/GC noise on a loaded machine, which can tip either
// side when the two are close. Noise only ever adds delay, so the
// minimum across trials is each strategy's true achievable time —
// a genuine architecture regression still fails every trial.
const seqTimes: number[] = [];
const poolTimes: number[] = [];
for (let i = 0; i < trials; i++) {
seqTimes.push(await runSequential());
poolTimes.push(await runPooled());
}
const seqMs = Math.min(...seqTimes);
const poolMs = Math.min(...poolTimes);
await fs.rm(dir, { recursive: true, force: true });
// eslint-disable-next-line no-console
console.info(
`read+hash ${nFiles} x 4 MiB: sequential ${seqMs.toFixed(0)} ms vs 3-lane pool ${poolMs.toFixed(0)} ms (${(seqMs / poolMs).toFixed(1)}x)`
`read+hash ${nFiles} x 4 MiB over ${trials} trials: best sequential ${seqMs.toFixed(0)} ms vs best 3-lane pool ${poolMs.toFixed(0)} ms (${(seqMs / poolMs).toFixed(1)}x)`
);
expect(poolMs).toBeLessThan(seqMs);
});
}, 20000);
});