デバッグツールとプロファイリングツール
以下のセクションでは、Burst でコンパイルされたコードを、エディターとプレイヤービルドでデバッグおよびプロファイルする方法について説明します。
Tip
Burst でコンパイルされたコードをデバッグする前に、Unity での C# コードのデバッグ の手順に従って、エディターまたはプレイヤービルドでのスクリプトデバッグを有効にしてください。理論上は、スクリプトコンパイルモードが Release に設定されていても、Burst でコンパイルされたコードをデバッグすることはできますが、実際には確実に動作するわけではありません。例えば、ブレークポイントがスキップされたり、Locals ウィンドウに変数が表示されなかったりすることがあります。
Burst でコンパイルされたコードをエディターでデバッグする
Burst でコンパイルされたコードをエディターでデバッグするには、マネージデバッガーまたはネイティブデバッガーを使用できます。このセクションでは、両方のオプションについて説明します。
マネージデバッガーをアタッチする
Visual Studio、Visual Studio for Mac、JetBrains Rider などのマネージデバッガーをアタッチできます。これらは、Unity プロジェクトで通常の C# マネージコードをデバッグするために使用できるデバッガーと同じタイプのデバッガーです。デバッガーのアタッチ方法は、使用している Unity のバージョンによって異なります。
Unity 2022.2 以降: Burst でコンパイルされたコード内にブレークポイントを配置し、マネージデバッガーをアタッチしている場合、Burst は自動的にそのコードパスに対して無効化されます。これにより、マネージデバッガーを使用してマネージバージョンのコードをデバッグできるようになります。そのコードパスからすべてのブレークポイントを削除すると、そのコードパスに対して Burst が再び有効化されます。
Unity 2022.1 以前: エディターの Burst メニュー のグローバルオプション (Jobs > Burst > Enable Compilation) で Burst を無効にするか、デバッグ対象の特定のエントリーポイントから
[BurstCompile]
属性をコメントアウトします。
ネイティブデバッガーをアタッチする
Visual Studio や Xcode などのネイティブデバッガーをアタッチできます。その前に、Burst 最適化を無効にする必要があります。これは、以下の方法で行うことができます。
エディターの Burst メニュー の Native Debug Mode Compilation 設定 (Jobs > Burst > Native Debug Mode Compilation) を使用します。重要: この設定によって、すべてのジョブで最適化が無効になるため、Burst コードのパフォーマンスが影響を受けます。特定のジョブに対してのみ最適化を無効にする場合は、このリストのもう一方のオプションを使用してください。
ジョブに
Debug = true
フラグを追加すると、その特定のジョブで最適化が無効になり、デバッグできるようになります。[BurstCompile(Debug = true)] public struct MyJob : IJob { // ... }
Tip
プレイヤービルドで
Debug
フラグを選択すると、プレイヤービルドのデバッグでもこれを使用できます。
Unity エディターのプロセスにネイティブデバッガーをアタッチするには、以下の ネイティブデバッグ のセクションを参照してください。
Burst でコンパイルされたコードをプレイヤービルドでデバッグする
Unity でプレイヤーのコードをビルドする方法の要件として、シンボルがある場所をデバッグツールに伝える必要があります。これを行うには、ツールに lib_burst_generated
ファイルが含まれるフォルダー (通常は Plugins
フォルダー) を指定します。
Burst でコンパイルされたコードをプレイヤービルドでデバッグするには、ネイティブデバッガー (Visual Studio や Xcode など) をプレイヤーのプロセスにアタッチする必要があります。その前に以下を行う必要があります。
シンボルの生成を有効にします。これは以下の 2 つの方法のどちらかで行うことができます。
プレイヤーをビルドする前に Development Build オプションを有効にする
Burst AOT Player Settings で、Force Debug Information オプションを有効にする
Burst の最適化を無効にします。これは以下の 2 つの方法のどちらかで行うことができます。
Burst AOT Player Settings の Enable Optimizations オプションを無効にする。重要: この設定によって、すべてのジョブで最適化が無効になるため、Burst コードのパフォーマンスが影響を受けます。特定のジョブに対してのみ最適化を無効にする場合は、このリストのもう一方のオプションを使用してください。
ジョブに
Debug = true
フラグを追加すると、その特定のジョブで最適化が無効になり、デバッグできるようになります。[BurstCompile(Debug = true)] public struct MyJob : IJob { // ... }
プレイヤーのプロセスにネイティブデバッガーをアタッチするには、以下の ネイティブデバッグ のセクションを参照してください。
ネイティブデバッグ
上記の手順に従って、エディター または プレーヤービルド のネイティブのデバッグを正しく設定してください。そのうえで、Visual Studio や Xcode などのネイティブデバッガーをアタッチしてください。
ネイティブデバッグの制限事項
- ネイティブデバッガーは
Entity.ForEach
でラムダキャプチャを検出できないので、これらに由来する変数を調べることができません。 [StructLayout(LayoutKind=Explicit)]
を使用し、かつフィールドが重複している構造体は、重複している一方が非表示になった構造体として表現されます。- 関数パラメーターはデバッグの観点では読み取り専用です。Burst はプロローグ中に関数パラメーターをスタック引数に記録します。デバッガーでそれらの値を変更しても、効果がない可能性があります。
コードベースのブレークポイント
Burst は System.Diagnostics.Debugger.Break
メソッドを介してコードベースのブレークポイントをサポートしています。このメソッドは、コード内にデバッグトラップを生成します。ブレークをインターセプトできるように、デバッガーをコードにアタッチする必要があります。ブレークポイントは、デバッガーをアタッチしているかどうかに関係なく発動します。
Burst は、ローカル変数、関数パラメーター、およびブレークポイントを追跡するための情報を追加します。デバッガーが条件付きブレークポイントをサポートしている場合は、コードにブレークポイントを追加するよりも、そちらを使用してください。条件付きブレークポイントはデバッガーをアタッチしたときにのみ発動されるからです。
Burst でコンパイルされたコードをプロファイルする
スタンドアロンのプロファイリングツールを使用したプロファイリング
プロファイリングツール (Instruments や Superluminal など) を使用して、Burst でコンパイルされたコードをプレイヤービルドでプロファイルすることができます。Unity でプレイヤーのコードをビルドする方法の要件として、シンボルがある場所をプロファイリングツールに伝える必要があります。これを行うには、ツールに lib_burst_generated
ファイルが含まれるフォルダー (通常は Plugins
フォルダー) を指定します。
Unity プロファイラーマーカー
エディターまたはアタッチされたプレイヤーで実行される、Burst でコンパイルされたコードについて、Unity プロファイラーから取得されるデータを改善するために、new ProfilerMarker("MarkerName")
を呼び出して Burst コードから Unity プロファイラーマーカーを作成できます。
[BurstCompile]
private static class ProfilerMarkerWrapper
{
private static readonly ProfilerMarker StaticMarker = new ProfilerMarker("TestStaticBurst");
[BurstCompile(CompileSynchronously = true)]
public static int CreateAndUseProfilerMarker(int start)
{
using (StaticMarker.Auto())
{
var p = new ProfilerMarker("TestBurst");
p.Begin();
var result = 0;
for (var i = start; i < start + 100000; i++)
{
result += i;
}
p.End();
return result;
}
}
}