Skip to content

Performance round: measure on real data, then fix the top costs #1475

Closed

Description

@currentbits

The August performance issues (#225, #564, #617, #618, #639, #640) are all closed and their numbers are stale. This round starts from fresh measurements on today's real data.

Baseline (2026-10-05, live data, read-only)

  • Store file: coder-store.json is 6.0 MB and parses in 18 ms. Boot parse is no longer an issue.
  • Threads: 2,097, of which 958 are live (not archived), across 14 projects. Message shards: 2,097 files, 788 MB, the largest 3.6 MB.
  • Running Nightly (not idle: the orchestrating thread runs inside it): main 347 MB RSS, renderer 575 MB RSS, GPU 60 MB.

Phase 1: measure (no code changes)

  • PM1, main process, on a clone of the userData dir: the boot timeline (window, first list, interactive); IPC payload sizes and rates for hot channels at 2k threads; a CPU profile during boot and during simulated streaming; what holds the main-process heap; disk writes while streaming.
  • PM2, renderer, the real Electron app on the clone driven over CDP: first render; sidebar with ~958 live rows; switching to the largest threads; typing latency; long tasks while streaming; heap and DOM-node breakdown.

Phase 2: fix

Pick the top costs from the Phase 1 numbers. Each fix needs a before/after measurement taken the same way.

Open from before: #1398 (scope threads:summaries); PM1 will check whether #1424 already covered it.

Activity

  1. currentbits commented on Oct 5, 2026

    @currentbits
    OwnerAuthor

    Incident during PM2 (resolved, no data lost)

    What happened: booting the app against a cp -Rc clone of userData is NOT isolated. The cloned worktrees/*/.git files point into the real repos' .git/worktrees/<id>. At 19:37, PM2's clone boot ran sweepOrphanWorktrees, which switched three real worktrees of archived threads to recovered/* branches and committed their uncommitted work there:

    • e055dfbb in ~/Desktop/Apps/saas/appfeedback
    • 7f93b763 and 08472090 in ~/code/huskyscout

    Restore (by PM2, at 19:39), verified independently:

    • All three worktrees are back on their original branches.
    • Their full contents (untracked included, compared via a temp index) are identical to the 19:37 snapshots.
    • The original branch tips have no ref changes today.
    • No recovered/* branches remain in any of the 14 project repos.
    • All 21 live worktree registrations are intact.
    • The live memory.db (which the clone's memory-server.json also pointed at) passes PRAGMA quick_check.

    Prevention: the safe launch recipe (PM1 used it with zero leaks) is in agent memory as solenta-cloned-data-dir-launch. PM2 has been told to use only that recipe from here on. Any future perf or dogfood worker gets it in its prompt.

    PM1 results (main process): docs/perf/2026-10-05-main-process.md

    1. Streaming rewrites the whole 5.9 MB envelope on every flush: 19 MiB/s, ≈92% of main-process JS busy time while streaming.
    2. The first threads:summaries call per session reads 463 MiB of transcripts synchronously, freezing the main process for 2.07 s when the Agents panel opens. P1: Scope threads:summaries so opening Agents does not read every transcript #1398 is only partly fixed.
    3. The login-shell PATH capture blocks boot for 0.71 s.
    4. Sync git in projects:list and git:listBranches: 140 ms on the boot path, and ~170 ms stalls on run starts.
    5. files:resolve fan-out: 424 IPCs and 131 ms per thread open.
    6. The message cache never shrinks: +4 MB heap per large thread visited.

    Idle is fine: 50 ms of main JS per 30 s.

  2. currentbits commented on Oct 5, 2026

    @currentbits
    OwnerAuthor

    PM2 results (renderer): docs/perf/2026-10-05-renderer.md

    1. Provenance is recomputed over the whole transcript on every push: 30% of renderer JS while streaming into a big thread, and ~48 ms per big switch.
    2. The open transcript grows without bound while streaming: DOM 24.7k → 62.2k nodes, RSS 275 → 579 MB, and blocked time 220 → 337 ms/s.
    3. A forced synchronous layout in useStickToBottom runs on every push: ~25–30 ms/s.
    4. The whole streaming message is re-parsed as markdown on every push, so cost grows O(n²) with answer length.
    5. threads:changed ships 2.68 MB (all 2,004 rows): a ~21 ms renderer hitch per status change. PM1 found the same.
    6. A big-thread switch takes 120–220 ms.
    7. Cold start: ~500 ms to FCP.
    8. localStorage: the boot snapshot is at 2.7M of the 4M cap, with 1,667 stale paneLayout keys.

    Fine: the sidebar at 966 rows, small-thread switches, idle typing, streaming into a thread that isn't open, and memory after switching (no leaks).

    Phase 2: fixes running (six parallel workers, disjoint files)

    Next batch, after these land:

    No fix worker launches the app on cloned data. They measure with Store-on-a-copy benchmarks, unit benchmarks or the dev renderer.

  3. added 3 commits that reference this issue on Oct 5, 2026
  4. added 4 commits that reference this issue on Oct 5, 2026
  5. currentbits commented on Oct 5, 2026

    @currentbits
    OwnerAuthor

    Batch 1 status: #1478, #1479, #1480, #1481 and #1482 are merged. #1483 is in CI, re-running a Windows-only failure.

    Batch 2 started. Four workers, each owning separate files:

  6. added 3 commits that reference this issue on Oct 5, 2026
  7. 6 remaining items

  8. added a commit that references this issue on Oct 6, 2026
  9. currentbits commented on Oct 6, 2026

    @currentbits
    OwnerAuthor

    Round 3 status:

    Deep dives started:

    1. The transcript window sometimes stops trimming. In 2 of ~10 dev soaks DOM climbed as if perf(transcript): bound the tail window, stop forced layout per push, idle cache write (#1475) #1482 weren't there; suspected loss of stick-to-bottom state. Reproduce, root-cause, add a regression test.
    2. Renderer heap growth in Electron: +12 MB over the soak in Electron, against ~1.5 MB in the browser. Heap snapshots on the PM3 zero-leak recipe, to name the retainers.
  10. added 3 commits that reference this issue on Oct 6, 2026
  11. currentbits commented on Oct 6, 2026

    @currentbits
    OwnerAuthor

    Deep dives done.

    Left (bounded, small):

    • stale transcript closures keep a switched-away thread's copy (~4 MB);
    • the first thread:updated after launch is a full 4 MB transcript;
    • the index shift for scrolled-up readers on a retention trim.
  12. added a commit that references this issue on Oct 6, 2026
  13. added and removed on Oct 9, 2026
  14. currentbits commented on Oct 9, 2026

    @currentbits
    OwnerAuthor

    Done: measurements and fixes landed for 0.24.0 (e45a09a before/after, 8e77940 row patches, 8ad23c8 provenance, 5255a69 byte-capped hydration, e0f8561 tail-first switch). Closing in the 2026-10-09 board cleanup (#1532).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions