From e080f399ca0182ef60628f06684df2e246002172 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 3 Apr 2026 13:15:49 -0400 Subject: [PATCH] break out report generation --- benchmarking/compare/generate-report.js | 81 +++++++++++++++++++++++++ benchmarking/compare/index.js | 70 +-------------------- 2 files changed, 83 insertions(+), 68 deletions(-) create mode 100644 benchmarking/compare/generate-report.js diff --git a/benchmarking/compare/generate-report.js b/benchmarking/compare/generate-report.js new file mode 100644 index 0000000000..a61f58909b --- /dev/null +++ b/benchmarking/compare/generate-report.js @@ -0,0 +1,81 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; + +export function generate_report(outdir) { + const result_files = fs + .readdirSync(outdir) + .filter((file) => file.endsWith('.json')) + .sort((a, b) => a.localeCompare(b)); + + const branches = result_files.map((file) => file.slice(0, -5)); + const results = result_files.map((file) => + JSON.parse(fs.readFileSync(`${outdir}/${file}`, 'utf-8')) + ); + + if (results.length === 0) { + console.error(`No result files found in ${outdir}`); + process.exit(1); + } + + const report_file = path.join(outdir, 'report.txt'); + + fs.writeFileSync(report_file, ''); + + const write = (str) => { + fs.appendFileSync(report_file, str + '\n'); + console.log(str); + }; + + for (let i = 0; i < branches.length; i += 1) { + write(`${char(i)}: ${branches[i]}`); + } + + write(''); + + for (let i = 0; i < results[0].length; i += 1) { + write(`${results[0][i].benchmark}`); + + for (const metric of ['time', 'gc_time']) { + const times = results.map((result) => +result[i][metric]); + let min = Infinity; + let max = -Infinity; + let min_index = -1; + + for (let b = 0; b < times.length; b += 1) { + const time = times[b]; + + if (time < min) { + min = time; + min_index = b; + } + + if (time > max) { + max = time; + } + } + + if (min !== 0) { + write(` ${metric}: fastest is ${char(min_index)} (${branches[min_index]})`); + times.forEach((time, b) => { + const SIZE = 20; + const n = Math.round(SIZE * (time / max)); + + write(` ${char(b)}: ${'◼'.repeat(n)}${' '.repeat(SIZE - n)} ${time.toFixed(2)}ms`); + }); + } + } + + write(''); + } +} + +function char(i) { + return String.fromCharCode(97 + i); +} + +if (import.meta.url === pathToFileURL(process.argv[1]).href) { + const outdir = path.resolve(process.argv[1], '../.results'); + + generate_report(outdir); +} diff --git a/benchmarking/compare/index.js b/benchmarking/compare/index.js index 100d98a767..9064ee7da9 100644 --- a/benchmarking/compare/index.js +++ b/benchmarking/compare/index.js @@ -3,6 +3,7 @@ import path from 'node:path'; import { execSync, fork } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { safe } from '../utils.js'; +import { generate_report } from './generate-report.js'; // if (execSync('git status --porcelain').toString().trim()) { // console.error('Working directory is not clean'); @@ -12,7 +13,6 @@ import { safe } from '../utils.js'; const filename = fileURLToPath(import.meta.url); const runner = path.resolve(filename, '../runner.js'); const outdir = path.resolve(filename, '../.results'); -const report_file = `${outdir}/report.txt`; fs.mkdirSync(outdir, { recursive: true }); @@ -85,70 +85,4 @@ if (PROFILE_DIR !== null) { console.log(`\nCPU profiles written to ${PROFILE_DIR}`); } -const result_files = fs - .readdirSync(outdir) - .filter((file) => file.endsWith('.json')) - .sort((a, b) => a.localeCompare(b)); - -const branches = result_files.map((file) => file.slice(0, -5)); -const results = result_files.map((file) => - JSON.parse(fs.readFileSync(`${outdir}/${file}`, 'utf-8')) -); - -if (results.length === 0) { - console.error(`No result files found in ${outdir}`); - process.exit(1); -} - -fs.writeFileSync(report_file, ''); - -const write = (str) => { - fs.appendFileSync(report_file, str + '\n'); - console.log(str); -}; - -for (let i = 0; i < branches.length; i += 1) { - write(`${char(i)}: ${branches[i]}`); -} - -write(''); - -for (let i = 0; i < results[0].length; i += 1) { - write(`${results[0][i].benchmark}`); - - for (const metric of ['time', 'gc_time']) { - const times = results.map((result) => +result[i][metric]); - let min = Infinity; - let max = -Infinity; - let min_index = -1; - - for (let b = 0; b < times.length; b += 1) { - const time = times[b]; - - if (time < min) { - min = time; - min_index = b; - } - - if (time > max) { - max = time; - } - } - - if (min !== 0) { - write(` ${metric}: fastest is ${char(min_index)} (${branches[min_index]})`); - times.forEach((time, b) => { - const SIZE = 20; - const n = Math.round(SIZE * (time / max)); - - write(` ${char(b)}: ${'◼'.repeat(n)}${' '.repeat(SIZE - n)} ${time.toFixed(2)}ms`); - }); - } - } - - write(''); -} - -function char(i) { - return String.fromCharCode(97 + i); -} +generate_report(outdir);