Files
orca/docs/performance-audit.md
T

8.3 KiB
Raw Blame History

Orca Performance Audit

Audit date: 2026-04-13 Branch: Jinwoo-H/performance-improvement


Tier 1 — High Impact, Low Complexity

# Area Issue File(s) Status
1 Renderer App.tsx has 53 separate Zustand subscriptions — nearly every state change re-renders the root and cascades through the entire tree src/renderer/src/App.tsx:40-180 DONE (53→22 subs, memo barriers on 4 children)
2 Renderer Terminal.tsx has unscoped useAppStore.subscribe() — fires on every store mutation, does O(worktrees×tabs) scan each time src/renderer/src/components/Terminal.tsx:645-659 DONE
3 Terminal No IPC batching — every PTY data chunk is a separate webContents.send call, hundreds/sec under load src/main/ipc/pty.ts:173-177 DONE
4 Terminal Divider drag calls fitAddon.fit() on every pointermove pixel — xterm reflow can take 500ms+ with large scrollback src/renderer/src/lib/pane-manager/pane-divider.ts:90-119 DONE
5 Main Startup blocks: openCodeHookService.start() and runtimeRpc.start() awaited sequentially before window opens src/main/index.ts:131-168 DONE
6 Main persistence.ts uses readFileSync/writeFileSync/renameSync on the main thread — blocks during startup and every 300ms save src/main/persistence.ts:59-125 DONE
7 Worktree worktrees:listAll iterates repos sequentially with await — total time = sum of all repos instead of max src/main/ipc/worktrees.ts:53-84 DONE
8 Browser Reverse Map scan O(N) on every mouse/load/permission event in BrowserManager src/main/browser/browser-manager.ts:91-96 DONE
9 Browser before-mouse-event listener fires for ALL mouse events on ALL guests, even background ones src/main/browser/browser-guest-ui.ts:78-93 DONE
10 Worktree refreshGitHubForWorktree bypasses 5-min cache TTL on every worktree switch — fires GitHub API calls on rapid tab switching src/renderer/src/store/slices/worktrees.ts:467-489 DONE

Tier 2 — Medium Impact

# Area Issue File(s) Status
11 Main git/repo.ts: execSync('gh api user ...') and chains of 5 sync git processes block main thread src/main/git/repo.ts:87-138 TODO
12 Main hooks.ts: readFileSync/writeFileSync/mkdirSync/gitExecFileSync in IPC handlers src/main/hooks.ts:113-416 TODO
13 Renderer useSettings returns entire GlobalSettings (~30+ fields) — any setting change re-renders all consumers src/renderer/src/store/selectors.ts TODO
14 Renderer Tab title changes bump sortEpoch for ALL worktrees → triggers WorktreeList re-sort on every PTY title event src/renderer/src/store/slices/terminals.ts:325 TODO
15 Renderer CacheTimer: one setInterval per mounted card (20 cards = 20 intervals/sec), each with O(n) selector work src/renderer/src/components/sidebar/CacheTimer.tsx:28-48 TODO
16 Renderer Three simultaneous 3-second polling intervals per active worktree (git status, worktrees, stale conflict) src/renderer/src/components/right-sidebar/useGitStatusPolling.ts TODO
17 Renderer 6 components missing React.memo: SourceControl, RightSidebar, EditorPanel, ChecksPanel, FileExplorer, TabBar Various files in src/renderer/src/components/ DONE (8 components wrapped)
18 Worktree Git polling fires immediately on every worktree switch (burst of git status + git worktree list) src/renderer/src/components/right-sidebar/useGitStatusPolling.ts:69-103 REVERTED (150ms debounce caused visible flash on switch)
19 Worktree FileExplorer dirCache discarded on every worktree switch — re-fetches entire tree from scratch src/renderer/src/components/right-sidebar/useFileExplorerTree.ts:27,81-96 TODO
20 Terminal pty:resize uses ipcRenderer.invoke (round-trip) instead of fire-and-forget send src/preload/index.ts:203-205 DONE
21 Terminal Flow control watermarks defined but never enforced for local PTYs — unbounded output floods renderer src/main/providers/local-pty-provider.ts:330-332 TODO
22 Browser BrowserPane subscribes to entire browserPagesByWorkspace map — any tab's navigation re-renders all panes src/renderer/src/components/browser-pane/BrowserPane.tsx:312 TODO
23 Browser findPage/findWorkspace do O(N) Object.values().flat().find() scans on every navigation event src/renderer/src/store/slices/browser.ts:221-240 TODO
24 Browser Download progress IPC fires at full Chromium frequency (many/sec) src/main/browser/browser-manager.ts:421-430 TODO
25 Main detectConflictOperation runs 4 existsSync + readFile on every 3s poll before git status src/main/git/status.ts:236-265 DONE
26 Main getBranchCompare: loadBranchChanges and countAheadCommits run sequentially src/main/git/status.ts:374-375 DONE
27 Main addWorktree calls 4-5 synchronous git processes from IPC handler src/main/git/worktree.ts:116-157 DONE

Tier 3 — Lower Impact / Architectural

# Area Issue File(s) Status
28 Terminal SSH relay FrameDecoder uses Buffer.concat on every chunk (quadratic copy) src/relay/protocol.ts:84 TODO
29 Terminal SSH relay replay buffer uses string concatenation (quadratic allocation) src/relay/pty-handler.ts:68-72 TODO
30 Terminal extractLastOscTitle regex runs on every PTY chunk with no fast-path bail src/shared/agent-detection.ts:23-39 TODO
31 Terminal Binary search calls serialize() up to 16× at shutdown src/renderer/src/components/terminal-pane/TerminalPane.tsx:579-596 TODO
32 Browser capturePage() captures full viewport then crops — should pass rect directly src/main/browser/browser-grab-screenshot.ts:36 TODO
33 Browser Parked webviews retain full 100vw×100vh compositor surfaces src/renderer/src/components/browser-pane/BrowserPane.tsx:94-107 TODO
34 Browser onBeforeSendHeaders intercepts every HTTPS request even when UA override unused src/main/browser/browser-session-registry.ts:126-137 TODO
35 Main setBackgroundThrottling(false) wastes CPU when window is minimized src/main/window/createMainWindow.ts:97 TODO
36 Main warmSystemFontFamilies() competes with startup I/O src/main/system-fonts.ts:30-32 TODO
37 Renderer Session persistence effect has 15 deps — fires on every tab title change src/renderer/src/App.tsx:239-283 TODO
38 Renderer Per-card fetchPRForBranch on mount — 30 worktrees = 30 simultaneous IPC calls src/renderer/src/components/sidebar/WorktreeCard.tsx:128-132 TODO
39 Renderer Synchronous full monaco-editor import blocks EditorPanel chunk evaluation src/renderer/src/components/editor/EditorPanel.tsx:7 TODO
40 Worktree removeWorktree runs git worktree list twice (pre and post removal) src/main/git/worktree.ts:163-208 TODO
41 Worktree worktrees:list can trigger duplicate git worktree list when cache is dirty src/main/ipc/worktrees.ts:86-116 TODO
42 Renderer SSH targets initialized sequentially in a for...await loop src/renderer/src/hooks/useIpcEvents.ts:232-252 TODO

Key Themes

  1. Zustand subscription granularity — App.tsx subscribes to 53 slices, Terminal.tsx subscribes to everything, useSettings returns the full object. Almost any state change cascades through the entire tree.

  2. Synchronous I/O on the main thread — persistence.ts, hooks.ts, git/repo.ts, and git/worktree.ts use readFileSync/writeFileSync/execSync in startup and IPC handler paths.

  3. Unthrottled high-frequency events — PTY data (no IPC batching), divider drag (fit on every pixel), download progress (no throttle), before-mouse-event (all mouse events on all guests), CacheTimer (20 intervals/sec).

  4. Sequential operations that could be parallel — Startup server binds, repo iteration in listAll, git ref probing, loadBranchChanges/countAheadCommits, SSH target init.

  5. Aggressive polling — Three 3-second intervals per worktree, per-card 1-second cache timers, per-card 5-minute issue polling, 250ms error-page detection.