// Benchmark the generated debug writer the way Pi startup exercises it: // one fresh module copy per extension, enabled through user settings, logging // against already-existing private directories. Prints Go benchmark lines. // Usage: node pi-ext-debug.bench.mjs [template.ts] import { spawnSync } from "node:child_process"; import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from "node:fs"; import { tmpdir } from "node:os"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; const EXTENSIONS = 40; const ROUNDS = Number(process.env.PI_EXT_DEBUG_BENCH_ROUNDS ?? 30); const WARM_RECORDS = 2_000; const here = dirname(fileURLToPath(import.meta.url)); if (process.argv[2] === "--child") { const [, , , moduleDir] = process.argv; const started = process.hrtime.bigint(); const loaded = []; for (let index = 0; index < EXTENSIONS; index++) { const module = await import( pathToFileURL(join(moduleDir, `ext-${index}.ts`)).href ); const debug = module.defineDebug({ events: ["session.start", "session.shutdown"], spans: ["catalog.refresh"], fields: { count: "number", network: "boolean", outcome: ["ok"] }, }); debug.dbg?.("session.start", { count: index }); for (let refresh = 0; refresh < 2; refresh++) debug.span?.("catalog.refresh", { network: false })("finish", { outcome: "ok", }); loaded.push(debug); } const startup = process.hrtime.bigint() - started; const [first] = loaded; const warmStarted = process.hrtime.bigint(); for (let index = 0; index < WARM_RECORDS; index++) first.dbg?.("session.start", { count: index }); const warm = (process.hrtime.bigint() - warmStarted) / BigInt(WARM_RECORDS); for (const debug of loaded) debug.closeDebug(); console.log(`${startup} ${warm}`); process.exit(0); } const template = resolve( process.argv[2] ?? join(here, "templates", "pi-ext-debug.ts"), ); const root = mkdtempSync(join(tmpdir(), "pi-ext-debug-bench-")); try { const moduleDir = join(root, "modules"); mkdirSync(moduleDir); const source = readFileSync(template, "utf8"); for (let index = 0; index < EXTENSIONS; index++) writeFileSync( join(moduleDir, `ext-${index}.ts`), source.replaceAll("{{extension-slug}}", `bench-${index}`), ); const agentDir = join(root, "agent"); mkdirSync(agentDir); // Realistic user settings size (~4.5 KB) with global debug selection. writeFileSync( join(agentDir, "settings.json"), JSON.stringify({ "pi-ext": { debug: true }, padding: Array.from({ length: 60 }, (_, index) => ({ key: `setting-${index}`, value: "x".repeat(48), })), }), ); const env = { ...process.env, HOME: join(root, "home"), XDG_STATE_HOME: join(root, "state"), PI_CODING_AGENT_DIR: agentDir, }; const run = () => { const result = spawnSync( process.execPath, [ "--no-warnings", "--experimental-strip-types", fileURLToPath(import.meta.url), "--child", moduleDir, ], { env, encoding: "utf8" }, ); if (result.status !== 0) throw new Error(result.stderr); return result.stdout.trim().split(" "); }; // First run creates the directories; later runs match normal startups. for (let index = 0; index < 3; index++) run(); console.log(`goos: ${process.platform}`); console.log(`goarch: ${process.arch}`); console.log("pkg: pi-ext/debug"); for (let round = 0; round < ROUNDS; round++) { const [startup, warm] = run(); console.log(`BenchmarkDebugStartup${EXTENSIONS}\t1\t${startup} ns/op`); console.log(`BenchmarkDebugRecordWarm\t${WARM_RECORDS}\t${warm} ns/op`); } } finally { rmSync(root, { recursive: true, force: true }); }