통계 시스템 개요

통계 시스템은 언리얼 엔진 프로젝트 최적화에 유용한 퍼포먼스 데이터를 수집 및 표시합니다.

Choose your operating system:

Windows

macOS

Linux

추가 참고
필요한 사전지식

이 페이지의 콘텐츠를 이해하고 활용하기 위해 다음 주제를 숙지해 주세요.

통계 시스템(Stats System) 을 통해 퍼포먼스 데이터를 수집 및 표시하여 게임 최적화에 활용할 수 있습니다.

통계 명령 도움말이 필요하면 콘솔에 stat 을 입력하거나 PrintStatsHelpToOutputDevice(); 메서드를 참조합니다.

타입

통계 시스템은 다음 타입을 지원합니다.

통계 타입

설명

주기 카운터(Cycle Counter)

오브젝트의 수명 동안 주기 횟수를 세는 데 사용되는 일반적 주기 카운터입니다.

Float/Dword 카운터

매 프레임마다 지워지는 카운터입니다.

Float/Dword 축적기

매 프레임마다 지워지지 않고 지속적으로 유지되는 통계 카운터입니다. 리셋 가능합니다.

메모리

메모리 트래킹에 최적화된 특수 타입 카운터입니다.

통계 그룹화

각 통계는 그룹화되어야 하며, 이는 보통 특정 통계 그룹의 표시에 대응합니다. 예를 들어 stat statsystem 은 통계 관련 데이터를 표시합니다.

통계 그룹을 정의하려면 다음 메서드 중 하나를 사용합니다.

메서드

설명

DECLARE_STATS_GROUP(GroupDesc, GroupId, GroupCat)

디폴트로 활성화된 통계 그룹을 선언합니다.

DECLARE_STATS_GROUP_VERBOSE(GroupDesc, GroupId, GroupCat)

디폴트로 비활성화된 통계 그룹을 선언합니다.

DECLARE_STATS_GROUP_MAYBE_COMPILED_OUT(GroupDesc, GroupId, GroupCat)

디폴트로 비활성화되고 컴파일러에 의해 제거될 수 있는 통계 그룹을 선언합니다.

축약어 뜻:

  • GroupDesc 는 그룹에 관한 텍스트 설명입니다.

  • GroupId 는 그룹의 UNIQUE ID입니다.

  • GroupCat 은 향후 사용을 위해 예약됩니다.

  • CompileIn 은 true로 설정될 경우 컴파일러에 의해 제거될 수 있습니다.

사용 범위에 따라 그룹화는 소스 또는 헤더 파일에서 수행될 수 있습니다.

사용 예시

DECLARE_STATS_GROUP(TEXT("Threading"), STATGROUP_Threading, STATCAT_Advanced);
DECLARE_STATS_GROUP_VERBOSE(TEXT("Linker Load"), STATGROUP_LinkerLoad, STATCAT_Advanced);

통계 선언 및 정의하기

이제 통계를 선언 및 정의할 수 있지만, 그 전에 통계는 다음에서 사용할 수 있다는 점에 유의하세요.

  • 단 하나의 cpp 파일

  • 함수 범위

  • 모듈 범위

  • 전체 프로젝트

단일 파일의 경우

단일 파일 범위의 경우 통계 타입에 따라 다음 메서드 중 하나를 사용해야 합니다.

메서드

설명

DECLARE_CYCLE_STAT(CounterName, StatId, GroupId)

주기 카운터 통계를 선언합니다.

DECLARE_SCOPE_CYCLE_COUNTER(CounterName, StatId, GroupId)

주기 카운터 통계를 선언하는 동시에 사용합니다. 또한 하나의 함수 범위로 제한됩니다.

QUICK_SCOPE_CYCLE_COUNTER(StatId)

'Quick'이라고 명명된 통계 그룹에 속할 주기 카운터 통계를 선언합니다.

RETURN_QUICK_DECLARE_CYCLE_STAT(StatId, GroupId)

주기 카운터를 반환합니다. 가끔 일부 특수 클래스에서 사용됩니다.

DECLARE_FLOAT_COUNTER_STAT(CounterName, StatId, GroupId)

float 카운터를 반환하며 double 타입(8바이트)을 기반으로 합니다.

DECLARE_DWORD_COUNTER_STAT(CounterName, StatId, GroupId)

dword 카운터를 반환하며 qword 타입(8바이트)을 기반으로 합니다.

DECLARE_FLOAT_ACCUMULATOR_STAT(CounterName, StatId, GroupId)

float 축적기를 선언합니다.

DECLARE_DWORD_ACCUMULATOR_STAT(CounterName, StatId, GroupId)

dword 축적기를 선언합니다.

DECLARE_MEMORY_STAT(CounterName, StatId, GroupId)

dword 축적기와 동일한 메모리 카운터를 선언합니다. 하지만 특정 메모리 단위로 표시됩니다.

DECLARE_MEMORY_STAT_POOL(CounterName, StatId, GroupId, Pool)

풀이 있는 메모리 카운터를 선언합니다.

다수 파일의 경우

통계를 전체 프로젝트(또는 폭넓은 파일 범위)에서 액세스 가능하게 하려면 extern 버전을 사용해야 합니다. 이 메서드는 이전에 언급한 것과 같지만, 이름 끝에 _EXTERN 이 붙습니다.

DECLARE_CYCLE_STAT_EXTERN(CounterName, StatId, GroupId, API)
DECLARE_FLOAT_COUNTER_STAT_EXTERN(CounterName, StatId, GroupId, API)
DECLARE_DWORD_COUNTER_STAT_EXTERN(CounterName, StatId, GroupId, API)
DECLARE_FLOAT_ACCUMULATOR_STAT_EXTERN(CounterName, StatId, GroupId, API)
DECLARE_DWORD_ACCUMULATOR_STAT_EXTERN(CounterName, StatId, GroupId, API)
DECLARE_MEMORY_STAT_EXTERN(CounterName, StatId, GroupId, API)
DECLARE_MEMORY_STAT_POOL_EXTERN(CounterName, StatId, GroupId, Pool, API)

그런 다음 소스 파일에서 다음 통계를 정의해야 합니다. 이는 _EXTERN 을 붙여 선언한 통계를 정의합니다.

축약어 뜻:

  • CounterName 은 통계에 관한 텍스트 설명입니다.

  • StatId 는 통계의 UNIQUE ID입니다.

  • GroupId 는 통계가 속할 그룹의 ID이며, DECLARE_STATS_GROUP* 에서 온`GroupId`입니다.

  • Pool 은 플랫폼 전용 메모리 풀입니다.

  • API 는 모듈의 *_API 이며 통계가 해당 모듈에서만 사용되는 경우 비어 있을 수 있습니다.

예제

풀이 있는 커스텀 메모리 통계

우선 enum EMemoryCounterRegion 에 새 풀을 추가해야 합니다. 이는 글로벌일 수도 있고 플랫폼 전용일 수도 있습니다.

enum EMemoryCounterRegion
{
    MCR_Invalid,        // 메모리 아님
    MCR_Physical,       // 메인 시스템 메모리
    MCR_GPU,            // GPU의 직접 메모리(그래픽 카드)
    MCR_GPUSystem,      // GPU로 직접 액세스 가능한 시스템 메모리
    MCR_TexturePool,    // 사전에 크기가 지정된 텍스처 풀
    MCR_MAX
};

다음은 풀을 모든 곳에서 사용하도록 허용하는 예시입니다(CORE_API 참조).

풀 이름은 MCR_ 로 시작되어야 합니다.

헤더 파일 샘플

DECLARE_MEMORY_STAT_POOL_EXTERN(TEXT("Physical Memory Pool [Physical]"), MCR_Physical, STATGROUP_Memory, FPlatformMemory::MCR_Physical, CORE_API);
DECLARE_MEMORY_STAT_POOL_EXTERN(TEXT("GPU Memory Pool [GPU]"), MCR_GPU,STATGROUP_Memory, FPlatformMemory::MCR_GPU, CORE_API);
DECLARE_MEMORY_STAT_POOL_EXTERN(TEXT("Texture Memory Pool [Texture]"), MCR_TexturePool, STATGROUP_Memory, FPlatformMemory::MCR_TexturePool,CORE_API);

소스 파일 샘플

DEFINE_STAT(MCR_Physical);
DEFINE_STAT(MCR_GPU);
DEFINE_STAT(MCR_TexturePool);

// 이것은 풀이므로 초기화되어야 합니다. 보통 F*PlatformMemory::Init()에서 수행됩니다.
SET_MEMORY_STAT(MCR_Physical, PhysicalPoolLimit);
SET_MEMORY_STAT(MCR_GPU, GPUPoolLimit);
SET_MEMORY_STAT(MCR_TexturePool, TexturePoolLimit);

// 풀이 생겼으니 풀을 위한 메모리 통계를 구성해야 합니다.

// 다음은 어디서든 액세스 가능합니다.          
DECLARE_MEMORY_STAT_POOL_EXTERN(TEXT("Index buffer memory"), STAT_IndexBufferMemory, STATGROUP_RHI, FPlatformMemory::MCR_GPU, RHI_API);
DECLARE_MEMORY_STAT_POOL_EXTERN(TEXT("Vertex buffer memory"), STAT_VertexBufferMemory, STATGROUP_RHI, FPlatformMemory::MCR_GPU, RHI_API);
DECLARE_MEMORY_STAT_POOL_EXTERN(TEXT("Structured buffer memory"), STAT_StructuredBufferMemory,STATGROUP_RHI, FPlatformMemory::MCR_GPU, RHI_API);
DECLARE_MEMORY_STAT_POOL_EXTERN(TEXT("Pixel buffer memory"), STAT_PixelBufferMemory, STATGROUP_RHI, FPlatformMemory::MCR_GPU, RHI_API);

// 다음은 정의된 모듈에서만 액세스 가능합니다. 
DECLARE_MEMORY_STAT_POOL_EXTERN(TEXT("Pool Memory Size"), STAT_TexturePoolSize, STATGROUP_Streaming, FPlatformMemory::MCR_TexturePool, );
DECLARE_MEMORY_STAT_POOL_EXTERN(TEXT("Pool Memory Used"), STAT_TexturePoolAllocatedSize, STATGROUP_Streaming, FPlatformMemory::MCR_TexturePool, );

// 마지막으로 메모리 통계를 업데이트해야 합니다.

// 메모리 통계를 정해진 값만큼 늘립니다.
INC_MEMORY_STAT_BY(STAT_PixelBufferMemory,NumBytes);
// 메모리 통계를 정해진 값만큼 줄입니다.
DEC_MEMORY_STAT_BY(STAT_PixelBufferMemory,NumBytes);
// 메모리 통계를 정해진 값으로 설정합니다.
SET_MEMORY_STAT(STAT_PixelBufferMemory,NumBytes);

풀이 없는 정규 메모리 통계

DECLARE_MEMORY_STAT(TEXT("Total Physical"), STAT_TotalPhysical, STATGROUP_MemoryPlatform);
DECLARE_MEMORY_STAT(TEXT("Total Virtual"), STAT_TotalVirtual, STATGROUP_MemoryPlatform);
DECLARE_MEMORY_STAT(TEXT("Page Size"), STAT_PageSize, STATGROUP_MemoryPlatform);
DECLARE_MEMORY_STAT(TEXT("Total Physical GB"), STAT_TotalPhysicalGB, STATGROUP_MemoryPlatform);

위 예시 말고 다른 방법으로는 헤더 파일에서 DECLARE_MEMORY_STAT_EXTERN 을 사용한 다음 소스 파일에서 DEFINE_STAT 을 사용할 수도 있습니다.

메모리 통계 업데이트는 풀이 있는 버전과 똑같이 이뤄집니다.

주기 카운터를 사용한 퍼포먼스 데이터

우선 주기 카운터를 추가해야 합니다.

DECLARE_CYCLE_STAT(TEXT("Broadcast"), STAT_StatsBroadcast, STATGROUP_StatSystem);
DECLARE_CYCLE_STAT(TEXT("Condense"), STAT_StatsCondense, STATGROUP_StatSystem);

위 예시 말고 다른 방법으로는 헤더 파일에서 DECLARE_MEMORY_STAT_EXTERN 을 사용한 다음 소스 파일에서 DEFINE_STAT 을 사용할 수 있습니다.

다음으로 퍼포먼스 데이터를 가져옵니다.

Stats::Broadcast()
{
    SCOPE_CYCLE_COUNTER(STAT_StatsBroadcast);
    // ...
    // 코드 부분
    // ...
}

함수가 호출될 때마다 통계를 매번 가져오지 않으려면 조건부 주기 카운터를 사용합니다. 흔하지는 않지만 경우에 따라 유용합니다.

Stats::Broadcast(bool bSomeCondition)
{

    CONDITIONAL_SCOPE_CYCLE_COUNTER(STAT_StatsBroadcast,bSomeCondition);
    // ...
    // 코드 부분
    // ...
}

한 함수에서 퍼포먼스 데이터를 가져오려면 다음 구성을 사용할 수 있습니다.

Stats::Broadcast(bool bSomeCondition)
{
    DECLARE_SCOPE_CYCLE_COUNTER(TEXT("Broadcast"), STAT_StatsBroadcast, STATGROUP_StatSystem);
    // ...
    // 코드 부분
    // ...
}

이렇게 처리해도 됩니다.

Stats::Broadcast(bool bSomeCondition)
{
    QUICK_SCOPE_CYCLE_COUNTER(TEXT("Stats::Broadcast"));
    // ...
    // 코드 부분
    // ...
}

이는 대체로 임시 통계에 사용됩니다.

앞서 언급된 모든 주기 카운터는 계층구조를 생성하여 더욱 상세한 퍼포먼스 데이터 관련 정보를 얻고자 할 때 사용됩니다. 그러나 플랫 주기 카운터를 설정하는 옵션도 있습니다.

Stats::Broadcast(bool bSomeCondition)
{
    const uint32 BroadcastBeginTime = FPlatformTime::Cycles();
    // ...
    // 코드 부분
    // ...
    const uint32 BroadcastEndTime = FPlatformTime::Cycles();
    SET_CYCLE_COUNTER(STAT_StatsBroadcast, BroadcastEndTime-BroadcastBeginTime);
}

GetStatId를 사용한 퍼포먼스 데이터

언리얼 엔진에 구현된 몇 가지 태스크는 퍼포먼스 데이터를 가져오기 위해 다른 접근법을 사용합니다. 이런 태스크는 GetStatId() 메서드를 구현하며, GetStatId() 가 없는 경우 코드가 컴파일되지 않습니다.

예시는 다음과 같습니다.

class FParallelAnimationCompletionTask
{
    // ...
    // 코드 부분
    // ...
    FORCEINLINE TStatId GetStatId() const
    {
        RETURN_QUICK_DECLARE_CYCLE_STAT(FParallelAnimationCompletionTask, STATGROUP_TaskGraphTasks);
    }
    // ...
    // 코드 부분
    // ...
};

퍼포먼스 데이터 로깅

퍼포먼스 데이터를 로깅만 하려는 경우를 위해 다음 함수 기능이 있습니다.

메서드

다음 메서드는 시간(단위: 초)을 캡처하고 전달되는 변수에 델타 시간을 추가합니다.

SCOPE_SECONDS_COUNTER(double& Seconds)

코드 샘플

Stats::Broadcast()
{
    double ThisTime = 0;
    {
       SCOPE_SECONDS_COUNTER(ThisTime);
        // ...
        // 코드 부분
        // ...
    }
    UE_LOG(LogTemp, Log, TEXT("Stats::Broadcast %.2f"), ThisTime);  
}

유틸리티 클래스 및 메서드

클래스

설명

FScopeLogTime

시간(단위: 초)을 로깅하는 유틸리티 클래스입니다. 전달된 변수에 누적 통계를 추가하며 퍼포먼스 데이터를 소멸자의 로그에 출력합니다.

메서드

설명

SCOPE_LOG_TIME(Name, CumulativePtr)

제공된 이름을 사용하여 퍼포먼스 데이터를 출력하고 누적 통계를 수집합니다.

SCOPE_LOG_TIME_IN_SECONDS(Name, CumulativePtr)

SCOPE_LOG_TIME과 동일한 함수 기능이지만 초 단위로 출력합니다.

SCOPE_LOG_TIME_FUNC()

함수 이름을 사용하여 퍼포먼스 데이터를 출력하며 중첩이 불가능합니다.

SCOPE_LOG_TIME_FUNC_WITH_GLOBAL(CumulativePtr)

SCOPE_LOG_TIME_FUNC와 동일한 함수 기능이지만 누적 통계를 수집합니다.

코드 샘플

double GMyBroadcastTime = 0.0;
Stats::Broadcast()
{
    SCOPE_LOG_TIME("Stats::Broadcast", &GMyBroadcastTime);
    SCOPE_LOG_TIME_IN_SECONDS("Stats::Broadcast (sec)", &GMyBroadcastTime);
    // ...
    // 코드 부분
    // ...
}

Stats::Condense()
{
    SCOPE_LOG_TIME_FUNC(); // The name should be "Stats::Condense()", may differ across compilers
    SCOPE_LOG_TIME_FUNC_WITH_GLOBAL(&GMyBroadcastTime);
    // ...
    // 코드 부분
    // ...
}

FLOAT 또는 DWORD 카운터를 사용한 일반 데이터

일반적으로 가장 먼저 다음과 같이 카운터를 추가해야 합니다.

DECLARE_FLOAT_COUNTER_STAT_EXTERN(STAT_FloatCounter,StatId,STATGROUP_TestGroup, CORE_API);
DECLARE_DWORD_COUNTER_STAT_EXTERN(STAT_DwordCounter,StatId,STATGROUP_TestGroup, CORE_API);
DECLARE_FLOAT_ACCUMULATOR_STAT_EXTERN(STAT_FloatAccumulator,StatId,STATGROUP_TestGroup, CORE_API);
DECLARE_DWORD_ACCUMULATOR_STAT_EXTERN(STAT_DwordAccumulator,StatId,STATGROUP_TestGroup, CORE_API);

카운터를 업데이트 및 관리하려면 다음 메서드를 사용합니다.

카운터 업데이트 메서드

메서드

설명

INC_DWORD_STAT(StatId)

dword 통계를 1 늘립니다.

DEC_DWORD_STAT(StatId)

dword 통계를 1 줄입니다.

INC_DWORD_STAT_BY(StatId, Amount)

dword 통계를 지정된 값만큼 늘립니다.

DEC_DWORD_STAT_BY(StatId, Amount)

dword 통계를 지정된 값만큼 줄입니다.

SET_DWORD_STAT(StatId, Value)

dword 통계를 지정된 값으로 설정합니다.

INC_FLOAT_STAT_BY(StatId, Amount)

float 통계를 지정된 값만큼 늘립니다.

DEC_FLOAT_STAT_BY(StatId, Amount)

float 통계를 지정된 값만큼 줄입니다.

SET_FLOAT_STAT(StatId, Value)

float 통계를 지정된 값으로 설정합니다.

카운터 관리를 위한 헬퍼 메서드

메서드

설명

GET_STATID(StatId)

통계의 TStatId 인스턴스를 반환합니다.

고급 기능입니다.

GET_STATDESCRIPTION(StatId)

통계 설명을 반환합니다.

태그
언리얼 엔진의 이전 버전을 위해 작성된 페이지입니다. 현재 언리얼 엔진 5 버전을 위해 업데이트되지 않았습니다.