
2026/10/04 15:26
メタデータを早期に生成することで、Rust のビルド時間と検証時間が最大 2 倍に短縮されます
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Headstart は、依存関係のインターフェースが準備ができ次第に早期に型チェックを実行し、完全な完了前に初期メタデータを生成することで、Rust のコンパイルを加速します。このアプローチは、6 つの rustc パッチ(
-Zearly-metadata)と 3 つの cargo パッチ(-Zheadstart)による実装であり、16 コアのマシンにおいて cargo check で最大 54% の速度向上、cargo build では 42% の速度向上を実現します。より小さなシステムでは同様の比例した恩恵が得られ(例:4 コアでチェックは約 24% 高速化、ビルドは約 13–15% 高速化)、並列フロントエンド実行(-Zthreads=8)によってアイドル中のコアを活用することでさらに約 25% の追加速度向上が可能になります。依存関係の本体にエラーが含まれていても、標準的なビルドと同じ診断情報と終了ステータスでビルドは失敗します。cargo はすべての依存関係が正常に完了するまで出力を報告せず、失敗したクリートのメッセージを抑制してノイズを低減します。同時実行による負荷によりメモリ使用量が増加しますが、これは下流の作業を早期に計算するためであり、後で破棄される可能性があるというトレードオフを反映しています。開発者は scripts/setup.sh を使用して Headstart を導入し、ベンチマークスイート(scripts/bench.sh、scripts/real-projects.sh、scripts/bench-suite.sh)を使用してパフォーマンスを検証できます。設計、測定、準備状況、および結果に関するさらなる詳細は docs ディレクトリにあります。本文
Headstart: Rust コンパイルの高速化技術
概要
依存関係の型チェックが完了する前に、それらを参照するクレイ(ライブラリなど)のコンパイルを早期に開始する仕組みです。従来の「各クレイが自身の開始までに全ての依存クレイが完全にチェックされ、関数の本体も含まれるまで待機する」スタイルと異なり、以下の点で革新を遂げています。
- メタデータの活用: 自身を型チェックするために相手の本体全体を読む必要はありません。
- 初期化の早さ: 依存先のインタフェース(
ファイル内のメタデータ)を対象にコンパイルを行います。.rmeta - 並列処理の促進: ヘッドスタートにより、rustc がインタフェースチェック直後に初期化されたメタデータを出力し、cargo がそれに基づいて依存クレイの処理を即座に開始します。
- 結果: 各クレイの本体は、すでに下流のクレイがコンパイルを行っている最中にチェックされます。
動作特性
コマンド別の挙動
| コマンド | 動作内容 |
|---|---|
| 依存クレイは初期メタデータを対象に完走します。 |
|
|
エラー処理とコスト
本体中にエラーが存在する場合でもビルドは失敗し、診断情報や終了ステータスは通常通りとなります。主な変化点は以下の通りです。
- 出力順序: プログレスラインおよびクレイ間での JSON メッセージの順序が異なります。
- レポートタイミング: cargo は依存関係が全ての正常に完了した後のみ、クレイの出力を報告します(エラー発生時の出力は破棄されます)。
- コスト増大:
- 下流で捨てられる作業量が増加します。
- エラー報告が遅れます。
- 同時に使用されるメモリ容量が増えます。
構成要素とパッチ詳細
この仕組みを実現するためのアップストリームへのプルリクエスト(一連のコミット)は以下の 2 つのコンポーネントで構成されています。
rustc (-Zearly-metadata
)
-Zearly-metadata- 新しいクエリ:
を使用し、分析を「アイテムのインタフェース」と「関数の本体」に分割します。analysis_interfaces - ファイル出力: ドライバがこれら 2 つの処理の間などに
ファイルを書き出します。.early-rmeta - モジュール動作: クレイ読み込みモジュールは初期メタデータを受け入れ、コード生成時に完全なメタデータで置換し、書き込みまでプロデューサが保持するロックを待機します。
cargo (-Zheadstart
)
-Zheadstart- フラグ付与: コンパイルごとに
フラグを渡します。-Zearly-metadata - 即時開始: チェックもビルドも問わず、初期メタデータの通知を受け取ると直ちに依存クレイの処理を開始します。
- リソース管理: 一時停止したコンパイルのジョブスロットを他の作業に割り当てます。
- 成功のみレポート: クレイの出力を報告するのは、その依存関係が成功した場合に限ります。
パフォーマンス向上とリスク
- デフォルトフロントエンドでの成果:
で最大 54% の速度向上(例:rust-analyzer, zed, bevy など)。cargo check
で最大 42% の速度向上。cargo build- どのプロジェクトもパフォーマンス劣化はありません。
- 並列フロントエンド (
):-Zthreads=8- ビルド時に通常はアイドル状態となるコアを有効活用できるため、さらに最大 25% の向上が見られます。
- マシンサイズが小さいほど効果は小さくなります(例:4 コアマシンでは rust-analyzer のチェックが 24% 高速化)。
視覚的な違い
以下の図は、時間軸を横に、依存関係の深さを縦にした表示です(詳細は
docs/results.md を参照)。
- Headstart を使用しない場合: ワークスペースのクレイは長い階段状の構造を形成します。
- Headstart を使用する場合: オーバーラップして並行処理が進みます。
試してみる
セットアップと実行
まず、rustc と cargo のチェックアウトとパッチ適用、両者のビルドを行います。
./scripts/setup.sh
その後、任意の Rust プロジェクトで以下のように実行します。
環境変数設定方法:
RUSTC=/path/to/headstart/rustc/build/host/stage1/bin/rustc \ /path/to/headstart/cargo/target/release/cargo check -Zheadstart # または build
の設定方法:.cargo/config.toml
[unstable] headstart = true
このオプションがなければ、パッチ済み cargo はアップストリームと同様の挙動を示すため、公平な基準線を得ることができます。
テストスクリプトと検証
-
視覚化テスト (
):tests/smoke- 2 クレイからなるワークスペースで効果を可視化します。
- 「チェックに数秒かかる」とされる遅いライブラリ(
)の大半は関数の本体にあります。slow - Headstart を有効にすると、
の完了を待たずにslow
が約 0.2 秒後に開始します。app
-
エラー検証 (
):scripts/check-errors.sh- テスト
でエラーに関する主張を検証します。tests/errors - シナリオ:クリーンビルド、依存クレイでのエラー、バイナリでのエラーの 3 つ。
- Headstart 無効・有効両方で実行し、人間可读な出力、JSON 出力、終了ステータス、ビルドされたバイナリの内容を比較します。
- テスト
-
インクリメンタル検証 (
):scripts/check-incremental.sh- 依存呼び出しに対する
の追加やインタフェースの破損・修復などの一連の変更をまたいでチェックを行います。impl Fn - 最終状態をクリーンビルドと比較します。
- 依存呼び出しに対する
-
最適化レベル検証 (
):scripts/check-swap.sh- ライブラリが依存先の初期メタデータを起点とし、一時停止中に完全なメタデータで置換されるプロセスを検証します。
- すべての最適化レベルで、出力が完全なメタデータからビルドしたものと同じであることを確認します。
-
ベンチマークスキャン (
):scripts/sweep.sh- Headstart 無効・有効の両方で(
フラグ付き)、rustc-perf の全ての 53 つのコンパイルベンチマークをビルドします。-Zearly-metadata-verify - オプション
で cargo build スキャン、-c build
でリリースプロファイル、-r
で並列フロントエンド対応可能です。-t
- Headstart 無効・有効の両方で(
ベンチマーク
単一プロジェクト測定
Clean
cargo check(または cargo build)のビルド時間を測定し、中央値を表示します。Headstart を無効・有効に交互に切り替えます。
scripts/bench.sh -n 5 [-c build] path/to/project ...
- 引数の付与: プロジェクト名の後続部分に
で cargo 引数を付与できます(例:::
)。path/to/vaultwarden::--features=sqlite
リアルプロジェクトスイート測定
実プロジェクトのクローンと実行
scripts/real-projects.sh で 13 つの実プロジェクトをクローンし、同形式で表示します。
scripts/bench.sh -n 3 -c build $(scripts/real-projects.sh ~/hs-real)
codex-rs の設定
codex-rs 用の同等の設定を行い、パッチ済みの依存関係と codex のプリビルト V8 を必要とします(詳細はスクリプトを参照)。
scripts/setup-codex.sh <dir> # 計測前に `<dir>/codex/headstart.env` からソースを読み込みます。
スイート実行
現在のマシンに対して
docs/results.md に記載された全スイートを実行します(対象:rust-analyzer, 21 の rustc-perf ベンチマーク、その他実プロジェクトおよび codex-rs)。中断・再開が可能です。
scripts/bench-suite.sh <out-dir>
最後にサマリーテーブルを出力し、まだ測定されていないマシンサイズ(例:8 コア)のデータを取得できます。
その他のベンチマークスクリプト
-
メモリサンプリング (
):scripts/bench-mem.sh- ビルド中のすべての rustc プロセスの合計メモリをサンプリングします。
- 注意: 対象以外のマシンはアイドル状態にしてください。
-
インクリメンタル再チェック (
):scripts/bench-incremental.sh- 1 つの関数の本体を編集した後の再チェック時間を測定します。
-
スケジュールログ (
):scripts/log-rustc- 各 rustc の実行開始・終了時刻を記録し、スケジュールを確認できます。