プロファイラーカウンターにコードを追加すると、Profiler ウィンドウ、またはアプリケーションのビルドで可視化することができます。
ProfilerCounter または ProfilerCounterValue で生成されるデータを Profiler ウィンドウで表示するには、カスタム Profiler モジュールを使用することができます。これにより、他のシステムメトリクスとの関係を視覚的に認識し、パフォーマンスの問題を迅速に特定できるようになります。
以下の例は、GameManager クラスが高レベルのロジックを処理し、敵について知っていることを前提としています。カウンターの値を更新するには、Update メソッドまたは LateUpdate メソッドで (ロジックが敵のスポーンまたは破壊とともに実行されるタイミングに応じて)、Sample メソッドを使用して敵のカウント値をプロファイラーにプッシュします。
using UnityEngine;
using Unity.Profiling;
class GameManager : MonoBehaviour
{
Enemy[] m_Enemies;
void Update()
{
GameStats.EnemyCount.Sample(m_Enemies.Length);
}
}
この例では、弾丸の数をプロファイラーに渡すために、弾丸のライフライフサイクルを管理するシェルスクリプトがあることを前提としています。その後、Awake で GameStats.BulletCount の値を増やし、OnDestroy で値を減らすことで、ゲーム内の現在の弾丸の流れに関する正確な情報を提供します。
using UnityEngine;
using Unity.Profiling;
public class Shell : MonoBehaviour
{
void Awake()
{
GameStats.BulletCount.Value += 1;
}
void OnDestroy()
{
GameStats.BulletCount.Value -= 1;
}
}
注:Unity は、開発ビルド以外では ProfilerCounter と ProfilerCounterValue の両方をコンパイルします。
プロファイラーモジュールエディターを使用して、ビルトインまたは新しく追加したカウンターを可視化の対象として選択します。プロファイラーモジュールエディターを開くには、以下のようにします。
重要:Profiler ウィンドウにデータをロードしていないと、作成したカウンターは、プロファイラーモジュールエディターをロードしたときに Available Counters ペインに表示されません。カスタムカウンターを表示するには、作成したカウンターを含むデータをプロファイラーでキャプチャまたはロードして、プロファイラーモジュールエディターを再度開きます。
その後、Profiler ウィンドウで他のカウンターと一緒にデータを表示することができます。詳細については、カスタムプロファイラーモジュールの作成を参照してください。
注:静的として宣言されたカウンターは、型を初期化する際に C# コードで動的に初期化されます。実際に初期化され、使用するまで利用できない場合があります。これは編集モードと再生モードの両方に適用されます。プロファイラーモジュールエディターにカウンターが表示されない場合は、まずプロファイラーで数フレーム分のデータを記録してください。
ビルドされたプレイヤーでプロジェクトを実行した場合、Profiler ウィンドウにはアクセスできません。ただし、ビルドされたプレイヤーで UI 要素としてカウンターを表示することができます。つまり、アプリケーションのビルドにプロファイリングツールを入れることができます。
以下の画像は、ビルドされたプレイヤーでカスタム UI を使用して、シーンの左上にカウンターを表示しています。
注:(開発ビルドではない) リリース版のプレイヤーでは、すべてのプロファイラーカウンターを利用できるわけではありません。ProfilerRecorder.Valid を使用して、データが利用可能で、プロファイラーがデータを記録できるかどうかを判断します。または、ProfilerRecorderHandle.GetAvailable を使用して、使用可能なすべてのプロファイラー統計を列挙することができます。
プロファイラーのカウンターは、ゲームやエンジンシステムの重要なメトリクスに関するインサイトを提供します。継続的なインテグレーション設定がある場合、またはテスト再生中にアプリケーションの主要なパフォーマンス指標を視覚化したい場合は、ProfilerRecorder API を使用してカスタムおよびビルトインプロファイラーのカウンター値を取得できます。
例えば、以下のスクリプトは、フレーム時間、Mono/IL2CPP ヒープサイズ、およびアプリケーションが使用するメモリの合計量を表示します。
using System.Collections.Generic;
using System.Text;
using Unity.Profiling;
using UnityEngine;
public class StatsScript : MonoBehaviour
{
string statsText;
ProfilerRecorder systemMemoryRecorder;
ProfilerRecorder gcMemoryRecorder;
ProfilerRecorder mainThreadTimeRecorder;
double GetRecorderFrameAverage(ProfilerRecorder recorder)
{
var samplesCount = recorder.Capacity;
if (samplesCount == 0)
return 0;
double r = 0;
unsafe
{
var samples = stackalloc ProfilerRecorderSample[samplesCount];
recorder.CopyTo(samples, samplesCount);
for (var i = 0; i < samplesCount; ++i)
r += samples[i].Value;
r /= samplesCount;
}
return r;
}
void OnEnable()
{
systemMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "System Used Memory");
gcMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "GC Reserved Memory");
mainThreadTimeRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Internal, "Main Thread", 15);
}
void OnDisable()
{
systemMemoryRecorder.Dispose();
gcMemoryRecorder.Dispose();
mainThreadTimeRecorder.Dispose();
}
void Update()
{
var sb = new StringBuilder(500);
sb.AppendLine($"Frame Time: {GetRecorderFrameAverage(mainThreadTimeRecorder) * (1e-6f):F1} ms");
sb.AppendLine($"GC Memory: {gcMemoryRecorder.LastValue / (1024 * 1024)} MB");
sb.AppendLine($"System Memory: {systemMemoryRecorder.LastValue / (1024 * 1024)} MB");
statsText = sb.ToString();
}
void OnGUI()
{
GUI.TextArea(new Rect(10, 30, 250, 50), statsText);
}
}
重要:ProfilerRecorder.Dispose を使用して、ProfilerRecorder に関連付けられたアンマネージリソースを解放します。
エディターでプロファイラーフレームデータを処理するときにプロファイラーカウンターの値を取得するには、FrameDataView API を使用します。
FrameDataView.GetCounterValueAsInt、FrameDataView.GetCounterValueAsLong、FrameDataView.GetCounterValueAsFloat、および FrameDataView.GetCounterValueAsDouble を使用して、以下のように特定のカウンターのフレーム値を取得できます。
using UnityEditor.Profiling;
class Example
{
static int ExtractMyCounterValue(FrameDataView frameData, string counterName)
{
var counterMarkerId = frameData.GetMarkerId(counterName);
return frameData.GetCounterValueAsInt(counterMarkerId);
}
}