You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte/benchmarking/run.js

150 lines
4.2 KiB

import { fork } from 'node:child_process';
import { fileURLToPath } from 'node:url';
import * as $ from '../packages/svelte/src/internal/client/index.js';
import { reactivity_benchmarks } from './benchmarks/reactivity/index.js';
import { ssr_benchmarks } from './benchmarks/ssr/index.js';
import { with_cpu_profile } from './utils.js';
const PROFILE_DIR = './benchmarking/.profiles';
const single = process.env.BENCH_SINGLE;
if (single) {
// child mode — run a single benchmark and report the result to the parent
const benchmark = [...reactivity_benchmarks, ...ssr_benchmarks].find((b) => b.label === single);
if (!benchmark) {
throw new Error(`Unknown benchmark ${single}`);
}
$.push({}, true);
const result = await with_cpu_profile(PROFILE_DIR, benchmark.label, () => benchmark.fn());
$.pop();
// exit via the callback so the message is guaranteed to be delivered
/** @type {NodeJS.Process} */ (process).send(result, () => process.exit(0));
} else {
// parent mode — run every benchmark in its own child process, so that
// heap/GC/JIT state from one benchmark cannot contaminate the others
// e.g. `pnpm bench kairo` to only run the kairo benchmarks
const filters = process.argv.slice(2);
const suites = [
{
benchmarks: reactivity_benchmarks.filter(
(b) => filters.length === 0 || filters.some((f) => b.label.includes(f))
),
name: 'reactivity benchmarks'
},
{
benchmarks: ssr_benchmarks.filter(
(b) => filters.length === 0 || filters.some((f) => b.label.includes(f))
),
name: 'server-side rendering benchmarks'
}
].filter((suite) => suite.benchmarks.length > 0);
if (suites.length === 0) {
console.log('No benchmarks matched provided filters');
process.exit(1);
}
const filename = fileURLToPath(import.meta.url);
/**
* @param {string} label
* @returns {Promise<{ time: number, gc_time: number }>}
*/
const run_benchmark = (label) => {
return new Promise((fulfil, reject) => {
const child = fork(filename, [], {
env: {
...process.env,
BENCH_SINGLE: label
}
});
/** @type {{ time: number, gc_time: number } | null} */
let result = null;
child.on('message', (message) => {
result = /** @type {{ time: number, gc_time: number }} */ (message);
});
child.on('error', reject);
child.on('exit', (code) => {
if (result === null) {
reject(new Error(`benchmark ${label} exited with code ${code}`));
} else {
fulfil(result);
}
});
});
};
const COLUMN_WIDTHS = [25, 9, 9];
const TOTAL_WIDTH = COLUMN_WIDTHS.reduce((a, b) => a + b);
/** @type {(str: string, n: number) => string} */
const pad_right = (str, n) => str + ' '.repeat(n - str.length);
/** @type {(str: string, n: number) => string} */
const pad_left = (str, n) => ' '.repeat(n - str.length) + str;
let total_time = 0;
let total_gc_time = 0;
try {
for (const { benchmarks, name } of suites) {
let suite_time = 0;
let suite_gc_time = 0;
console.log(`\nRunning ${name}...\n`);
console.log(
pad_right('Benchmark', COLUMN_WIDTHS[0]) +
pad_left('Time', COLUMN_WIDTHS[1]) +
pad_left('GC time', COLUMN_WIDTHS[2])
);
console.log('='.repeat(TOTAL_WIDTH));
for (const benchmark of benchmarks) {
const results = await run_benchmark(benchmark.label);
console.log(
pad_right(benchmark.label, COLUMN_WIDTHS[0]) +
pad_left(results.time.toFixed(2), COLUMN_WIDTHS[1]) +
pad_left(results.gc_time.toFixed(2), COLUMN_WIDTHS[2])
);
total_time += results.time;
total_gc_time += results.gc_time;
suite_time += results.time;
suite_gc_time += results.gc_time;
}
console.log('='.repeat(TOTAL_WIDTH));
console.log(
pad_right('suite', COLUMN_WIDTHS[0]) +
pad_left(suite_time.toFixed(2), COLUMN_WIDTHS[1]) +
pad_left(suite_gc_time.toFixed(2), COLUMN_WIDTHS[2])
);
console.log('='.repeat(TOTAL_WIDTH));
}
console.log(`\nCPU profiles written to ${PROFILE_DIR}`);
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
process.exit(1);
}
console.log('');
console.log(
pad_right('total', COLUMN_WIDTHS[0]) +
pad_left(total_time.toFixed(2), COLUMN_WIDTHS[1]) +
pad_left(total_gc_time.toFixed(2), COLUMN_WIDTHS[2])
);
}