【Unity】スクリプトがどれくらい負荷が掛かっているかを調査(プロファイラー調査)

2024年3月10日

Unityでは、どの処理にどれくらい時間がかかっているかを調べるツールが備わっています
Profilerを使い、様々な調査をしてボトルネックになっているところを調べてみましょう

今回はそのうちの1つ、スクリプトが処理にどれくらい営業しているかを調べてみます

環境

ハードウェア

Mac Studio 2022 (Apple M1 Max) 32GB

チップセットの機種: Apple M1 Max

  • 機種名: Mac Studio
    機種ID: Mac13,1
    チップ: Apple M1 Max
    コアの総数: 10(パフォーマンス: 8、効率性: 2)
    メモリ: 32 GB
  • 種類: GPU
    バス: 内蔵
    コアの総数: 24
    製造元: Apple(0x106b)
    Metalファミリー: 対応、Metal GPUFamily Apple 7

Unity バージョン

  • 2022.1.17f1

シーンの構築

DebugSampleとしてプロジェクトを作成しましょう
1つのゲームオブジェクト、1つのスクリプトで構成します

Profilerツールの起動方法

Windowメニューから起動します

テストコード

調査にため、高負荷がかかる処理のコードを作成します

using UnityEngine;
using UnityEngine.Profiling;

public class ProfileTest : MonoBehaviour
{
    Renderer renderer;

    private void Start()
    {
        renderer = GetComponent<Renderer>();
    }

    void Update()
    {
        Profiler.BeginSample("負荷テスト");

        for (int i = 0; i < 100000; i++)
        {
            // ここに負荷のかかるコードを記述してテストします
        }

        Profiler.EndSample();
    }
}

コードの説明

プロファイリングの時に目印としてコメントを追加したいので、名前空間を追加します

using UnityEngine.Profiling;

コンポーネントを取得して、フィールド変数に代入しています
コンポーネントが変化しないため、先にキャッシュしています

Renderer renderer;

private void Start()
{
    renderer = GetComponent<Renderer>();
}

このスクリプト内でどこからどこまでを計測範囲とするかを指定しています
LoadTest(翻訳:負荷テスト)のところは自由に変更できます

Profiler.BeginSample("負荷テスト");
// この間に記述されているコードの実行時間を計測
Profiler.EndSample();

負荷のかかるサンプルコード

GetComponentメソッドをUpdateメソッド内で実行

GetComponnetメソッドは、Updateで都度呼び出さないのがセオリーと言われていますが、それのテストをします
次のコードでは、Startメソッドで一旦代入されているフィールドに再代入(上書き)しています
なのでStartのrendrerの値は無効になります

// この間に記述されているコードの実行時間を計測のところに追加

renderer = GetComponent<Renderer>();

追加したコード全体

using UnityEngine;
using UnityEngine.Profiling;

public class ProfileTest : MonoBehaviour
{
    Renderer renderer;

    private void Start()
    {
        renderer = GetComponent<Renderer>();
    }

    void Update()
    {
        Profiler.BeginSample("負荷テスト");

        for (int i = 0; i < 100000; i++)
        {
            renderer = GetComponent<Renderer>();
        }

        Profiler.EndSample();
    }
}

Profilerでの測定

Cube1つだけですが、すでに30fpsくらいになっています
スクリプトだけで、25msかかっています
複数のゲームオブジェクトで同じように実行されるとゲーム全体で高負荷になることがわかります

負荷を軽減するサンプルコード

Startメソッドで取得したコンポーネントを例えばUpdateメソッドで使うことを想定して次のコードに置き換えてみます

Renderer getRenderer = renderer;

更新したコード全体

using UnityEngine;
using UnityEngine.Profiling;

public class ProfileTest : MonoBehaviour
{
    Renderer renderer;

    private void Start()
    {
        renderer = GetComponent<Renderer>();
    }

    void Update()
    {
        Profiler.BeginSample("負荷テスト");

        for (int i = 0; i < 100000; i++)
        {
            Renderer getRenderer = renderer;
        }

        Profiler.EndSample();
    }
}

Profilerでの測定

250fps以上でています
スクリプトだけでは、0.12msくらいに収まっています

参考)Debug.Logメソッドの場合

Debug.Logの負荷は高いですが、実際にどれくらいか見てみましょう

Debug.Log("Test");

結果

ほとんど、ハングアップ状態です
3.2秒かかっていますので明らかにコマ落ちしています(厳密には描画するできていません)

詳細を確認

キャプチャー上はLoatTestになっていますが、ここは「負荷テスト」と考えてください

全体の94%を処理に使っているのがわかります

参考

Unity,デバッグ

Posted by hidepon