點解 Cargo 食晒 CPU 同 SSD
同我哋點樣修好佢

claude-view · 2026-03-29

多個 agent session 喺唔同 git worktree 同時跑 cargo build,每個都用晒所有 CPU core。 加上 Cargo 嘅 incremental cache 永遠唔會自動清理,一晚就漲到 45GB。 呢個 slide 解釋我哋搵到嘅根因、做咗咩修、同點解 work。

之前
target/ 大小 45GB
Dependency .rlib 數量 793
hashbrown 編譯次數 7
Incremental cache dirs 379
最高 CPU 使用 880%
Orphan process(kill 後) 3+
之後
target/ 大小(clean build) 142MB
Dependency .rlib 數量 81
hashbrown 編譯次數 1
Incremental cache dirs 0
最高 CPU 使用 100%
Orphan process(kill 後) 0
三個 Verified Fixes
01

Build Queue — cq

用 perl flock 將所有 cargo 命令排隊。一個 build 用晒所有 core(burst mode), 其他等佢做完先開始。macOS 冇 flock CLI,所以用 perl FFI。 同時 set CARGO_INCREMENTAL=0 for one-shot commands(test/check/clippy), 防止 write-only cache 漲大。

Process group 隔離:cargo + 所有 child(rustc、linker)共用一個 PGID。 Kill cq → kill(-TERM, -$pgid) → 0 orphans。
02

cargo-hakari — Feature 統一

Workspace 入面 5 個 crate 各自用唔同嘅 feature 組合, Cargo 就會幫每個組合獨立編譯成個 dependency tree。 hakari 整一個 workspace-hack crate,強制所有人用同一個 feature union, 令每個 dependency 只編譯一次。

實測:.rlib 793 → 81(減 90%)。 Diem(Meta)原創、nextest 團隊維護、963K downloads。
03

Incremental = 0 for Agents

Incremental compilation 只幫到「改一行再 build」嘅 loop。 Agent 跑 cargo test 一次就走 — 個 cache 寫完 500MB 永遠唔會再讀。 關咗之後 build 速度一樣(實測 ±1s),但唔再寫 cache。

根因:31 個 server incremental hash × ~700MB = 15GB, 就係一個 crate。全部 write-only,從未 reused。

攞走嘅方案(經 /prove-it 審計 reject)

Cranelift backend
Nightly-only、要全套 toolchain dance、cargo check 完全冇受惠(skip codegen)
setsid process groups
macOS 冇 setsid CLI。用 perl POSIX::setpgid 代替
codegen feature 永遠開
實測 +18.8s(+33%)。ts-rs proc macro overhead 太重
sccache 跨 worktree 共享
Rust cache hit rate = 0%。只 cache C/C++ deps(ring、aws-lc-sys)

Build 慢唔係因為 Rust 慢 — 係因為做咗 31 倍多餘嘅嘢。 修好 feature matrix 同 incremental 浪費之後,再用 queue 管理 concurrency。 先 eliminate waste,再 optimize throughput。