TRACE_CPUPROFILER_EVENT_SCOPEによるお手軽C++プロファイリング![UE5.1]

こんにちは!
株式会社アドグローブ ゲーム事業部エンジニアの林です。
今回はUnreal Engine(以降 UE )でのプロファイリング時に使用できるTRACE_CPUPROFILER_EVENT_SCOPEについて紹介します。
UEでのプロファイリングを行う上では必須級の機能なのですが、現時点では日本語での解説記事をあまり見かけません。
コードを一行追加するだけで簡単に使用することができるので、ぜひ使っていきましょう!

本記事ではTRACE_CPUPROFILER_EVENT_SCOPEの機能について簡単なサンプルを通して紹介していきます。

※執筆バージョン: UE5.1.1

目次

TRACE_CPUPROFILER_EVENT_SCOPEとは

簡潔にまとめると、C++コードの処理負荷を確認するための機能になります。
UEでC++コードの処理負荷を確認する場合、主にUnreal Insightsを使用することになると思います。
ですがUnreal InsightsではC++コードの処理負荷を確認しようとしても、デフォルトの状態では確認することが出来ず、C++コードに処理負荷があることがわかっていても、どの処理が原因なのかまで特定することは出来ません。
TRACE_CPUPROFILER_EVENT_SCOPEを使用することで、C++コードの処理負荷をUnreal Insights上で確認できるようになり、原因を特定しやすくなります。

左: デフォルトのUnreal Insights 右: TRACE_CPUPROFILER_EVENT_SCOPEを追加した場合TRACE_CPUPROFILER_EVENT_SCOPEを追加したC++コードの負荷が表示されている

公式ドキュメントにも機能の説明があります。詳しくはこちらをご参照下さい。
docs.unrealengine.com

本記事ではUnreal Insightsを使用していますが、基本的な使い方の説明は省略させて頂きます。
Unreal Insightsの基本的な使い方については公式ドキュメントをご参照下さい。
docs.unrealengine.com

TRACE_CPUPROFILER_EVENT_SCOPEを実際に使ってみる

使い方は至って簡単で、処理負荷を確認したいC++コードにTRACE_CPUPROFILER_EVENT_SCOPEを一行追加するだけです。
サンプルを通して使い方を確認していきます。

サンプルコード

今回は以下のC++クラスをサンプルとして使用します。

// MyCppActor.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyCppActor.generated.h"

UCLASS()
class SAMPLE_PRJ_API AMyCppActor : public AActor
{
    GENERATED_BODY()
    
public: 
    AMyCppActor();
public: 
    virtual void Tick(float DeltaTime) override;
};
// MyCppActor.cpp
#include "MyCppActor.h"

AMyCppActor::AMyCppActor()
{
    PrimaryActorTick.bCanEverTick = true;
}

void AMyCppActor::Tick(float DeltaTime)
{
    // 重たい処理1
    for(int32 i = 0; i < 100; ++i)
    {
        UE_LOG(LogTemp, Log, TEXT("Omotai 1"));
    }
    // 重たい処理2
    for(int32 i = 0; i < 1000; ++i)
    {
        UE_LOG(LogTemp, Log, TEXT("Omotai 2"));
    }
}

サンプル用にTick内に2つのforループを設けてあります。
TRACE_CPUPROFILER_EVENT_SCOPEを使用して、これらの処理をUnreal Insights上で確認していきます。

挙動確認

まずはデフォルトの挙動を確認してみます。

  1. Editor上で空のレベルを作成し、MyCppActorを継承したBlueprintを作成してレベルに配置
  2. ツールバーからTools > Run Unreal Insightsを選択してUnreal Insights Session Browserを起動
  3. Editor上で実行モードをSelected ViewportからStandalone Gameに変更
  4. Editor上で実行(初回はStandalone Gameに切り替えたタイミングで実行されます)
  5. Unreal Insights Session BrowserにLIVEと書かれたSessionが追加されるので、ダブルクリックで開く
Unreal Insights Session Browserと"LIVE"表記のセッション

Unreal Insights上のGameThreadFEngineLoop::Tick部分を拡大します。

※添付画像ではGameThread以外のTrackを非表示にしています。

この段階ではAMyCppActor::Tick()に対応する処理は確認できません。

TRACE_CPUPROFILER_EVENT_SCOPEを追加する

AMyCppActor::Tick()にTRACE_CPUPROFILER_EVENT_SCOPEを追加します。

void AMyCppActor::Tick(float DeltaTime)
{
    TRACE_CPUPROFILER_EVENT_SCOPE(AMyCppActor::Tick)    // << 追加
    
    // 重たい処理1
    for(int32 i = 0; i < 100; ++i)
    {
        UE_LOG(LogTemp, Log, TEXT("Omotai 1"));
    }

    // 重たい処理2
    for(int32 i = 0; i < 1000; ++i)
    {
        UE_LOG(LogTemp, Log, TEXT("Omotai 2"));
    }
}

ビルド後に再度実行します。
※Live Codingでは反映されないようなので、IDEから再度ビルドする必要があるようです。

TRACE_CPUPROFILER_EVENT_SCOPE追加後

拡大していくと、先程追加したAMyCppActor::Tickという項目を確認することが出来ました。

TRACE_CPUPROFILER_EVENT_SCOPEで追加した"AMyCppActor::Tick"を確認

TRACE_CPUPROFILER_EVENT_SCOPEで処理負荷の詳細を確認する

TRACE_CPUPROFILER_EVENT_SCOPEはスコープを分割していくことでよりピンポイントの処理負荷を確認することが出来ます。
サンプルコードの2つのforループの負荷をUnreal Insights上で確認できるようにしていきます。
AMyCppActor::Tick()を以下のように編集します。

void AMyCppActor::Tick(float DeltaTime)
{
    TRACE_CPUPROFILER_EVENT_SCOPE(AMyCppActor::Tick)
    
    {
        TRACE_CPUPROFILER_EVENT_SCOPE(AMyCppActor::Tick::Omotai_1)
        // 重たい処理1
        for (int32 i = 0; i < 100; ++i)
        {
            UE_LOG(LogTemp, Log, TEXT("Omotai 1"));
        }
    }

    {
        TRACE_CPUPROFILER_EVENT_SCOPE(AMyCppActor::Tick::Omotai_2)
        // 重たい処理2
        for (int32 i = 0; i < 1000; ++i)
        {
            UE_LOG(LogTemp, Log, TEXT("Omotai 2"));
        }
    }
}

再度ビルドしてから実行し、Unreal Insightsを確認します。
無事に追加したAMyCppActor::Tick::Omotai_1AMyCppActor::Tick::Omotai_2を確認することが出来ました。

Unreal Insights上で"AMyCppActor::Tick::Omotai_1"と"AMyCppActor::Tick::Omotai_2"を確認

C++コードからは明確でしたが、Omotai_2の方が処理時間がかかっていることをUnreal Insights上でも実際に確認することが出来ました。

まとめ

サンプルコードを用いてTRACE_CPUPROFILER_EVENT_SCOPEの機能を確認しました。
今回は簡単なサンプルを用いましたが実際のプロジェクトに応用していくことも出来ます。
C++コードに一行追記するだけで処理負荷を手軽に確認することができるので、プロファイリングしていく上では必須級の機能だと思います。
ぜひ有効活用していきましょう!
最後までお読みいただき、ありがとうございました!


現在アドグローブでは、さまざまなポジションで一緒に働く仲間を募集しています。
詳細については下記からご確認ください。みなさまからのご応募お待ちしております。

hrmos.co