import fs from 'fs'; const results = []; async function bench(name, fn, options = {}) { const iterations = options.iterations || 1; const warmup = options.warmup || 0; const unit = options.unit || 'ops/s'; const itemsPerIter = options.itemsPerIter || null; for (let i = 0; i < warmup; i++) { await fn(); } let totalTime = 0; for (let i = 0; i < iterations; i++) { const start = process.hrtime.bigint(); await fn(); const end = process.hrtime.bigint(); totalTime += Number(end - start) / 1e6; } const avgTime = totalTime / iterations; const iterPerSec = 1000 / avgTime; const itemsPerSec = itemsPerIter ? Math.round(iterPerSec * itemsPerIter) : null; const resultEntry = { name, avgTimeMs: parseFloat(avgTime.toFixed(3)), iterPerSec: Math.round(iterPerSec), itemsPerSec, unit, itemsPerIter, samples: iterations, timestamp: new Date().toISOString() }; results.push(resultEntry); return resultEntry; } async function run(options = {}) { const outputFile = options.output || './benchmark-results.json'; const threshold = options.regressionThreshold || 0.9; const output = { timestamp: new Date().toISOString(), package: process.env.npm_package_name || 'unknown', version: process.env.npm_package_version || '0.0.0', node: process.version, benchmarks: results }; if (fs.existsSync(outputFile)) { const previous = JSON.parse(fs.readFileSync(outputFile, 'utf8')); if (previous.benchmarks) { for (const newBench of results) { const prev = previous.benchmarks.find(b => b.name === newBench.name); if (prev) { const ratio = newBench.iterPerSec / prev.iterPerSec; newBench.regression = ratio < threshold; newBench.comparedToPrevious = { iterPerSec: prev.iterPerSec, ratio: parseFloat(ratio.toFixed(4)) }; } } } } const regression = results.some(b => b.regression); console.log('\nBenchmark Results:'); console.log('-'.repeat(90)); console.log(`${'Benchmark'.padEnd(50)} ${'Iter/s'.padStart(10)} ${'Items/s'.padStart(12)} Unit`); console.log('-'.repeat(90)); for (const r of results) { const reg = r.regression ? ' [REGRESSION]' : ''; const prev = r.comparedToPrevious ? ` (prev: ${r.comparedToPrevious.iterPerSec}, ratio: ${r.comparedToPrevious.ratio})` : ''; const itemsRate = r.itemsPerSec ? r.itemsPerSec.toString().padStart(12) : ' -'; console.log(`${r.name.padEnd(50)} ${r.iterPerSec.toString().padStart(10)} ${itemsRate} ${r.unit}${reg}${prev}`); } console.log('-'.repeat(90)); if (outputFile) { fs.writeFileSync(outputFile, JSON.stringify(output, null, 2)); console.log(`\nResults saved to: ${outputFile}`); } if (regression) { console.error('\nWARNING: Performance regression detected!'); process.exit(1); } return results; } export { bench, run };