世界を動かす技術を、日本語で。

Rustコンパイラの性能

2025年6月10日原文(kobzol.github.io)

概要

Rustのコンパイル時間が長いことは、ユーザーの間で頻繁に指摘される問題。 Rustプロジェクトはコンパイラ性能改善に継続的に取り組んでいる現状。 過去数年でビルド速度は確実に向上しているが、依然として十分ではないとの声も多い。 技術的・運用的な制約が、さらなる高速化の障壁となっている実態。 今後も新たなアプローチや大規模な変更での改善が期待される状況。

Rustコンパイル時間への不満と現状

  • Rustの コンパイル速度フィードバックループの遅さ は、ユーザーから最も多く寄せられる不満点。
  • Rust関連の ポッドキャスト、ブログ、アンケート、カンファレンス など、様々な場で頻繁に議論される話題。
  • Rustプロジェクト内でも パフォーマンス改善 を重視し、 毎週のトリアージベンチマークスイートの運用 を実施。
  • パフォーマンス向上PR は積極的に歓迎し、 退行があれば即座に修正やリバート を行う体制。
  • x64 Linux 向け最適化に特に注力しているため、他プラットフォームでは効果が限定的な場合も。

コンパイル性能の進歩と現状の課題

  • 2022年から2025年にかけて、 hyperqueue プロジェクトのビルド時間は 約2倍高速化
    • 例:1.61.0(2022年)で26.1秒→1.87.0(2025年)で14.7秒
  • ただし、依然として 多くの開発者にとって生産性のボトルネック である現状。
  • C++開発者 は慣れているが、 Python開発者 などには特に遅さが際立つ印象。
  • 「根本的な解決は可能か?」 という問いに対し、 インクリメンタルビルド の最適化などで十分な高速化が理論上は可能と考察。
  • モノモルフィゼーション、型システム、ビルドスクリプト など、Rust特有の複雑さが高速化の障害。

取り組みと技術的な制約

  • パラレルフロントエンド、代替コード生成バックエンド、より高速なリンカの採用 など、多様なアプローチを模索。
  • MIR-only rlibs、-Zhint-mostly-unused、スマートなインクリメンタルコンパイル など、現時点で利用可能な最適化も存在。
  • ビルドパフォーマンス改善 はRustコミュニティ全体に恩恵をもたらし、 CIやテスト実行時間短縮 にも寄与。

なぜ進捗が遅いのか

  • 技術的な理由

    • rustcは巨大かつ複雑なコードベース で、全体を把握している開発者はほぼ不在。
    • マイクロ最適化の余地は減少 し、既存の最適化は局所的な最小値に達しつつある状況。
    • 最適化によるトレードオフ (例:新しいCPU命令セット対応による互換性問題、メモリアロケータ変更によるメモリ消費増加)。
    • 複数バージョン配布のコスト増大 や、CIリソースの逼迫。
  • 運用・組織的な理由

    • 大規模な変更にはチーム内の合意形成(Major Change Proposal)が必要
    • 下層の変更が全体に波及し、多数のテストやレビューが必要
    • 他の開発と競合しやすく、長期的なメンテナンスコストも高い

今後の展望とアプローチ

  • 特定のワークフロー改善 (例:Relink, don’t rebuild提案)による生産性向上の可能性。
    • Cargoとの連携強化や、無駄な再ビルド回避 など、賢いビルドプロセスの実現。
  • 大規模リファクタリング・構造改革 による本質的な高速化も模索。
  • 証明的なパフォーマンス向上 を実現しても、エッジケース対応や後方互換性維持が難題。

まとめ

  • Rustプロジェクトは コンパイル性能改善に真剣に取り組んでいる
  • 技術的・運用的な制約 が進捗の遅さにつながっている現実。
  • 新たな最適化手法や構造改革 による今後の改善に期待が寄せられる状況。

Hackerたちの意見

LLVMをスキップしてJIT最適化を優先することにどれだけの価値があるのか気になるな。リリースビルドでは、そこそこ最適化されつつデバッグしやすさを保てるなら、いい代理になるかもしれない。JVMを最初のターゲットにするのも面白いかもね、彼らのJITは成熟してて強力だし。

現代の言語でこれがあったら最高だな。開発ビルドでは、JITコンパイルはデバッグビルドよりも良い選択だと思う。最終的にピークパフォーマンスに達する可能性があるからね。ゲームのようなパフォーマンスに敏感なものでは、すべての最適化をオフにしてゲームが使えなくなることなく、良いフィードバックループを保つことが本当に重要だよ。AOTの静的バイナリはデプロイメントにとって価値がある。Rustのような既存の言語で開発するのがどれだけ高コストになるかは全く分からないけど。

JVMはRustにとってあまり意味のあるターゲットじゃないね。Cみたいなフラットなメモリアドレスやポインタ演算を使わないから。Javaのオブジェクトやフィールドがそれぞれ小さなメモリセグメントやアドレス空間にあるみたいな感じ。これのおかげで、GCにはほとんど透明になるのがJavaの大事な特性なんだけど、逆に言うとC系の言語をJVMにコンパイルするのは、JVMのバイト値の配列として「メモリ」を再実装することが多いんだよね。

LLVMをスキップしてJIT最適化されたリンクを使うことにどれだけの価値があるのか気になるな。リリースビルドでは、適切に最適化されてデバッグしやすさを保ちながら、合理的なプロキシを得られるかもしれない。Rustは今、craneliftバックエンドを構築中なんだ。Craneliftは元々JITコンパイラとして作られた。これがデバッグビルドのコンパイラになればいいなと思ってる。 https://github.com/rust-lang/rustc_codegen_cranelift

LLVMの最適化は、Felderaでのコンパイルボトルネックの大部分を占めてるんだ。ここで直面したいくつかの課題についてブログに書いたよ: https://www.feldera.com/blog/cutting-down-rust-compile-times... 将来的にはこの問題を避けるためにJITを構築する必要がほぼ確実にあるね。

大規模なC++コードベースで働いてきたから、長いコンパイル時間には慣れてるんだけど、C++の開発者がRustを嫌うことにここまでこだわるのが意外だな。

これは常に指摘できる定量的なマイナスだよね。もちろん、正当化に使われることもあるけど。

C++にはコンパイル時間を短縮するためにできることがたくさんあるけど、Rustではできないことも多いよ。

C++の開発者がRustを嫌うことにここまでこだわるのが意外だな。人は自分の現在の問題を誇張することがあるから、まるでそれが唯一の重要なことのように聞こえるよね。別のプロジェクトでは「これが商業的な代替品を使い続ける唯一の理由だ」とか、「これが広範な採用を妨げている唯一の要因だ」とか言われたこともある。一方で、私には基本的な完成度を持たせるために必要な優先事項のリストがある。パフォーマンスに関しては、誰にとっても十分なものにはならないよ。常に利用可能なリソースを消費する大きなプロジェクトがあるし、変わったやり方にこだわる人もいる(有効かもしれないけど、非常に典型的ではない)。改善のリクエストは、通常のものと区別がつかないことが多いね。

それ、めっちゃ納得!十分なC++の経験がある人なら、誰でも一度はその悪夢に直面したことがあるよね。できることなら、二度と経験したくないよ。

毎日大規模なC++コードベースで作業してるんだけど、i9で128GBのRAMとNVMeドライブを使っても、コンパイルに30分かかることもある。Rustのコンパイル時間はまだ信じられないくらい遅いよ。少し前に「小〜中規模」のオープンソースプロジェクト[0]に貢献して、使ってるときに出た問題をいくつか修正したんだ。このプロジェクトは、日常のプロジェクトの約3桁小さいから、数千行のRustコードのクリーンビルドに10分近くかかった。プロジェクトへのインクリメンタルな変更も、その時は1分近くかかってた。Rustで5百万行以上のプロジェクトには参加したことがないけど、どれだけ時間がかかるか想像もつかないよ。逆に、同じくらいのサイズのGolangプログラム[1]にいくつかパッチを提出したけど、そのプロジェクトをクローンして依存関係をインストールしてクリーンビルドする方が、Rustプロジェクトの1ファイル変更よりも早かったよ。[0] https://github.com/getsentry/symbolicator [1] https://github.com/buildkite/agent

そこでは、日常のコーディングのために小さなスタンドアロンの実行可能ユニットテストセットとシミュレーションを書くことが答えだったよ。QTやBoostのようなテンプレート重視のものを避けるのも助けになるね。

Hacker Newsで議論の続きを見る