Repository navigation
perf(wsl): pooled wsl.exe command loops and orcad compile cache on the WSL wake path (C4 follow-up) - #27923
Conversation
ca22e1a to
21a0166
Compare
fa0b90e to
a17d5b1
Compare
a17d5b1 to
fbc7021
Compare
21a0166 to
ae08e94
Compare
fbc7021 to
850b587
Compare
b7ce5f1 to
deaf720
Compare
850b587 to
342e50a
Compare
|
Important Review skippedReview was skipped as selected files did not have any reviewable changes. ⚙️ Run configuration
📥 Commits
You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 Walkthrough
Priority: ➖ Normal Merge Risk: 🔵 Low · up to
|
342e50a to
61d2f1e
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/main/wsl/wsl-command-loop.ts (1)
88-94: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoffPooled output can exceed the memory bound that
execCommandenforces.The loop keeps every base64 line of a command in
command.stdoutandcommand.errors. It decodes all of them at once insettle.execCommandkeeps only the lastMAX_EXEC_OUTPUT_CHARSof output, but that limit applies after the data reaches it. A directwsl.exechild streams its output, so it never holds the full output in memory.The guest script also writes each command's full output to
$d/obefore it frames anything. If a command such ascaton a large file produces a lot of output, memory grows with the full output size, at about 1.33× because of base64.The probes in the current callers are small, so the practical risk is low. To fix it, push each decoded chunk to the channel as it arrives. Decode in multiples of 4 base64 characters.
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
0f5675d6-2bcd-41de-8d5c-8b429220b3aa
📥 Commits
Reviewing files that changed from the base of the PR and between 4857afd and 61d2f1e66b73448ce5bc178f08de2cc138a91f73.
📒 Files selected for processing (17)
src/main/orcad/launcher.tssrc/main/orcad/orcad-compile-cache.test.tssrc/main/orcad/orcad-compile-cache.tssrc/main/orcad/orcad-launcher-isolation.integration.test.tssrc/main/orcad/orcad-profile-preflight.tssrc/main/ssh/remote-install-transport.tssrc/main/ssh/ssh-relay-exec-closed-stdin.test.tssrc/main/ssh/ssh-relay-exec-command.tssrc/main/wsl/wsl-command-loop-pool.tssrc/main/wsl/wsl-command-loop.test.tssrc/main/wsl/wsl-command-loop.tssrc/main/wsl/wsl-orcad-deploy.tssrc/main/wsl/wsl-orcad-host-transport-loops.test.tssrc/main/wsl/wsl-orcad-host-transport.test.tssrc/main/wsl/wsl-orcad-host-transport.tssrc/shared/orcad-idle-exit.tssrc/shared/orcad-managed-launch-env.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.
2ca6b4d to
b852950
Compare
…ache orcad's compiled bundle The WSL wake path made ~37 sequential wsl.exe starts at ~180 ms each. Stdin-free execCommand calls now go through a few long-lived wsl.exe sh loops (one command at a time per loop, own session, stdin at EOF, base64-framed output). SSH has no such method, so its commands and options are unchanged. orcad enables Node's compile cache inside a client-managed slot, and hands it to the profile preflight child, which compiles the same bundle.
… managed slot An unmanaged orcad started with its own NODE_COMPILE_CACHE kept that location for its preflight before; never redirect it into the install dir.
b852950 to
8eddaf4
Compare
Stacked on #27819 (C4). C5 (#27834) now stacks on #27941 above this. Do not merge.
ELI5
Restarting Orca's server inside a WSL distro took about 12 seconds. Most of that time went to starting
wsl.exearound 37 times in a row, once for each small check. Each start costs about 180 ms. Now a fewwsl.exeprocesses stay open and run those checks one after another, at about 10 ms each. The server itself also starts faster, because Node now caches its compiled code. A warm restart takes about 5.7 seconds instead of about 12.5.What Changed
src/main/wsl/wsl-command-loop.ts,wsl-command-loop-pool.ts).execWithClosedStdin. It sends a command to an idlewsl.exe --exec sh -c <loop>built withbuildWslExecArgsand spawned through process-host.setsid sh -c "$cmd" </dev/null(plainsh -cif the guest has nosetsid), so it gets its own session as before. Its stdout, stderr and exit status come back base64-encoded between per-loop random markers.wsl.exe, as before. Idle loops end after 5 s, or right away throughdispose(), whichdeployAndLaunchWslOrcadcalls when it finishes.mktemp/base64), that transport goes back to onewsl.exeper command.execCommand.execCommandusesexecWithClosedStdinonly when the caller passes nostdinand the transport defines the method. In that case nothing would ever write the channel's stdin anyway. Commands that do take stdin (uploads,writeFile, the stdio bridge) still get their ownwsl.exe. SSH transports do not define the method, so the SSH command text and options are byte-for-byte unchanged. A new test asserts this.src/main/orcad/orcad-compile-cache.ts).module.enableCompileCache(<slot>/.orcad-compile-cache), but only for a client-managed slot (one withORCA_ORCAD_MANAGED_ACTIVATION_ROOTset). It never runs in a packaged app directory, where a new file would break the bundle's signature.NODE_COMPILE_CACHEin its own env only. The daemon and terminals never inherit it.Why
The orcad lifecycle code (fence, journal, recovery, census, GC) is shared with SSH, and every one of its steps matters. Batching those steps into combined scripts would have meant rewriting shared command sequences that SSH also runs. Making each round trip cheap at the transport level speeds up all of them without changing what any of them do. A full stdin multiplexer would need a helper inside the guest, so loops serve only commands that never use stdin.
The compile cache is a standard Node feature that TypeScript's own CLI also uses. It changes no command and works the same on SSH and WSL hosts.
Linked Issue
Internal WSL-via-orcad tracker, step C4 follow-up.
Visual Proof
N/A: no UI change.
Testing
win-lowspec (Windows 11, 8 logical CPUs). Throwaway Ubuntu 24.04 distro
orca-c4b-probewithsystemd=false. I randeployAndLaunchWslOrcadunderOrca.exewithELECTRON_RUN_AS_NODE, wrapping every exec with timing. For each warm run I killed orcad, then relaunched. Before = C4 transport plus C4 orcad. After = this branch, for both the transport and orcad.wsl.exeexits: same PID, its own session./tmp/orca-wsl-exec.*directories were left behind.0700.Automated.
sh: framing, binary output, stderr, exit codes, stdin EOF, its own session, the concurrency cap, abort, a loop dying mid-command, the startup fallback, and a backgrounded writer.shforwsl.exe, plus theexecCommandrouting and the SSH byte-identity test.src/main/{ssh,wsl,orcad}pass. A few real-shell timing tests fail only under full parallel load and pass alone.orcad-state-snapshot-shell's killed-group case also fails on macOS without this change.pnpm tc,check:code-quality:changed, oxlint, anti-slop, process-host imports, the max-lines, runtime-electron and runtime-launcher ratchets, the node pin check andsmoke:orcad-terminalall pass.AI Disclosure
Review
Agent skill upstream boundary
Notes
execWithClosedStdin, so its commands and options are unchanged. The compile cache applies to managed SSH slots too. It changes no command, and if it fails, orcad compiles as before.wsl.exewas.materializeOrcadArtifacttakes about 1.3 s locally. It hashes the template and cache three times per call.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)