Rust:複数 worktree にそれぞれ同じものをコンパイルさせない
AI の並列開発で最も高くつくコストは、モデルではなく、Rust が依存関係を繰り返し再コンパイルすることである場合がよくあります。
現場:8 コアの Mac で、二つの worktree が同時に
cargo testを実行している。問題は「二つの cargo」そのものではなく、各 cargo がデフォルトで論理コア数に合わせてコンパイラを起動することです。十数個のrustcが一斉に走り、マシンは激しく swap し始めます。コンパイル自体は落ちていなくても、コンピューターはもう普通に作業できません。
四つの対策は、すべて必要です。
1. 並行数を制限する:二つの軸、どちらも必須
多くの人は半分だけ制限しています。「同時にいくつの cargo を走らせるか」だけを制限し、各 cargo 自身がさらに fan-out することを忘れています。
semで同時にいくつの cargo を走らせるかを制限するCARGO_BUILD_JOBSで各 cargo がいくつの rustc を起動するかを制限する。これがないと、各 cargo は論理コア数に合わせて並行実行します。これこそが「2 個の cargo が 15 個の rustc になる」本当の原因です。
wrapper(heavy-cargo):
#!/bin/sh
# 8コア/16GB:同時に重い cargo は一つ、各 cargo は最大二つの rustc。
# コア数だけでなく swap を見て調整する。32GB+ なら sem -j 2 を試せる。
exec sem --id rust-heavy -j 1 --fg -- \
env RUSTC_WRAPPER=sccache CARGO_INCREMENTAL=0 CARGO_BUILD_JOBS=2 \
nice -n 15 taskpolicy -b cargo "$@"
nice は CPU 優先度を下げます。taskpolicy -b は Darwin のバックグラウンドスケジューリング方針を設定します(バックグラウンドタスクの CPU/I-O を抑える)。この二つは Linux の ionice と厳密には等価ではなく、同じ目的のためのプラットフォーム別手段です。
2. コンパイルキャッシュを共有する(sccache)
sccache により、異なる worktree 間でコンパイル生成物を再利用できます。鍵になるのは incremental です。
.cargo/config.tomlの[env] CARGO_INCREMENTAL = "0"は効きません。[env]は cargo が起動する子プロセスに変数を渡すだけで、cargo 自身の増分コンパイル判断に影響するには間に合いません。- ただし、起動前に
CARGO_INCREMENTAL=0 cargo …を設定すれば有効です(上の wrapper はこの方法です)。利点は、「incremental を切る」対象を重いビルドに限定できることです。他のプロジェクトは通常どおり増分コンパイルでき、全体で犠牲にする必要はありません。全体で無効化したいなら、[build] incremental = falseを使えます。
worktree をまたいでヒットしやすいのは主にサードパーティ依存関係です(同じ registry、同じパス)。自前の crate はデフォルトでは絶対パスがキャッシュキーに入るため、worktree をまたいでヒットしません。ただし新しい sccache の SCCACHE_BASEDIRS は、異なる checkout のパスを正規化できます。
SCCACHE_BASEDIRS="$PWD" RUSTC_WRAPPER=sccache CARGO_INCREMENTAL=0 cargo check
100% ヒットすると約束してはいけません。bin、dylib、cdylib、proc-macro のようにリンカを呼ぶ crate は、そもそもキャッシュできません。
本当に効いているか必ず検証してください。そうしないと、設定しても有効かどうか分かりません。
sccache --zero-stats
heavy-cargo test -p server
sccache --show-stats # cache hits / requests executed を見る
3. target はそれぞれ独立させ、共有しない
容量を節約しようとして、複数の worktree を同じ CARGO_TARGET_DIR に向けてはいけません。ロック競合が起き、かえって遅くなります。再利用はキャッシュで行い、target の共有では行いません。
4. さらに速くしたい場合(プラットフォームごとに検証)
- リンカ:Linux では mold / lld を試せます(リンク段階が時間の半分を食うことはよくあります)。macOS に mold をそのまま適用してはいけません。mold の Rust 設定は明確に
target_os = "linux"に限定されており、README の Apple M1 テストは Fedora Asahi 上で実行されたもので、macOS ではありません。リンカを替える場合は、対象プラットフォームごとに個別に検証する必要があります。 - cargo-nextest でテストを実行する。dev profile で
debug = "line-tables-only"にし、デバッグ情報のサイズを削る。
最後:制約を AGENTS.md に固定する
ツールを入れても、agent が相変わらず素の cargo test を実行するなら、流量制限は実装されていないのと同じです。次の一文を固定してください。
重い Rust build/test は必ず heavy-cargo 経由で実行すること;
agent は複数の cargo test を直接並行起動してはならない。
一言で言えば、並行数を制限し(二つの軸で)、キャッシュを共有し、target を分離し、プラットフォームごとにリンカを選ぶことです。さらにそのルールを AGENTS.md に固定すれば、AI に同時に三つの作業ラインを開かせても、コンピューターは耐えられます。

微信
支付宝
コメント
コメントは即時公開されますが、ポリシー違反時は非表示になる場合があります。