Unity を検索

インクリメンタルビルドパイプラインによるプレイヤーのビルドの高速化

2022年12月20日 カテゴリ: Engine & platform | 13 分 で読めます
Accelerating player builds with an incremental build pipeline | Hero image
Accelerating player builds with an incremental build pipeline | Hero image
シェア

Is this article helpful for you?

Thank you for your feedback!

過去 2 年間、Unity のチームはスクリプトのコンパイルを行うパイプラインと、プレイヤーのビルドパイプライン(Build Player ウィンドウで Build をクリックした時に実行されるエディターのパーツ)の両方を高速化するために、それらの動作をインクリメンタルにすることに取り組んできました。2005 年から Unity のエンジニアリングチームで働いている Jonas Echterhoff です。このブログでは、インクリメンタルビルドをどのように実現したかを紹介します。

何を解決しようとしているのか

スクリプトをコンパイルし、エディターでプレイヤーをビルドするために、これまで Unity はカスタムの C# コードで一連のステップを実行し、外部ツールを呼び出すこともよくありました。何年も経ってビルド(とそれを実装するためのコード)はより複雑になり、ユーザーにとってより時間のかかるものとなってきました。私たちはこの問題を解決し、より良いユーザー体験を得られるようにビルドに費やす時間を最適化することを追求し、以下の事柄を確実に実現するようにしました。

  • 後続のビルドにおいては、入力が変更されたために実際に再実行する必要があるステップのみをエディターが再実行するようにしました。つまり、Build を 2 回クリックした場合は、クリックの間に何の変更もないので、2 回目のビルドはほぼ一瞬で終わるはずです。
  • エディターは、可能な限りビルドステップを並行して実行し、すべての CPU コアをフルに活用しようとします。

私たちは行ったこと

全体的な考え方

私たちは、ビルドを直線的に実行される連続したステップのリストとして扱うのをやめ、それに代わって各ビルドステップの入力と出力、およびステップ間の依存関係を理解する適切なビルドシステムの使用を始める必要がありました。このような依存関係の構造は、「ビルドグラフ」と呼ばれます。

幸いなことに、Unity にはすでにグラフベースのビルドシステムがありました。これは主にエディターとプレイヤーのランタイムのビルドに使われています。このシステムは Bee ビルドシステムと呼ばれ、ビルドグラフを記述するために C# API を使用しています。Bee は、私たちがサポートしているすべてのプラットフォームに対応しており、社内の多くの Unity 開発者がすでに慣れ親しんでいることから、エディタースクリプトのコンパイルとプレイヤーのビルドを Bee で再実装することにしました。

実装の詳細

Bee のビルドシステムの中心には、2 つのプログラムがあります。

ビルドプログラム

ビルドプログラムは、.NET プログラムで、ディスク上のすべてのソースファイルと設定ファイルを入力として受け取り、それらを使ってビルドグラフを生成します。ビルドグラフは以下の事柄を記述したものです。

  • ビルドする必要のあるすべてのもの(「ビルドノード」とも呼ばれる)
  • 上記のものをビルドするために実行するコマンド
  • ビルドノード間の依存関係

そして、この情報は .dag.json ファイルに格納されます。スクリプトコンパイル用のビルドプログラムと、各プラットフォームのプレイヤー用のビルドプログラムという、それぞれ異なるものをビルドするための複数のビルドプログラムがあります。

バックエンド

bee_backend と呼ばれるバックエンドプログラムは、生成された .dag.json ファイル内のビルドグラフを読み、ディスク上のどの入力ファイルが前回のビルド以降に変更されたか、また対応するどのビルドノードの再ビルドが必要かをチェックします。

そのために、プログラムは必要なノードを再ビルドするために必要なすべてのコマンドを実行するプロセスを起動し、利用可能なコアにそれらを並行して分散させます(依存関係の要件が許す限り)。 bee_backend は Andreas Fredriksson 氏によって書かれた Tundraビルドシステムをベースにしています。

ロールアウト

そのために、スクリプトのコンパイルパイプラインを Bee に書き換えることから取り組みました。これにより、Roslyn C# コンパイラープロセスを生成するために使用されていた多くのカスタムエディターコードを、よりシンプルで効率的なビルドシステムに置き換えることができました。

この変更は Unity 2021.1 TECH ストリームにおいて初めて適用されましたが、長期的な計画として、Unity のスクリプトコンパイルシステム全体を MSBuild ベースのシステムに置き換え、.NET エコシステムとの互換性をより向上させる予定があることにもご留意ください。

次に、プレイヤーのビルドコードを Bee で動作するように変換しました。この作業の大部分において、プラットフォーム固有のビルドコードをすべて書き換える作業が発生しました。これには時間がかかりましたが、その結果、プラットフォーム間でコードが共有されるようになり、より速く、よりきれいに、より簡単にメンテナンスできるようになりました。

この変更は、数回の Unity のリリースに渡ってロールアウトされました。

  • デスクトップ向けのスタンドアロンプレイヤー、 WebGL、Android(2021.2)
  • iOS/tvOS、すべての Xbox プラットフォーム(2022.1)
  • 残りの全プラットフォーム(2022.2)

また、Burst をインクリメンタルなプレイヤービルドパイプラインに統合したことにより、Burst コンパイラーが他のビルドタスクと並行して実行できるように、またアセンブリが実際に変更された場合にのみ実行されるようになりました。これは、Unity 2022.2 TECH ストリームと Burst 1.8.0 のリリースに同梱されています。

データビルド

ここで説明するビルドグラフには、明確に定義された依存関係を持つ、それぞれが外部ツールとして実行可能な、プレイヤーをビルドするためのステップがすべて含まれています。具体的には以下のステップです。

  • スクリプトのコンパイル
  • Il2CPP 変換と C++ コンパイル
  • UnityLinker によるコードストリップ
  • Burst コンパイル
  • コード署名
  • パッケージングと圧縮

また、プラットフォームに特化したツールも多く含まれています。しかし、シーンやアセットをプレイヤーデータファイルにシリアライズすることはできません(現在はエディター内のネイティブコードで行っています)。

残念ながら、完全にインクリメンタルなデータビルドパイプラインを構築するには、ビルドグラフにノードを追加する他にやらなければならないことがあります。Unity のデータファイルレイアウトの性質上、各シーンは以前にビルドしたすべてのシーンに依存するため、単純に小さな変更を抽出して他のすべてから独立してビルドすることはできないのです。この欠点は、Unity の他のチームが取り組んでいることであり、今後数年で大幅に改善されることを期待しています。

しかしそのような制約があっても、ユーザーが Build ボタンをクリックした時に不必要な作業を強いるようなことはしたくありませんでした。そこで、以前は Script only build と呼ばれていた機能を自動化することにしたのです。Build Player ウィンドウのチェックボックスで、Unity に前回のビルド時のプレイヤーデータを再利用し(変更は無視)、代わりにスクリプトだけを再コンパイルするように指示する機能で、コードに対するイテレーションの時間短縮を図るために使用されました。しかしこれでは、コンピューターに簡単に処理できるプレイヤーデータの変更を、ユーザーに負担させてしまうことになると考えたのです。

新しいインクリメンタルビルドパイプラインでは、プレイヤーで使用されているシーンやアセットが、前回のビルド以降に変更されたかどうかを追跡しています。変更がない場合、エディターは自動的にデータビルドをスキップし、前回のビルドからデータを再利用するようになりました。こうすることで、ユーザーはデフォルトで迅速なビルドが可能になり、変更を手動で追跡するような精神的なオーバーヘッドがなくなります。

ただし、Build ボタンのポップアップメニューで Force skip data build をクリックすると、データの変更があった場合でも、データのビルドをスキップすることが可能です。これは、データの変更があることは分かっているが、この目的のために保留中のデータの変更を適用せずに、コードの変更を迅速にテストしたい場合に便利です。

Build > Force skip data build
Build > Force skip data build

とはいえ、プレイヤーデータのビルドをさらにインクリメンタルなアプローチで行いたいなら、プロジェクトで Addressables パッケージを使うように変更することをお勧めします。これは、ビルトインのデータビルドパイプラインを、AssetBundle ベースのデータビルドおよび配布メカニズムに置き換えるものです。Addressables パッケージでは、アセットやシーンを含む Addressable グループを定義することができ、これらは互いに独立してアセットバンドルに組み込まれます(グループのデータが変更された場合のみ)。

Clean Build オプション

前述したように、インクリメンタルビルドパイプラインは、入力に変更がないビルドアクションをスキップし、以前のビルドからビルド結果を再利用します。しかし、それが好ましくない状況もあります。一般的には、ビルド中にアセットやシーンを変更するカスタムコールバックがあり、それらのコールバックの動作を変更したい場合、新しいビルドが必要になる場合があります。また、バグなどによって以前のビルド結果が破損した疑いがあるというケースもあります。こういう時は、もちろん新しいビルドが必要です。

このような場合は、Clean Build オプションを選択して、キャッシュされたビルドの成果物をすべてディスクから削除し、すべてを再ビルドすることが可能です。Build Player ウィンドウからプレイヤーをビルドする場合、このオプションは Build ボタンのポップアップメニューに含まれています。BuildPipeline API からプレイヤーをビルドする場合、BuildOptions.CleanBuildCache を使って同じことを行うことができます。

ビルドのプロファイリング

プレイヤーのビルドに費やす時間を最適化するためには、どこに時間がかかっているのかを真に理解することが重要です。私たちの Bee ビルドシステムは、すでに Chrome Trace Events フォーマットでのプロファイルファイルの書き出しをサポートしており、Google Chromeで可視化することができます。そこで、BuildReport のビルド手順をこのファイルに追加し、ビルドパイプラインイベントをフルビルドセッションのコンテキストに置くことにしました。これにより、ビルド中に発生するすべての出来事を、マルチスレッドなタイムラインの形で検査することができます。

Unity がどのように自分のプロジェクトをビルドしているのか、その舞台裏をもっと知りたいという方は、この方法をぜひ参考にしてみてください。実際にやってみるには、プレイヤーをビルドし、Chrome を開き、chrome://tracing に移動し、Load をクリックし、Library/Bee/buildreport.json ファイルをプロジェクトフォルダーから選択してください。ただし、ここで触れるものはサポートの無い内部領域に属するものであり、将来の Unity のバージョンで変更される可能性があるため、ワークフローをこれに依存させないように注意してください。

Profiling builds via Google Chrome
Google Chrome によるビルドのプロファイリング

結果

結局、このような取り組みがどのようなメリットをもたらすのでしょうか。MacStandalone IL2CPP Player として 2021 年版の 16 インチ M1 MacBook Pro 上でビルドされた、BoatAttack デモの数字を見てみましょう。

数値は、スクリプトを変更した場合と、まったく変更しない場合の「後続のビルドにかかる秒数」です。Unity 2021 では、「まったく変更しない」場合でも、多くのビルドステップが再実行されるため、かなりのオーバーヘッドがあることがおわかりいただけると思います。この数字は、Burst コンパイル、UnityLinker によるアセンブリのストリッピング、コード署名なども行った上でのものです。インクリメンタルビルドパイプラインでは、これらのステップをすべて省略することができます(これらのステップの再実行が必要な変更がない場合)。

The results
結果

Android のようにインクリメンタルなデプロイメントをサポートするプラットフォームでは、インクリメンタルビルドパイプラインは、ディスク上のファイルにのみ、かつそれらが変更される必要がある場合にのみ、影響を及ぼします。これにより、Unity はデバイスへのファイル転送のみを行えばよくなり、Patch and Run ワークフローにおける高速なイテレーションが実現されます。

プレイヤーのビルドに関するヒントについては、フォーラムをご覧いただくか、Mastodon の @jonas@mastodon.gamedev.place までお気軽に直接ご連絡ください。現在連載中の Tech from the Trenches シリーズの他の Unity 開発者による新しい技術ブログもぜひご覧ください

2022年12月20日 カテゴリ: Engine & platform | 13 分 で読めます

Is this article helpful for you?

Thank you for your feedback!

関連する投稿