Skip to content

Commit 8eb7887

Browse files
Add CPU pinning (taskset -c 0) and manual GC between benchmark suites
- bench-compare.mjs: detect Linux + taskset, pin benchmarks to CPU 0 - bench-compare.mjs: pass NODE_OPTIONS='--expose-gc' to vitest bench - parser.bench.js: add beforeAll(() => globalThis.gc?.()) per suite Co-authored-by: NullVoxPopuli <[email protected]>
1 parent 9da29f4 commit 8eb7887

2 files changed

Lines changed: 36 additions & 2 deletions

File tree

scripts/bench-compare.mjs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ const BASE_BRANCH = baseIdx !== -1 ? args[baseIdx + 1] : 'main';
3131
const iterIdx = args.indexOf('--iterations');
3232
const ITERATIONS = iterIdx !== -1 ? Math.max(1, parseInt(args[iterIdx + 1], 10) || 1) : 1;
3333

34+
// ---------------------------------------------------------------------------
35+
// Platform detection
36+
// ---------------------------------------------------------------------------
37+
38+
const IS_LINUX = process.platform === 'linux';
39+
const HAS_TASKSET = IS_LINUX && spawnSync('which', ['taskset'], { stdio: 'pipe' }).status === 0;
40+
41+
if (HAS_TASKSET) {
42+
console.log('📌 CPU pinning enabled (taskset -c 0) for reduced context-switch variance.');
43+
}
44+
3445
// ---------------------------------------------------------------------------
3546
// Helpers
3647
// ---------------------------------------------------------------------------
@@ -49,8 +60,19 @@ function hasUncommittedChanges() {
4960
}
5061

5162
function runBench(outputFile) {
52-
const result = spawnSync('pnpm', ['vitest', 'bench', '--outputJson', outputFile, '--run'], {
63+
const benchArgs = ['vitest', 'bench', '--outputJson', outputFile, '--run'];
64+
65+
// Pin to a single CPU core on Linux to eliminate cross-core migration variance.
66+
const cmd = HAS_TASKSET ? 'taskset' : 'pnpm';
67+
const args = HAS_TASKSET ? ['-c', '0', 'pnpm', ...benchArgs] : benchArgs;
68+
69+
// Expose GC so the bench file can trigger manual collections between suites.
70+
const existingNodeOpts = process.env.NODE_OPTIONS || '';
71+
const nodeOptions = existingNodeOpts ? `${existingNodeOpts} --expose-gc` : '--expose-gc';
72+
73+
const result = spawnSync(cmd, args, {
5374
stdio: 'inherit',
75+
env: { ...process.env, NODE_OPTIONS: nodeOptions },
5476
});
5577
if (result.status !== 0) {
5678
console.error('\n❌ Benchmark run failed.');

tests/parser.bench.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { readFileSync } from 'node:fs';
22
import { fileURLToPath } from 'node:url';
3-
import { bench, describe } from 'vitest';
3+
import { bench, describe, beforeAll } from 'vitest';
44
import { parseForESLint as parseGjsGts } from '../src/parser/gjs-gts-parser.js';
55
import { parseForESLint as parseHbs } from '../src/parser/hbs-parser.js';
66

@@ -51,6 +51,10 @@ const BENCH_OPTIONS = {
5151
// ---------------------------------------------------------------------------
5252

5353
describe('gts parser', () => {
54+
beforeAll(() => {
55+
globalThis.gc?.();
56+
});
57+
5458
bench(
5559
'small file',
5660
() => {
@@ -77,6 +81,10 @@ describe('gts parser', () => {
7781
});
7882

7983
describe('gjs parser', () => {
84+
beforeAll(() => {
85+
globalThis.gc?.();
86+
});
87+
8088
bench(
8189
'small file',
8290
() => {
@@ -103,6 +111,10 @@ describe('gjs parser', () => {
103111
});
104112

105113
describe('hbs parser', () => {
114+
beforeAll(() => {
115+
globalThis.gc?.();
116+
});
117+
106118
bench(
107119
'small file',
108120
() => {

0 commit comments

Comments
 (0)