Skip to content

perf(diagnostics): move the session recorder and feed-debug sinks off the main process #1346

Open

Description

@Juliusolsson05

Split out of #767 (item 6).

Expected

The session recorder and the feed-debug disk sink do their serialization and file I/O off the Electron main process. Main only postMessages.

Actual

Both run on main (fs/promises in SessionRecorder.ts / feedDebugLog.ts).

  • The recorder time-slices JSON.stringify into ≤ 8 ms chunks with setImmediate yields, but all of that CPU is still main-loop time. The issue measured ~1 MB/s of stringify, 93 % of it screen frames.
  • queueFeedDebugAppend stringifies per entry with no slicing.

Why separate

It is an architecture change: a worker entry, a structured protocol, backpressure and lifecycle. The app already has three utilityProcess.fork templates: src/main/performance/MonitorCoordinator.ts (with a BoundedQueue envelope), src/main/workflows/ElectronWorkflowWorkerLauncher.ts and src/main/extensions/serviceHost.ts. #767's items 1/3/7 PR makes feed-debug persistence opt-in, so by default this mostly affects dev-debug sessions and recordings.

Severity P3 (only while diagnostics are enabled, after the #767 gate lands).

🤖 Generated with Claude Code

Activity

  1. Juliusolsson05 commented on Sep 27, 2026

    @Juliusolsson05
    OwnerAuthor

    Measurement before building (W3, 2026-09-27): moving these sinks to a worker would make main slower, not faster.

    The test used one real feed-debug file from this machine: 16,832 records, 134 MB, Node 24.14.1, 3 runs each. The time is main-thread CPU to hand every record off:

    Hand-off Time
    JSON.stringify each record (what main does today) 333 ms
    v8.serialize each record (the structured-clone wire format postMessage and utilityProcess use) 5,029 ms
    structuredClone each record 13,955 ms

    What follows from this:

    • Posting objects to a utilityProcess or worker structured-clones them on main, which costs about 15× the stringify we would be moving.
    • Posting a pre-stringified string still leaves the stringify on main (the part the issue wanted moved). The only thing left to move is the file write, and fs/promises already does that on libuv's thread pool, off the main JS thread.
    • So the proposed architecture removes little or nothing from the main loop and adds a process, a protocol and backpressure.

    This file is feed-debug. The session recorder's screen frames are strings plus small objects, the same shape, so I expect the same result, but no session recording exists locally to measure it.

    Proposal: close this as not worth it, or re-scope it to what does help on main:

    That re-scope overlaps open #1392 (feedDebugLog.ts), so it would follow #1392. I am waiting on the manager's call before building anything.

    🤖 Generated with Claude Code

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