HN 日本語サマリー

← 一覧へ戻る
プログラミング

メタデータを早期に発行することで、Rustのビルド/チェックが最大2倍高速になる

Emitting metadata early makes building/checking Rust up to twice as fast (github.com)

22 pointsby knuckleheads1 コメント

要約

Rustのコンパイラとビルドツールであるcargoの新しい機能「headstart」は、メタデータを早期に発行することで、コンパイル時間を大幅に短縮します。依存関係の型チェックが完了する前に、その依存関係のインターフェース情報(メタデータ)を利用してビルドを開始し、全体のビルド速度を向上させます。これにより、特に大規模なプロジェクトにおいて、`cargo check`で最大54%、`cargo build`で最大42%の高速化が報告されています。

全文翻訳

headstart 依存関係のあるクレートが、その依存関係の型チェック完了前に開始されます。各クレートは、型チェック自体には不要な依存関係の関数本体のチェックが完了するまで待機します。依存関係のインターフェース、つまり.rmetaファイル内のメタデータに対してコンパイルされます。Headstartは、インターフェースがチェックされ次第、rustcに早期メタデータファイルを書き込ませ、依存関係の開始をcargoに指示します。その後、各クレートの本体チェックは、下流のクレートがすでにコンパイルされている間に行われます。cargo check: 依存関係は早期メタデータで完了まで実行されます。cargo build: 依存関係は早期メタデータで全ての解析を行い、コード生成の前に依存関係の完全なメタデータを待ちます。待機中、ジョブスロットを返却します。本体にエラーがある場合でも、ビルドは今日と同じ診断情報と終了ステータスで失敗します。表示される進捗行とクロスクレートのJSONメッセージの順序のみが異なる場合があります。Cargoは、すべての依存関係が正常に完了した後にのみクレートの出力を報告し、いずれかが失敗した場合は破棄します。コストとしては、破棄される下流の作業、わずかに遅れて報告されるエラー、および同時に使用されるメモリの増加(docs/design.mdを参照)があります。Pieces rustc, -Zearly-metadata (6パッチ): 新しいanalysis_interfacesクエリが、アイテムインターフェースと関数本体に解析を分割します。ドライバーは、その2つの間に.early-rmetaを書き込みます。クレートローダーは早期メタデータを受け入れ、コード生成前に完全なメタデータとスワップしますが、書き込み完了までロックで待機します。cargo, -Zheadstart (3パッチ): すべてのコンパイルに-Zearly-metadataを渡します。早期メタデータ通知で依存関係を開始します(checkとbuildの両方)。一時停止したコンパイルのジョブスロットを他の作業に譲ります。依存関係が成功した場合にのみクレートの出力を報告します。パッチはコミットシリーズであり、それぞれにコミットメッセージとテストが含まれており、アップストリームのプルリクエストになることを意図しています。patches/README.mdを参照してください。rustcのデフォルトフロントエンドでは、headstartは13の実際のプロジェクト(rust-analyzer、zed、bevy、lemmy、polarsなど)のクリーンビルドを、cargo checkで最大54%、cargo buildで最大42%高速化します。遅くなるものはありません。並列フロントエンド(-Zthreads=8)では、一部同じ領域をカバーしますが、最大25%を追加します。これらは16コアでの数値です。この利得は、ビルドがアイドル状態のままにするコアから来るため、小型マシンでは縮小します。4コアでは、rust-analyzerのcheckは24%高速化され、buildは13-15%高速化され、codex-rsのcheckは14%高速化され、ワイドビルドは同等になります。仕組み、早期メタデータで何が除外されるか、リスクについてはdocs/design.mdを参照してください。測定結果: docs/results.md。コンパイラとcargoチームに提供する準備ができているか: docs/readiness.md。試すにはscripts/setup.sh # rustc + cargoをチェックアウトし、パッチを適用して両方をビルドします。その後、任意のRustプロジェクトで: RUSTC=/path/to/headstart/rustc/build/host/stage1/bin/rustc \/path/to/headstart/cargo/target/release/cargo check -Zheadstart # またはbuild CARGO_UNSTABLE_HEADSTART=trueも有効にします。.cargo/config.tomlの[unstable] headstart = trueも同様です。これらがない場合、パッチ適用済みのcargoはアップストリームと同様に動作するため、同じバイナリで公平なベースラインが得られます。tests/smokeは、効果を示す2クレートのワークスペースです。その遅いライブラリはチェックに数秒かかり、そのほとんどが関数本体に費やされます。headstartをオンにすると、appは完了を待つ代わりに約0.2秒で開始されます。scripts/check-errors.shは、tests/errorsでのエラーに関する主張をチェックします。これは、クリーンビルド、依存関係のエラー、バイナリのエラーの3つのシナリオを、headstartオフとオンでcargo checkとcargo buildで実行します。その後、人間が読める出力、JSON出力、終了ステータス、およびビルドされたバイナリの印刷内容を比較します。scripts/check-incremental.sh [check|build]は、一連のインクリメンタル編集で同様のことを行います。ステップには、依存関係が呼び出すFnの実装の追加、インターフェースの破壊と修正が含まれます。また、最終状態をクリーンビルドと比較します。scripts/check-swap.shは、ライブラリが依存関係の早期メタデータで開始し、一時停止中に完全なメタデータとスワップするのを、すべての最適化レベルでテストします。そこからビルドされたプログラムは、完全なメタデータからビルドされたプログラムと同じものを印刷する必要があります。scripts/sweep.shは、-Zearly-metadata-verifyを使用して、すべての53のrustc-perfコンパイルベンチマークをheadstartオフとオンでビルドします。すべてのビルドが両方のモードで同じ診断情報で成功し、verifyが何も報告しない場合に合格します。-cはcargo buildをスイープし、-rはリリースプロファイルをスイープし、-tは並列フロントエンド(-Zthreads=8)をスイープします。ベンチマークscripts/bench.sh -n 5 [-c build] path/to/project ... これは、headstartオフとオンを交互に切り替えながら、クリーンなcargo check(またはcargo build)ビルドの時間を計測し、中央値を表示します。プロジェクトは::の後にcargo引数を取ることができます(path/to/vaultwarden::--features=sqlite)。`scripts/real-projects.sh `は、[docs/results.md](docs/results.md)から測定されたコミットで13の実際のプロジェクトをクローンし、その形式で表示します: scripts/bench.sh -n 3 -c build $(scripts/real-projects.sh ~/hs-real) scripts/setup-codex.sh <dir>は、パッチ適用済みの依存関係とcodexの事前ビルド済みV8(スクリプトを参照)を必要とするcodex-rsについても同様のことを行います。タイミングの前に<dir>/codex/headstart.envをソースしてください。-wは、ビルドスクリプトがターゲット外で一度だけ実行される作業(helixはソースツリーにグラムマをコンパイルします)のために、プロジェクトごとに時間計測されないウォームアップビルドを追加します。scripts/bench-suite.sh <out-dir>は、現在のマシンでdocs/results.mdのスイート全体を実行します: rust-analyzer、21のrustc-perfベンチマーク、その他の実際のプロジェクト、およびcodex-rs、checkおよびbuild。各ベンチマークの結果を個別に保持し、完了したものをスキップするため、再起動可能であり、最後に概要テーブルを書き込みます。まだ測定されていないマシンサイズ(例: 8コア)の数値を取得する方法です。scripts/bench-mem.shは、プロジェクトディレクトリ自体でビルド中にすべてのrustcプロセスの合計メモリをサンプリングします(アイドル状態のマシンで実行してください)。scripts/bench-incremental.shは、1つの関数本体を編集した後のインクリメンタル再チェックの時間を計測します。scripts/log-rustcは、各rustc実行の開始と終了を記録するため、スケジュールを確認できます。rustc-perfベンチマークは、rustc/src/tools/rustc-perf/collector/compile-benchmarksの下にあります(git -C rustc submodule update --init --depth 1 src/tools/rustc-perf)。