How To Use The PerformanceCollector API To Instrument Key Performance Metrics - o3de/o3de GitHub Wiki

The PerformanceCollector API was introduced in this PR: https://github.com/o3de/o3de/pull/12551.

The first customer of the API is the RPISystemComponent RPISystemComponent Initializing The PerformanceCollector.

The Unit Test is available at: PerformanceCollectorTests.cpp

How To Use The PerformanceCollector API

1. Make an instance of the PerformanceCollector:

#include <AzCore/Debug/PerformanceCollector.h>

class MyClass {
    AZStd::unique_ptr<AZ::Debug::PerformanceCollector> m_performanceCollector;
}

2. Define in advance the Key Performance Metrics.

In this hypothetical example we'll collect two metrics:

2.1. RunAI Time: Measures the duration of a function named MyClass::RunAI().
2.2. EnemySearchUpdate Time: Measures the time spent between calls of a function called MyClass::OnEnemySearchUpdated().

#include <AzCore/Debug/PerformanceCollector.h>

class MyClass {
    void RunAI();
    void OnEnemySearchUpdated()();

    static constexpr string_view RunAITime = "RunAI Time";
    static constexpr string_view EnemySearchUpdateTime = "EnemySearchUpdate Time";
    AZStd::unique_ptr<AZ::Debug::PerformanceCollector> m_performanceCollector;
}

3. Initialize The PerformanceCollector.

MyClass::MyClass()
{
    auto onBatchCompleteCallback = [](AZ::u32 pendingBatches) {
        AZ_TracePrintf("AISystem", "Completed a performance batch, still %u batches are pending.\n", pendingBatches);
    };

    auto performanceMetrics = AZStd::to_array<AZStd::string_view>({
        RunAITime ,
        EnemySearchUpdateTime,
    });
    m_performanceCollector = AZStd::make_unique<AZ::Debug::PerformanceCollector>(
                "AI", performanceMetrics, onBatchCompleteCallback);
}

4. Collecting The Metrics.

// In this example we are measuring the time spent, in microseconds, inside the RunAI()
// function.
void MyClass::RunAI()
{
    AZ::Debug::ScopeDuration duration(m_performanceCollector.get(), RunAITime );
    ... Many lines of code ...
}

// In this example we are measuring the time spent "In Between" calls of OnEnemySearchUpdated().
// In other words, this doesn't measure the duration of OnEnemySearchUpdated(), instead, it is assumed
// that this function is periodically called, and we want to measure how long it takes in between calls
// of this function.
void MyClass::OnEnemySearchUpdated()
{
    m_performanceCollector->RecordPeriodicEvent(EnemySearchUpdateTime );
}

5. The PerformanceCollector Must Be Ticked Each Frame.

void MyClass::OnTick()
{
    m_performanceCollector->FrameTick();
}

6. About The Collected Data

The PerformanceCollector will create a JSON File, in the Google Trace format. The amount of data that will be output depends on the value of PerformanceCollector::m_dataLogType.