// Throughput and peak RSS over a JSON array of sources, one tool per process. // Usage: node bench/throughput.mjs [tool-substring] [--mode=downlevel] import fs from "node:fs"; import { execFileSync } from "node:child_process"; import { tools } from "./tools.mjs"; const [inputsPath, only] = process.argv.slice(2).filter((a) => !a.startsWith("--")); const mode = process.argv.find((a) => a.startsWith("--mode="))?.slice(7) ?? "erase"; if (process.env.TP_WORKER) { const inputs = JSON.parse(fs.readFileSync(inputsPath, "utf8")); const tool = tools[process.env.TP_WORKER]; let strip = await tool.load(); if (mode === "downlevel" && tool.downlevel) strip = await tool.downlevel(); const bytes = inputs.reduce((n, s) => n + Buffer.byteLength(s), 0); let failed = 0; const pass = () => { failed = 0; for (const s of inputs) { try { strip(s); } catch { failed++; } } }; // maxRSS already peaked while parsing the inputs, so sample current RSS per file instead. globalThis.gc(); const before = process.memoryUsage.rss(); let peak = before; for (const s of inputs) { try { strip(s); } catch {} const r = process.memoryUsage.rss(); if (r > peak) peak = r; } const times = []; for (let i = 0; i < 3; i++) { const t = performance.now(); pass(); times.push(performance.now() - t); } const ms = times.sort((a, b) => a - b)[1]; console.log(JSON.stringify({ mbps: bytes / 1e6 / (ms / 1000), peakDeltaMiB: (peak - before) / 1048576, failed, files: inputs.length, mb: bytes / 1e6 })); process.exit(0); } console.log(`mode ${mode}, inputs ${inputsPath}\n`); console.log("| tool | MB/s | peak RSS growth (first pass, sampled per file) | inputs that threw |"); console.log("|---|---|---|---|"); // TP_REVERSE lets a caller alternate tool order across repeated runs, same reason as // bench/metrics.mjs's METRICS_REVERSE. const order = process.env.TP_REVERSE ? Object.entries(tools).reverse() : Object.entries(tools); for (const [name, tool] of order) { if (only && !name.includes(only)) continue; if (mode === "downlevel" && !tool.lowers) continue; const r = JSON.parse(execFileSync(process.execPath, ["--no-warnings", "--expose-gc", import.meta.filename, ...process.argv.slice(2)], { env: { ...process.env, TP_WORKER: name }, maxBuffer: 1 << 24 }).toString().trim().split("\n").pop()); console.log(`| ${name} | ${r.mbps.toFixed(1)} | +${r.peakDeltaMiB.toFixed(1)}MiB | ${r.failed}/${r.files} (${r.mb.toFixed(1)}MB total) |`); }