Search Unity

Burst コンパイラーによるモバイルパフォーマンスの向上

, 8月 17, 2020

先日行われた 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 について

Burst は、新しいデータ指向技術スタック(DOTS)とUnity Job System を使って作成された、Unity プロジェクトのパフォーマンスを向上させるために使用できる事前コンパイラー技術です。Burst は、高性能 C#(HPC#)として知られる C# 言語のサブセットをコンパイルすることで動作し、LLVM コンパイラーフレームワークの上に構築された高度な最適化を展開することで、デバイスのパワーを効率的に利用します。

Burst は、アプリケーションで活用されていない並列性を利用するのに最適です。DOTS プロジェクトから Burst を使用するのは簡単で、CPU に依存したアルゴリズムで大きなパフォーマンスのメリットを引き出すことができます。次に示す動画は、Burst を有効にした場合としない場合のデモ環境でのスクリプトの実行を並べて比較した結果を示しています。

デモでは、Unity Physics を使用したシミュレーションの 3 つの例を示しています。Burst でコンパイルされたコードでは、物理要素の数が多いフレームをより速く計算できるため、パフォーマンスが向上し、サーマルスロットリングやバッテリー消費量が少なくなり、より魅力的なコンテンツを提供できることがお分かりいただけると思います。

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 のためのプログラミング手法

Burst を使用して、DOTS の Unity Job System を利用した C# スクリプトをコンパイルすることができます。これは [BurstCompile] 属性を次のようにジョブ定義に追加します。

どのようなコードが生成されるかを確認するために、Jobs メニューから選択して Burst インスペクターを使用することができます。このデモでは、安全チェックを無効にし、Burst 1.3.3 を使用しています。

表示される Burst インスペクターで ARMV8A_AARCH64 ターゲットを選択して、Armv8-A 用のコード生成を有効にしています。

これで、Neon 命令セットを使用したコアループを含む、C# ループ用に生成される AArch64 コードを確認することができます。

Burst コンパイラーの使用方法の詳細についてはマニュアルを参照してください。また、こちらの Unite Now 講演では、本記事で紹介した内容や、上記のマニュアルで説明されている手順について詳しく紹介しています。Burst の利用に関する情報を集めたい、質問をしたいという方は、フォーラムを覗いてみてください。

24 replies on “Burst コンパイラーによるモバイルパフォーマンスの向上”

Thank you for the great job! We’re working together with the Arm compiler team on more optimizations.

We had a more than 10x performance boost in CPU heavy parts of a mobile game and the effort was just less than a week to convert all related code to use burst and unmanaged memory in a proper manner.

In our case access to raw textures and meshes helped a lot as well.

I wanted to do that right after the video went public, but it slipped through cracks somehow. Let me see what I can do.

Now that Unity Learn is free, I would love to see more stuff on Burst. Thanks!
Also there is a typo, “Mike Action” > “Mike Acton”

What point is there to Burst coupled with ECS if systems’ main thread work and job scheduling exceeds the execution time of Burst jobs most of the time?

Hey there Nikolai. Thanks for reaching out! Wanted to pass along from the team that they are aware of this overhead, and are actively working on reducing it.

As Trey said, job scheduling optimization are on their way. The goal of the team working on it is to ensure that the overhead of scheduling a job is minimal (thus greatly improving the throughput). We’ll keep you posted!

Burst is one of the best techs to come out of Unity, it gave us a 10x-20x speed increase, truly amazing

We have to think about the future too. Your current projects will probably just stick to current tech, but future projects can be made with DOTS from the get go.

If we only want solutions that remain 100% compatible with the old monobehaviour flow, we’ll never see anything that brings huge improvements. Not even the best engineers in the world could make all that performance happen without requiring rewrites

I guess “for free” means “without using more memory”, which is a common trade-off for many optimizations like pooling, caching, baking etc.

Bit sensitive over an optimisation article? No need to call someone a liar. Frank is right, that it means ‘for free’ without any trade-offs and is welcome.

If you are creating a new game with ECS, then you don’t have to rewrite anything. It is true that you can’t take your existing game, add [BurstCompile] and enjoy performance improvements – I’ve also covered that in the slide explaining the limitations. However, as people have answered, there is no memory overhead or other kind of impact, so it’s _almost_ for free.

Would be interesting to see a comparison between “regular PhysX”, “Havok Physics” and “Unity Physics”.

The one shown here feels very flawed, comparing “Unity Physics, optimized for Burst but not using Burst” with “Unity Physics as it was designed”… This does not show the power of Burst at all.

(I think Burst is great, but your example doesn’t make sense)

Thank you for the kind words.
I would rather say Unity.Physics is designed for ECS (pure C#, stateless) and not exactly optimized for Burst – there is still room for optimizations, especially with the hardware intrinsics in Burst. We’ll be working on that.

Comments are closed.