見出し画像

Unity 2020、Profiler周りの更新情報

この記事について

Unity 2019.4から Unity2020.2でProfiler周りも更新が色々とありました。
今回の記事はその点について紹介したい思います。

主な更新としては下記になります。
1.Job Flowが確認可能に
2.Unity.Profiling.LowLevelのAPIとUnity Profiling Core API パッケージ
3.DrawCallやメモリ状況などが取得可能になりました
4.独自のカウンターを追加することが可能になりました
5.Metadataを付けたSamplerがC#から発行出来るようになりました
6.Profiling.RecorderのGPU対応

他にもProfilerだけが別ProcessになったStandalone Profilerとか、Editor Iteration Profilerなどもあるのですが…
この辺りはEditor上での事で、Editor拡張等のパフォーマンス測定向けなので、今回は詳細については説明しません。

1.Job Flowが確認可能に

Unityでは、Jobという単位で、別のThreadに処理を投げてその同期を待っている処理を行っています。
エンジン内部での処理だけでなく、C# JobSystemでアプリ開発者も使う事が出来ます。

このJobの流れをProfilerで確認することが可能となりました。

動画のような形で、MainThreadから発行されたJobがどこで実行されていて、その処理がどこで行われて、どこで完了待ちをしているかが確認出来るようになっています。

私のビデオ6


この機能は、ProfilerWindow上で「Show Flow Events」にチェックを入れる事で利用が可能になります。

画像1

C# JobSystemを利用するコードを書くときや、MainThread側の同期待ちっぽい時に何が原因となっているかが一目瞭然になります。

2.Unity.Profiling.LowLevelのAPIとUnity Profiling Core API パッケージ

Unity 2020で新たにProfilingのLowレベルにアクセスできるAPIが追加されました。

Lowレベルにアクセスすることで、これまで出来なかったDrawCall数等へのアクセスや独自カウンタ、Metadata付Samplerと言った機能が利用できるようになります。
しかし、System.IntPtrの利用をするなど低レイヤーに対して直接アクセスをするコードが必要になってきます。

それでは敷居が高いという事で出来たのが、Unity Profiling Core API パッケージです。

Unity Profiling Core APIパッケージがWrapperとなり、扱いやすい形で新機能にアクセスすることが出来ます。
Unity Profiling Core APIパッケージは、Package Managerの「Add from git URL...」から「com.unity.profiling.core」と入力して下さい。

私のビデオ7

この後に紹介する DrawCallやメモリ状況の取得、独自のカウンター、Metadata付のSamplerは Unity Profiling Core APIパッケージの利用を前提として紹介します。

3.DrawCallやメモリ状況などが取得可能になりました

Profilerに出てくる RenderingやMemoryに関する数値が取得可能になりました。

画像4

カウンターAPIというのを利用する事で、これらの数値にアクセスが出来ます。下記のようなコードを書く事で、ドローコールやSetPassの値を取得することが出来るようになります。

void Update(){
  // Draw Calls Countの値取得用オブジェクト
  var drawCallsCount = ProfilerRecorder.StartNew(ProfilerCategory.Render,
                                                 "Draw Calls Count");
  // SetPass Calls Countの値取得用オブジェクト
  var setPassCount = ProfilerRecorder.StartNew(ProfilerCategory.Render,  
                                               "SetPass Calls Count");

  // 1フレーム中に複数データが入る可能性、また入っていない可能性もあり得ます…
  for (int i = 0; i < drawCallsCount .Count; ++i ) {
    Debug.Log("DrawCall:"+drawCallsCount .GetSample(i).Value);
  }
  for (int i = 0; i < setPassCount .Count; ++i){
    Debug.Log("SetPass:"+setPassCount .GetSample(i).Value);
  }
}

4.独自のカウンターを追加することが可能になりました

画像のような形で、独自の値をProfilerに載せる事が可能になりました。

画像5

コチラを利用するには、下記のような形となります。
1.スクリプト側にカウンターを記録するコードを仕込む
2.ProfilerWindowの設定で、書き込んだカウンターを表示する

4-1.スクリプト側にカウンターを記録するコードを仕込む

このような形でProfilerCounterオブジェクトを作成して、更新する形になります。

public class MyCunter : MonoBehaviour
{
   static readonly ProfilerCounter<int> EnemyCount =
       new ProfilerCounter<int>(ProfilerCategory.Scripts,
           "敵の数",
           ProfilerMarkerDataUnit.Count);

   int enemyCount = 10;
   void Update()
   {
       EnemyCount.Sample(enemyCount);
   }
}

4-2.ProfilerWindowの設定で、書き込んだカウンターを表示する

Profilerウィンドウで設定を変更することでカウンターの値をUI上に表示する事が出来るようになります。

私のビデオ9

5.Metadataを付けたSamplerがC#から発行出来るようになりました

これまでのバージョンでも、CustomSampler クラスを利用する事で、自分の処理をCPU Profilerに載せる事が出来ました。しかし、CustomSamplerでは関連オブジェクトしか情報として付加させることが出来ません。

ProfilerのSamplerには Metadataと言う形で、intやfloat、文字列等の情報を追加で渡す事をサポートしています。

画像のような形で 「Sleepミリ秒:3」という形で intの値を付加させてる事が出来るようになりました。

画像7

上記のようにデータを仕込むコードとしては下記のような形になります。

using UnityEngine;
using Unity.Profiling;
using System.Threading;

public class WithMetadata : MonoBehaviour
{
   static readonly ProfilerMarker<int> ListUpdateMaker = 
       new ProfilerMarker<int>(ProfilerCategory.Scripts, 
           "スレッド休止", "Sleepミリ秒");

   void Update()
   {
       int sleep = 3;
       // 処理区間をBegin/Endで括ります
       // ※他にも using( Auto(sleep)){ 処理 }という手段があります。
       ListUpdateMaker.Begin(sleep);
       Thread.Sleep(sleep);
       ListUpdateMaker.End();
   }
}

このような形で、Sampleの情報にMetadataという形で intの値を付加させることが出来ます。

6.Profiling.RecorderのGPU対応

Unityには元々Profiling.RecorderというAPIがあり、Profilerに出ているCPU処理時間に関する情報を取得することが出来ました。

これがGPUにも対応出来るようになりました。

ただし、全ての実行環境でGPU時間を計測できるわけではありません。SystemInfo.supportGPURecorderで実行環境がGPU時間計測に対応しているかを確認することが出来ます。

また他にも条件として、CustomSampler.Createの引数「collectGpuData」にtrueを渡して、そのCustomSamplerで呼び出した区間のGPU処理に関する所だけが取得可能になります。

下記のような形での利用となります。

// Cameraのレンダリング処理を計測用にCustomSamplerを作ります。
var customSampler = CustomSampler.Create("MainCamera.Render", true);
// そして、Recorderを取得してきます
var customSampleRecorder = customSampler.GetRecorder();

// Cameraのレンダリング処理全体をSampleします
customSampler.Begin();
Camera.main.Render();
customSampler.End();

if (!SystemInfo.supportsGpuRecorder)
{
   Debug.Log("SystemInfo.supportsGpuRecorderがfalseです");
}
else { 
   Debug.Log("GPU時間:" + customSampleRecorder.gpuElapsedNanoseconds+ "ナノ秒");
}

このような形で、GPU時間の計測が可能になります。

まとめ

このような形でUnity 2019からUnity 2020でProfilerで出来る事も増えました。

おまけ

あと…Unity 2019でもProfilerに画像データを仕込むパッケージつくりました。こちらも良かったら使ってみて下さい



この記事が気に入ったらサポートをしてみませんか?