Files
orca/config/scripts/main-blocking-probe.mjs
T
JinjingandJinwoo-H d2d32691ef perf(persistence): skip redundant whole-state flushes on terminal reattach (#20137)
* perf(persistence): add pty-binding fast lane to skip redundant flushes

Terminal pane reattachment currently clones the session and serializes the
entire 9.2 MB app state even when the binding is already in place and durable.
Add an early-return fast path that skips this work when all nine predicates
hold: no split, binding matches in-memory and on-disk, incarnation matches,
no tombstone, and generation counter proves durability.

Includes one-line fix in `writeToDiskSync` to record hash-matched sync flushes
as durable, so the fast path doesn't stay parked behind a stale generation.

Adds `persistence.pty-binding` observability spans (local NDJSON, unsampled for
mutations, budgeted for fast-lane hits) to measure eligibility rates before
and after. Includes ratchet test to ensure every binding writer bumps the
generation. Diagnostic tools and full investigation notes from September 7,
2026 capture that identified the 59–100 ms no-op binds and measured a real
terminal keystroke queued 117 ms behind one such call.

* perf(persistence): add pty-binding fast lane to skip redundant flushes

Rapid rebinds of already-durable PTY bindings (e.g., remounting panes)
were unnecessarily expensive because they cloned and flushed the entire
document state every time. Detect when a binding hasn't changed since the
last durable write and skip to return immediately, eliminating main-thread
cost on that path.

* perf(persistence): record binding.origin on the pty-binding span

Fresh spawns always flush, so a fast-lane rate over all calls is diluted
by however many terminals the user opened. Each caller knows whether it
is a spawn, a reattach, a split, or a relay reattach; pass that through
as metadata and record it so the reattach hit rate can be read from the
trace file. Never branched on.

* fix(persistence): keep the tab row on its first pane when a sibling pane binds

A tab row names one PTY, but a split tab holds several panes. The
renderer keeps the row on the first pane and refuses to let later
split-pane spawns steal it, since a remount reattaches the tab to
whatever the row says. Main overwrote it with whichever pane was binding,
and the renderer's next publish put it back, so every sibling reattach
was a state change and could never take the fast lane. On the real
profile that is 38% of panes.

Rewrite the row only when it names nothing useful: null, the PTY this
leaf is replacing, or a PTY no leaf holds. The fast-lane predicate
compares against the same rule.

* perf(persistence): record durable pty-binding flushes per pane

The global write generation is held back by any unrelated dirty
state, causing bindings unchanged for minutes to appear unpersisted
despite being on disk. Track per-pane durability to skip redundant
flushes.

* docs(persistence): describe the per-pane durability record

The durability section still described the global generation check as the
whole story and claimed there was no binding durability cache. Record the
measurement that motivated the per-pane record, and why retiring one needs
no cooperation from other binding writers.

* docs(perf): consolidate every measured Orca performance issue into one register

Folds the findings from all related debug sessions into the live lag
investigation: the persistence/main-thread work (P1-P11), host contention
(H1-H5), git and subprocess load on main (G1-G8), renderer and terminal
rendering (R1-R8), the terminal daemon session leak from the deleted
debug-orca-perf-issue worktree (D1-D9), and the Cmd-J palette review (C1-C6).

Keeps the measurement behind each claim, records what is fixed versus open,
and restates what the 117 ms keystroke delay still does not explain.

* fix: address performance review findings

* fix: satisfy diagnostic probe lint

* chore: keep investigation artifacts out of performance PR

* fix: run lag probe regression tests with Vitest

* perf(persistence): replace pane receipts with global durability check

* refactor(persistence): remove redundant binding review machinery

* test(persistence): satisfy current assertion-free quality gate

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
2026-09-14 01:04:43 -04:00

121 lines
3.5 KiB
JavaScript

export function installMainBlockingProbe() {
if (globalThis.__orcaMainBlockingProbe) {
throw new Error('Main blocking probe already exists')
}
const events = []
const cleanup = []
const startedAt = Date.now()
function wrap(object, name, label, sizeOf) {
const original = object[name]
const wrapped = function (...args) {
const start = performance.now()
const epoch = Date.now()
let result
try {
result = Reflect.apply(original, this, args)
return result
} finally {
const durationMs = performance.now() - start
if (durationMs >= 8 && events.length < 2000) {
events.push({
epoch,
durationMs,
label,
size: sizeOf?.(args, result) ?? null,
stack: new Error('Main blocking call').stack?.split('\n').slice(2, 10)
})
}
}
}
object[name] = wrapped
cleanup.push(() => {
if (object[name] === wrapped) {
object[name] = original
}
})
}
wrap(JSON, 'stringify', 'JSON.stringify', (_args, result) => result?.length)
wrap(globalThis, 'structuredClone', 'structuredClone')
wrap(Buffer, 'from', 'Buffer.from', (args) => args[0]?.length)
const hashPrototype = Object.getPrototypeOf(
process.getBuiltinModule('crypto').createHash('sha256')
)
wrap(hashPrototype, 'update', 'hash.update', (args) => args[0]?.length)
const fs = process.getBuiltinModule('fs')
for (const name of ['existsSync', 'accessSync', 'writeFileSync', 'fsyncSync', 'renameSync']) {
wrap(fs, name, name)
}
const timerGaps = []
let previous = performance.now()
const timer = setInterval(() => {
const now = performance.now()
const gap = now - previous - 25
previous = now
if (gap > 20 && timerGaps.length < 2000) {
timerGaps.push({ epoch: Date.now(), gapMs: gap })
}
}, 25)
timer.unref()
globalThis.__orcaMainBlockingProbe = {
stop() {
clearInterval(timer)
for (const restore of cleanup.toReversed()) {
restore()
}
delete globalThis.__orcaMainBlockingProbe
return { startedAt, endedAt: Date.now(), events, timerGaps }
}
}
return { startedAt }
}
export function installRendererIpcProbe() {
if (window.__orcaIpcTimingProbe) {
throw new Error('Renderer IPC probe already exists')
}
const requests = []
const keys = []
let pending = false
let stopped = false
const timer = setInterval(async () => {
if (pending || stopped) {
return
}
pending = true
const start = performance.now()
const epoch = Date.now()
try {
await window.api.app.getIdentity()
if (requests.length < 2000) {
requests.push({ epoch, durationMs: performance.now() - start })
}
} catch (error) {
if (requests.length < 2000) {
requests.push({ epoch, durationMs: performance.now() - start, failed: String(error) })
}
} finally {
pending = false
}
}, 100)
const keydown = (event) => {
if (keys.length < 1000) {
keys.push({
epoch: Date.now(),
queueMs: performance.now() - event.timeStamp,
terminal: !!event.target?.closest?.('.xterm'),
trusted: event.isTrusted
})
}
}
document.addEventListener('keydown', keydown, true)
window.__orcaIpcTimingProbe = {
stop() {
stopped = true
clearInterval(timer)
document.removeEventListener('keydown', keydown, true)
delete window.__orcaIpcTimingProbe
return { requests, keys }
}
}
}