ハクソク

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

Firefoxのビルドを17%速くする方法

概要

  • buildcacheccachesccacheと異なり、Luaプラグインシステムを持つ
  • WebIDLバインディング生成のキャッシュ化が可能に
  • ビルド時間短縮を実現、特にウォームキャッシュ時に顕著
  • 設定方法Luaラッパー導入手順を解説
  • 今後は他のコード生成ステップへの応用も期待

buildcacheのLuaプラグインによるWebIDLコード生成キャッシュ化

  • buildcacheccachesccacheと異なり、任意コマンドのキャッシュが可能なLuaプラグインシステムを搭載
  • Bug 2027655のマージにより、FirefoxのWebIDLバインディングコード生成ステップもキャッシュ対象に
  • WebIDLステップとは、python3 -m mozbuild.action.webidlを用いて、.webidlファイルからC++バインディングコードを自動生成する処理
  • 生成物はヘッダ、cpp、イベント実装など数千ファイル。出力は入力が同じなら常に同一となるためキャッシュに最適
  • これまでコンパイラキャッシュはこのステップに適用されていなかった

変更内容

  • dom/bindings/Makefile.inで、条件付きで$(CCACHE)をpy_action呼び出しのラッパーに指定
  • MOZ_USING_BUILDCACHEが有効な場合、webidlアクションがbuildcache python3 -m mozbuild.action.webidl ...の形で実行される
  • これによりbuildcacheがこのコマンドをインターセプト可能に
  • ccacheやsccacheは任意コマンドのキャッシュ機構を持たないため、buildcache固有の対応
  • Luaラッパーを利用し、WebIDLコード生成専用の処理を追加

Luaラッパー(webidl.lua)の仕組み

  • mozbuild.action.webidlをコマンド引数から検出し、対象コマンドか判別
  • 入力ファイル:全.webidlファイル、Pythonスクリプト(file-lists.json、codegen.jsonから取得)
  • 出力ファイル:生成されたバインディングヘッダ、cpp、イベントファイル、状態ファイル(file-lists.jsonから取得)
  • direct_modeを利用し、入力ファイルを直接ハッシュ化してキャッシュ判定
  • キャッシュにヒットすれば出力をリプレイ、ミスなら実コマンド実行後に結果を保存

ビルド時間比較

  • Linux上での./mach buildによる比較
    • ツール | コールド(初回) | ウォーム(キャッシュ有) | プラグイン有
    • none | 5m35s | n/a | n/a
    • ccache | 5m42s | 3m21s | n/a
    • sccache | 9m38s | 2m49s | n/a
    • buildcache | 5m43s | 1m27s | 1m12s
      • webidl.luaラッパー有効時はさらに15秒短縮し、1m12s
  • ウォームキャッシュ時の改善幅が大きく、編集-コンパイル-テストサイクルが大幅に短縮

セットアップ方法

  • machとbuildcacheを利用中の場合、Makefileの変更はcentral更新で反映
  • Luaラッパー有効化手順
    • buildcache-wrappersリポジトリをクローン
    • ~/.buildcache/config.jsonのlua_pathsにパスを追加
      • 例:
        {
          "lua_paths": ["/path/to/buildcache-wrappers/mozilla"],
          "max_cache_size": 10737418240,
          "max_local_entry_size": 2684354560
        }
        
    • またはBUILDCACHE_LUA_PATH環境変数をmozconfigで設定
      • 例:
        mk_add_options "export BUILDCACHE_LUA_PATH=/path/to/buildcache-wrappers/mozilla/"
    • max_local_entry_sizeは大きなRustクレート対応のため2.5GB推奨

今後の展望

  • Luaプラグインシステムの活用により、他の決定的なビルドステップにも同様のキャッシュ化を適用可能
  • WebIDLラッパーはあくまで実証例。今後は他のPythonコード生成アクションへの展開を予定
  • ビルド高速化のさらなる可能性

備考

  • 計測は単一マシン・単発実行であり、厳密なベンチマークではない点に注意
  • 方向性としてbuildcacheがウォームビルドで他ツールを大きく引き離すことは明確

Hackerたちの意見

ccacheを使えば、コードをコンパイルする必要ないじゃん。速いし。
ccacheは、チェックサムを使って中央サーバーからコンパイル済みのコードを取得するの?
すごい、17%も改善されるなんて簡単な修正で驚き!これを別プロジェクトとして構築して、webidlファイルを依存関係として取り込むことができるかな。
依存関係を別プロジェクトとして管理すると、日常的に面倒なことがたくさん出てくるよね。特に、ファイルが結構頻繁に変更される場合は。
そうだね… Mozillaはユーザーシェアの低下にもっと注力すべきかも。スピードも大事だけど、恐竜みたいに絶滅の危機が迫ってる時にその戦略に集中してもあまり意味がないよね。
これだけは言わせて:記事の内容に関わらない選択をしたのは残念だね。
Firefoxは主に自分たちの貢献者にアピールしてるから、開発者体験を良くするのは重要だよね。
明らかに、開発者がコードのコンパイルを待ちながら指をくわえている時間を増やす方が、シンプルなビルドパフォーマンスの改善をするより効率的になるわけないよね。Firefoxをもっと良くするために時間を使うべきなのに。しかも、他の開発者たちもビルドが速くなることで恩恵を受けるのに。
あー、そんなこと考えたことなかったよ。うちらはビルドを速くするためにすべての開発者を投入してたのに、ユーザーシェアを増やすことを考えなかったなんて、振り返ってみると結構バカだったな!ごめん、すぐに取り組むよ。マジで、プロジェクトの誰かがやってることが、プロジェクトの主な目標だと仮定するトレンドはどうなってるの?「Firefoxのフロントエンドデザイナーは、ユーザーシェアの減少を逆転させて、何億ドルもの寄付をもたらすWebUSBを実装する代わりに、フロントエンドデザインの仕事をしてる!何考えてるんだ?!!」って。これ、かなり叩かれるだろうな。
投稿者です。こういうコメントは予想してたけど、いくつか説明したいことがある。1. 私がMozillaの開発者で、ビルドキャッシュのサポートをFirefoxリポジトリに入れたからって、これがMozillaのプロジェクトになるわけじゃない。これは自分の時間を使って、実際に働くときに効率を上げるためにやってることなんだ。2. 主に楽しむためにやってる。ブログも含めてね。3. Sccacheは、今もMozillaで公式に開発しているコンパイラキャッシュだよ。
まあ、ブラウザの普及は主に主要なOSにデフォルトで付いてくるブラウザによって決まるんだよね。実際に積極的に選ぶユーザーは少ない(統計的に言えば)。Safariが人気なのは、iOSやmacOSに付いてくるからだし、Edge(以前のIE)はWindowsに付いてくるから人気なんだよね。でもChromeは色々な理由で人気があるんだ。一つは、AndroidやChromeOSに付いてくるからなんだけど、その前にGoogleはすごく攻撃的なマルチチャネルキャンペーンを展開して、Google検索で大きなバナーを出してた(みんなGoogle使ってたし)。それにWindowsのAVベンダーと契約して、ユーザーがパソコンにアンチウイルスをインストールするとChromeが自動的にインストールされてデフォルトブラウザになってたんだ。もう一つの理由は、GoogleがChromeを自社のウェブサービスと一緒にずっと開発してきたから、検索や地図、Gmail、ドキュメントなんかがChromeで一番うまく動くんだよね。Firefoxが持ってるデフォルトのチャンネルは、私が知ってる限りではいくつかのLinuxディストリビューションだけで、マーケットシェアはかなり薄いんだ。
あの… buildcacheってRustのproc-macrosをキャッシュできる?sccacheと戦ってて、次のnext.jsビルドCIのために10個のパッチを維持してるんだ。Windowsビルドも非決定論的な問題でキャッシュヒット率がひどかったし、解決できなかった。試してみるのは大歓迎だよ。
proc macrosを冪等性として扱う実験的なPRがあったんだけど、それに関してどうなったかはわからない。安定化には後方互換性を壊さないようにデザイン作業がたくさん必要だった。でも、これはチームの関心事の一つだよ。
「コードの17%を削除する」って、正しい答えじゃないよね?
ビルドが線形にスケールするならね。そうでなければ、違う割合になるかも。
コードの17%を削除できるなら、あるいはビルドを避けられるなら、やった方がいいかもね。でもそれは結構厳しいトレードオフになることもあるよ。(そして、兄弟コメントも正しいけど、17%のコードを削除することが17%早いビルドにはならないってこともあるし、もっと早くなるか遅くなるかも分からないけどね)
Firefoxのビルドについてはあまり詳しくないんだけど、なんでクラッバー(clobber)ビルドが一般的なの? 一見すると、ビルドシステムを直すよりもキャッシュを追加するのが変に思えるんだけど。
「修正する」ってどういう意味? 一時的なコンテナでビルドしてるなら、変更しないファイルには外部キャッシュが必要だよ。
Firefoxを積極的に使ってるわけじゃないから、彼らのユースケースについては語れないけど、clobberビルドの重要なユースケースの一つはCIだね。私はBuildCacheの作者で、私が働いてるところでは毎日何千ものclobberビルドをCIで作ってる。キャッシングはビルド時間を短く保つのにすごく役立つんだ。ローカル開発にもいくつかのユースケースがあるよ。例えば、gitのブランチを切り替えると、ほぼフルビルドをしなきゃいけないことがある(C++の場合、たくさんのファイルに含まれてるヘッダーファイルが触られたらね)。ローカル開発者としてのもう一つの利点は、中央のCIキャッシュにアクセスできること。最新のトランクを引っ張ってビルドすると、CIシステムがそのバージョンをすでにビルドしてる可能性が高いから(例えばマージゲートの一部として)、キャッシュヒットが得られるんだ。
「clobberビルド」って何なの?
AIの統合を全部無効にする?ごめん、私はこれで失礼するわ。