先日行われた Unite Now セッションにて、Burst コンパイラーの技術を使って、Unity でプロジェクトを構築している開発者が、Arm Neon 命令セットを活用する方法について議論しました。Android デバイスをターゲットにする場合に Burst コンパイラーを使用することで、Arm アーキテクチャでサポートされている Unity プロジェクトのパフォーマンスを向上させることができます。
Unity と Arm はパートナーシップを結び、Android エコシステムの中で 10 億を超える Arm 搭載モバイルデバイス向けのモバイルゲーム開発体験を強化しています。
ゲーム開発者にとって、パフォーマンスは最も重要な要素です。Arm は、より豊かな体験を構築するために必要な性能と効率の向上を提供するために、CPU と GPU 技術の改善に毎年投資しています。最近、Arm は 2 つの新製品を発表しました。Cortex-A78 は電力効率を大幅に改良し、Cortex-X1 ではさらに印象的なパフォーマンスを示します。これらのハードウェア開発は、Arm アーキテクチャのコンパイラー技術の進歩によって補完されます。コンパイラーによって、高性能なゲームを開発する際に、コードが Arm アーキテクチャの機能を最大限に活用できるように、効率的なバイナリの変換・最適化を確実に行います。
Burst は、新しいデータ指向技術スタック(DOTS)とUnity Job System を使って作成された、Unity プロジェクトのパフォーマンスを向上させるために使用できる事前コンパイラー技術です。Burst は、高性能 C#(HPC#)として知られる C# 言語のサブセットをコンパイルすることで動作し、LLVM コンパイラーフレームワークの上に構築された高度な最適化を展開することで、デバイスのパワーを効率的に利用します。
Burst は、アプリケーションで活用されていない並列性を利用するのに最適です。DOTS プロジェクトから Burst を使用するのは簡単で、CPU に依存したアルゴリズムで大きなパフォーマンスのメリットを引き出すことができます。次に示す動画は、Burst を有効にした場合としない場合のデモ環境でのスクリプトの実行を並べて比較した結果を示しています。
デモでは、Unity Physics を使用したシミュレーションの 3 つの例を示しています。Burst でコンパイルされたコードでは、物理要素の数が多いフレームをより速く計算できるため、パフォーマンスが向上し、サーマルスロットリングやバッテリー消費量が少なくなり、より魅力的なコンテンツを提供できることがお分かりいただけると思います。
Burst を使えばあとは何もしなくてもパフォーマンスが向上すると言われていますが、それはどのようにして実現されているのでしょうか。
Burst は、HPC# コードを LLVM コンパイラーフレームワークで使用される中間言語である LLVM IR に変換します。これにより、コンパイラーは LLVM のサポートする Arm アーキテクチャ用のコード生成をフルに活用して、プログラムのデータフローを中心に最適化された効率的なマシンコードを生成することができます。このフローの図を以下に示します。
Mike Acton 氏は「Data-oriented design and C++」という講演を行いましたが、この講演では「ハードウェアを知り、データを知る(know your hardware, know your data)」という格言が最大のパフォーマンスを達成するための手段として取り上げられています。Burstがうまく機能するのは、HPC# 言語と DOTS フレームワークによって保証されている配列エイリアシングの制約を可視化し、ハードウェアアーキテクチャに関する LLVM の知識を利用できるからです。これにより、Burst は Unity API に対して書かれたスクリプトのプロパティに基づいてターゲット固有の変換を行うことができます。
Burst を使用して、DOTS の Unity Job System を利用した C# スクリプトをコンパイルすることができます。これは [BurstCompile] 属性を次のようにジョブ定義に追加します。
[BurstCompile] struct MyJob : IJob { public NativeArray<float> Input; public NativeArray<float> Output; public void Execute() { for (int I = 0; I < Input.Length; i++) { Output[i] = Input[i] * Input[i]; } } }
どのようなコードが生成されるかを確認するために、Jobs メニューから選択して Burst インスペクターを使用することができます。このデモでは、安全チェックを無効にし、Burst 1.3.3 を使用しています。
表示される Burst インスペクターで ARMV8A_AARCH64 ターゲットを選択して、Armv8-A 用のコード生成を有効にしています。
これで、Neon 命令セットを使用したコアループを含む、C# ループ用に生成される AArch64 コードを確認することができます。
Burst コンパイラーの使用方法の詳細についてはマニュアルを参照してください。また、こちらの Unite Now 講演では、本記事で紹介した内容や、上記のマニュアルで説明されている手順について詳しく紹介しています。Burst の利用に関する情報を集めたい、質問をしたいという方は、フォーラムを覗いてみてください。