mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
* test: reproduce accumulated-workspace typing latency through real PTYs * test: make the bench harness self-checks falsifiable Review found four assertions that could not fail and one fixture gap: - `missingPtyArrivalCount`/`missingEchoCount` were hardcoded `0` and `validateExpectedSeqs` throws before them, so every assertion on them was vacuous and every report read `0`. The throw is the real guard and is already covered; drop the vestigial fields. - An absent status controller returned an all-zero result, which satisfied its own accepted-equals-generated equality. Assert presence first. - The byte-pacing control had only an upper bound, so a generator emitting no stream bytes passed. Add the lower bound. - `lineageEvery: 1` built zero lineage: no ordinal satisfies `% 1 === 1`. Offset the interval and cover the densest setting. - The documented control command never set ORCA_TYPING_BENCH, so it skipped instead of running.
208 lines
7.9 KiB
TypeScript
208 lines
7.9 KiB
TypeScript
import { randomUUID } from 'node:crypto'
|
|
import { mkdirSync, rmSync, writeFileSync } from 'node:fs'
|
|
import path from 'node:path'
|
|
import { test, expect } from './helpers/orca-app'
|
|
import { ensureTerminalVisible, waitForSessionReady } from './helpers/store'
|
|
import { sendToTerminal, waitForActivePanePtyId, waitForTerminalOutput } from './helpers/terminal'
|
|
import { measurePacedTyping } from './paced-terminal-typing'
|
|
import {
|
|
typingProbeReadyMarker,
|
|
writeTypingEchoProbeScript
|
|
} from './sustained-agent-typing-load-scripts'
|
|
import {
|
|
createSpinnerRepository,
|
|
refreshSpinnerAgents,
|
|
seedSpinnerWorkspaces,
|
|
startSpinnerStatusTraffic
|
|
} from './spinner-workspace-fixture'
|
|
import { collectRendererCensus } from '../../config/scripts/idle-cpu-renderer-scale-fixture.mjs'
|
|
import {
|
|
setSpinnerVariant,
|
|
spinnerCensus
|
|
} from '../tools/benchmarks/spinner-rendering/app-variants.mjs'
|
|
import { sampleCpu } from '../tools/benchmarks/spinner-rendering/sample-cpu.mjs'
|
|
import { traceIterations } from '../tools/benchmarks/spinner-rendering/trace-iterations.mjs'
|
|
|
|
const enabled = process.env.ORCA_SPINNER_BENCH === '1'
|
|
const sampleMs = Number(process.env.ORCA_SPINNER_SAMPLE_MS ?? 10000)
|
|
const rounds = Number(process.env.ORCA_SPINNER_ROUNDS ?? 4)
|
|
const keyCount = Number(process.env.ORCA_SPINNER_KEYS ?? 48)
|
|
// Avoid phase-locking keystrokes to the 200 ms status burst or 60 Hz frames.
|
|
const keyCadenceMs = Number(process.env.ORCA_SPINNER_KEY_CADENCE_MS ?? 113)
|
|
const variants = (process.env.ORCA_SPINNER_VARIANTS ?? 'original,long').split(',')
|
|
if (enabled) {
|
|
for (const [name, value, minimum] of [
|
|
['sample duration', sampleMs, 1000],
|
|
['rounds', rounds, 1],
|
|
['keys', keyCount, 0],
|
|
['key cadence', keyCadenceMs, 1]
|
|
] as const) {
|
|
if (!Number.isInteger(value) || value < minimum) {
|
|
throw new Error(`Invalid spinner benchmark ${name}: ${value}`)
|
|
}
|
|
}
|
|
}
|
|
const scenarios = [
|
|
{ name: 'one-agent', worktrees: 1, lineageDepth: 0, agentsPerWorktree: 1, subagentsPerAgent: 0 },
|
|
{ name: 'one-family', worktrees: 1, lineageDepth: 0, agentsPerWorktree: 2, subagentsPerAgent: 2 },
|
|
{ name: '200-flat', worktrees: 200, lineageDepth: 0, agentsPerWorktree: 2, subagentsPerAgent: 2 },
|
|
{
|
|
name: '200-lineage',
|
|
worktrees: 200,
|
|
lineageDepth: 2,
|
|
agentsPerWorktree: 2,
|
|
subagentsPerAgent: 2
|
|
}
|
|
]
|
|
|
|
test.use({
|
|
seedTestRepo: false,
|
|
orcaAppExtraEnv: { ORCA_BACKGROUND_LAUNCH: '1' },
|
|
orcaAppExtraArgs: [
|
|
'--disable-backgrounding-occluded-windows',
|
|
'--disable-renderer-backgrounding'
|
|
],
|
|
trace: 'off',
|
|
screenshot: 'off'
|
|
})
|
|
test.skip(!enabled, 'Opt-in performance benchmark')
|
|
|
|
for (const scenario of scenarios) {
|
|
test(`spinner performance ${scenario.name}`, async ({
|
|
electronApp,
|
|
orcaPage: page,
|
|
registerPostElectronShutdownCleanup
|
|
}, testInfo) => {
|
|
test.setTimeout(900_000)
|
|
const output = path.resolve(process.env.ORCA_SPINNER_OUTPUT ?? '.bench-fixtures/spinner-app')
|
|
mkdirSync(output, { recursive: true })
|
|
const fixture = await createSpinnerRepository(scenario.worktrees)
|
|
registerPostElectronShutdownCleanup(async () =>
|
|
rmSync(fixture.directory, { recursive: true, force: true })
|
|
)
|
|
await waitForSessionReady(page)
|
|
await electronApp.evaluate(({ BrowserWindow }) => {
|
|
const window = BrowserWindow.getAllWindows()[0]
|
|
window.webContents.setBackgroundThrottling(false)
|
|
window.setSize(1280, 900)
|
|
})
|
|
await page.emulateMedia({ reducedMotion: 'no-preference' })
|
|
const seeded = await seedSpinnerWorkspaces(page, fixture.repoPath, scenario)
|
|
await ensureTerminalVisible(page)
|
|
await page.waitForTimeout(10000)
|
|
await expect(page.locator('[data-worktree-sidebar] [data-agent-spinner]').first()).toBeVisible()
|
|
const census = await collectRendererCensus(page, scenario.lineageDepth)
|
|
const rings = await spinnerCensus(page)
|
|
expect(census.worktrees.store).toBe(scenario.worktrees)
|
|
expect(census.agentRows.storeLive).toBeGreaterThanOrEqual(
|
|
scenario.worktrees * scenario.agentsPerWorktree
|
|
)
|
|
if (scenario.subagentsPerAgent) {
|
|
expect(rings.workingSubagentRows).toBeGreaterThan(0)
|
|
}
|
|
if (scenario.lineageDepth) {
|
|
expect(census.worktrees.mountedUnique).toBe(scenario.worktrees)
|
|
}
|
|
const report = {
|
|
benchmark: 'working-spinner-workspaces',
|
|
createdAt: new Date().toISOString(),
|
|
scenario,
|
|
options: { sampleMs, rounds, keyCount, keyCadenceMs, variants },
|
|
seeded,
|
|
census,
|
|
rings,
|
|
versions: await electronApp.evaluate(() => process.versions),
|
|
traces: [] as unknown[],
|
|
samples: [] as unknown[],
|
|
typing: [] as unknown[]
|
|
}
|
|
const save = () =>
|
|
writeFileSync(
|
|
path.join(output, `${scenario.name}.json`),
|
|
`${JSON.stringify(report, null, 2)}\n`
|
|
)
|
|
save()
|
|
console.log(
|
|
JSON.stringify({
|
|
scenario: scenario.name,
|
|
rings,
|
|
mountedWorkspaces: census.worktrees.mountedUnique
|
|
})
|
|
)
|
|
const cdp = await page.context().newCDPSession(page)
|
|
await cdp.send('Performance.enable')
|
|
for (let round = 0; round < (process.env.ORCA_SPINNER_CPU === '0' ? 0 : rounds); round++) {
|
|
const order = round % 2 ? variants.toReversed() : variants
|
|
for (const variant of order) {
|
|
await setSpinnerVariant(page, variant)
|
|
await refreshSpinnerAgents(page)
|
|
await page.waitForTimeout(1500)
|
|
const before = await spinnerCensus(page)
|
|
const sample = { variant, round, before, ...(await sampleCpu(electronApp, cdp, sampleMs)) }
|
|
const after = await spinnerCensus(page)
|
|
expect(after.mounted).toBe(before.mounted)
|
|
report.samples.push(sample)
|
|
save()
|
|
console.log(JSON.stringify({ scenario: scenario.name, ...sample }))
|
|
if (round === rounds - 1) {
|
|
const trace = await traceIterations(
|
|
cdp,
|
|
path.join(output, `${scenario.name}-${variant}-trace.json`)
|
|
)
|
|
report.traces.push({ variant, ...trace })
|
|
save()
|
|
}
|
|
}
|
|
}
|
|
const ptyId = await waitForActivePanePtyId(page)
|
|
for (let round = 0; round < Math.min(rounds, 2); round++) {
|
|
for (const variant of round % 2 ? variants.toReversed() : variants) {
|
|
if (keyCount === 0) {
|
|
continue
|
|
}
|
|
await setSpinnerVariant(page, variant)
|
|
await refreshSpinnerAgents(page)
|
|
const runId = randomUUID()
|
|
const scriptPath = path.join(fixture.repoPath, `spinner-typing-${runId}.mjs`)
|
|
const sidecarPath = path.join(output, `typing-${runId}.jsonl`)
|
|
writeTypingEchoProbeScript(scriptPath, runId, sidecarPath)
|
|
await sendToTerminal(page, ptyId, `node ${path.basename(scriptPath)}\r`)
|
|
await waitForTerminalOutput(page, typingProbeReadyMarker(runId), 15000)
|
|
const traffic = await startSpinnerStatusTraffic(page)
|
|
try {
|
|
await page.waitForTimeout(2000)
|
|
const measurement = await measurePacedTyping(page, runId, sidecarPath, {
|
|
keyCount,
|
|
keyCadenceMs
|
|
})
|
|
report.typing.push({ variant, round, measurement })
|
|
save()
|
|
console.log(
|
|
JSON.stringify({
|
|
scenario: scenario.name,
|
|
variant,
|
|
typing: measurement.totalMs,
|
|
input: measurement.inputHalfMs
|
|
})
|
|
)
|
|
} finally {
|
|
await traffic.evaluate((probe) => probe.stop())
|
|
await traffic.dispose()
|
|
await sendToTerminal(page, ptyId, '\x03')
|
|
}
|
|
}
|
|
}
|
|
await setSpinnerVariant(page, 'long')
|
|
await page.screenshot({ path: path.join(output, `${scenario.name}.png`) })
|
|
expect(
|
|
await electronApp.evaluate(({ BrowserWindow }) =>
|
|
BrowserWindow.getAllWindows().every((window) => !window.isVisible() && !window.isFocused())
|
|
)
|
|
).toBe(true)
|
|
await testInfo.attach('spinner-benchmark', {
|
|
path: path.join(output, `${scenario.name}.json`),
|
|
contentType: 'application/json'
|
|
})
|
|
})
|
|
}
|