import { performance } from 'node:perf_hooks' function percentile(sorted, p) { if (sorted.length === 0) return 0 const idx = Math.min(sorted.length - 1, Math.floor(sorted.length * p)) return sorted[idx] } export function getBenchOptions() { const runs = Number.parseInt(process.env.BENCH_RUNS ?? '8', 10) const warmup = Number.parseInt(process.env.BENCH_WARMUP ?? '2', 10) return { runs: Number.isFinite(runs) && runs > 1 ? runs : 8, warmup: Number.isFinite(warmup) && warmup >= 0 ? warmup : 2, } } export async function measure(name, fn, options) { const times = [] for (let i = 0; i < options.runs; i++) { const t0 = performance.now() await fn() const dt = performance.now() - t0 if (i >= options.warmup) { times.push(dt) } } times.sort((a, b) => a - b) const mean = times.reduce((sum, value) => sum + value, 0) / Math.max(1, times.length) return { name, samples: times.length, mean, min: times[0] ?? 0, p50: percentile(times, 0.5), p95: percentile(times, 0.95), max: times[times.length - 1] ?? 0, } } export function printResults(title, results, options) { console.log(`\n${title}`) console.log(`runs=${options.runs} warmup=${options.warmup} measured=${Math.max(0, options.runs - options.warmup)}`) for (const row of results) { console.log( `${row.name.padEnd(32)} n=${String(row.samples).padStart(2)} mean=${row.mean.toFixed(1)}ms ` + `p50=${row.p50.toFixed(1)}ms p95=${row.p95.toFixed(1)}ms min=${row.min.toFixed(1)}ms max=${row.max.toFixed(1)}ms` ) } }