Skip to content

perf: cut per-repaint CPU with concurrent sessions (ps walk, lazy proxy agent) - #728

Open
axisrow wants to merge 3 commits into
sirmalloc:mainfrom
axisrow:perf/397-cpu-per-repaint
Open

axisrow wants to merge 3 commits into
sirmalloc:mainfrom
axisrow:perf/397-cpu-per-repaint

Conversation

@axisrow

@axisrow axisrow commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Why

Closes #397. With several concurrent Claude Code sessions every statusline invocation is a fresh process, so per-render fixed costs multiply by session count. Two of those fixed costs are payable once instead of per repaint:

  1. the macOS terminal-width probe runs a ps walk per render, with two spawns per ancestor (-o ppid= then -o tty=);
  2. https-proxy-agent (and its transitive undici/proxy module graph) was loaded at startup even when no proxy is configured.

What this does

  • terminal: one ps -o ppid= -o tty= -p <pid> spawn answers both walk questions per ancestor (two -o flags, not a comma list — FreeBSD's parser collapses the comma form). The walk now starts at process.ppid and reads each generation's TTY before terminating on its PPID, keeping the old two-spawn walk's generation coverage (a PPID of 0 no longer hides a valid width on the same ps row).
  • usage-fetch / claude-service-status: ./proxy-agent is now dynamically imported inside the "proxy actually configured" branch, so the undici/proxy graph leaves startup entirely. node --cpu-prof: compileForInternalLoader 40.7ms → 7.5ms per render.

Measurement

13MB transcript, 4 parallel workers × 20 renders via stdin:

before after
CPU total 27.2 CPU-s 20.6 CPU-s
CPU per render 0.34 CPU-s 0.26 CPU-s (−24%)
wall 7.5s 5.6s

Verification

  • terminal tests assert the one-spawn-per-ancestor call sequence (and a PPID-of-0 row still yielding its TTY); green under both bun test and vitest.
  • claude-service-status proxy behavior (no agent by default, tunnel via HTTPS_PROXY, stalled-proxy deadline) unchanged and green — the lazy load is behavior-invariant; the win is startup cost, shown by cpu-prof above.
  • Full suite: 3111 pass / 1 fail (pre-existing git-hardening-exec LFS failure under Bun on macOS). Note: usage-fetch.test.ts is red under vitest on macOS for pre-existing reasons (its subprocess probe hits Node ESM extensionless resolution) — green under bun.

🤖 Generated with Claude Code

Every statusline invocation is a fresh process, so per-render fixed
costs multiply by the number of concurrent Claude Code sessions (sirmalloc#397):

- terminal: one ps spawn answers both walk questions per ancestor
  (`-o ppid= -o tty=`; two flags, not a comma list - FreeBSD's parser
  collapses the comma form). The walk re-runs per render on macOS, so
  halving its spawns halves that cost. The walk now starts at
  process.ppid and reads each generation's TTY before terminating on
  its PPID, keeping the old two-spawn walk's generation coverage.
- usage-fetch, claude-service-status: load https-proxy-agent (and its
  transitive undici/proxy module graph) on demand, only when a proxy is
  actually configured. node --cpu-prof shows the graph gone from
  startup (compileForInternalLoader 40.7ms -> 7.5ms per render).

Benchmark (13MB transcript, 4 parallel workers x 20 renders via stdin):
27.2 -> 20.6 CPU-seconds total, 0.34 -> 0.26 CPU-s per render (-24%),
wall 7.5s -> 5.6s.

Closes sirmalloc#397

Co-Authored-By: Claude Code <[email protected]>
axisrow and others added 2 commits November 1, 2026 04:18
Union: the fork's lazy async proxy-agent request builder keeps its
await-import, upstream's per-model apiPath parameter rides along.

Co-Authored-By: Claude Code <[email protected]>
…awn walk

Upstream's it.each COLUMNS=0/wide tests mock the old two-spawn ps
protocol (ppid probe, then tty probe); this PR's walk answers both
questions with one ps spawn started at process.ppid, so the mock threw
Unexpected command and the walk bailed with null on CI. The mocks now
describe the PR's protocol; the tests' intent (invalid COLUMNS falls
back to probing) is unchanged.

Co-Authored-By: Claude Code <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

High CPU usage observed with multiple concurrent Claude Code sessions

1 participant