#!/usr/bin/env node // Terminal interaction latency benchmark: tab creation, tab switching, and // workspace switching against the real Electron dev app over CDP. Produces // median/p95 phase timings so Windows terminal slowness can be attributed to // store work, PTY spawn, shell startup, or renderer paint — not guessed at. import { execFileSync } from 'node:child_process' import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs' import os from 'node:os' import path from 'node:path' import process from 'node:process' import { fileURLToPath } from 'node:url' import { collectRendererDiagnostics, connectToApp, createGpuUserDataDirectory, installRendererProbe, launchDevApp, pickFreePort, stopDevApp, waitForStoreReady } from '../../config/scripts/windows-apphang-repro/electron-dev-session.mjs' import { pollUntil, rendererActionTimeoutMs, runWithTimeout, setupTimeoutMs } from '../../config/scripts/windows-apphang-repro/repro-timing.mjs' import { safeRemoveLocalDirectory } from '../../config/scripts/windows-apphang-repro/wsl-workspace-fixture.mjs' const rootDir = path.resolve(fileURLToPath(new URL('../..', import.meta.url))) const scenarioTimeoutMs = 300_000 const defaultIterations = 8 const defaultSwitches = 24 const defaultCycles = 12 function parseArgs() { const args = { label: 'run', iterations: defaultIterations, switches: defaultSwitches, cycles: defaultCycles, shell: null, scenarios: ['tab-create', 'tab-switch', 'workspace-switch'], reportPath: null, keep: false } for (const arg of process.argv.slice(2)) { if (arg === '--help' || arg === '-h') { printHelp() process.exit(0) } if (arg === '--keep') { args.keep = true continue } const [name, value] = arg.split('=', 2) if (name === '--label') { args.label = value?.trim() || 'run' continue } if (name === '--iterations') { args.iterations = parsePositiveInt(name, value) continue } if (name === '--switches') { args.switches = parsePositiveInt(name, value) continue } if (name === '--cycles') { args.cycles = parsePositiveInt(name, value) continue } if (name === '--shell') { args.shell = value?.trim() || null continue } if (name === '--scenarios') { const scenarios = (value ?? '') .split(',') .map((entry) => entry.trim()) .filter(Boolean) const known = new Set(['tab-create', 'tab-switch', 'workspace-switch']) if (scenarios.length === 0 || scenarios.some((scenario) => !known.has(scenario))) { throw new Error( `Unsupported --scenarios=${value}. Use tab-create,tab-switch,workspace-switch.` ) } args.scenarios = scenarios continue } if (name === '--report') { args.reportPath = value?.trim() || null continue } throw new Error(`Unknown argument: ${arg}`) } return args } function printHelp() { console.log(`Usage: node tools/benchmarks/terminal-perf-bench.mjs [options] Options: --label=NAME Label recorded in the report filename/JSON. Default: run. --iterations=N Terminal tab create/close iterations. Default: ${defaultIterations}. --switches=N Tab switch alternations. Default: ${defaultSwitches}. --cycles=N Workspace switch cycles. Default: ${defaultCycles}. --shell=PATH Shell override for created tabs (e.g. cmd.exe). Default: app default. --scenarios=a,b Subset of tab-create,tab-switch,workspace-switch. --report=PATH Report JSON path. Default: tools/benchmarks/results/terminal-perf-