CPU 및 GPU 최적화 도움말

이 문서에서는 도구를 사용하여 CPU 및 GPU 병목 현상을 식별하고 해결하여 게임 성능을 최적화하는 방법을 보여줍니다.

CPU 최적화

분석 결과 게임이 CPU에 좌우되는 것으로 나타나면 추가 조사가 필수입니다. 이를 위해서는 병목 현상을 일으키고 FPS를 줄이는 특정 스레드나 API를 식별해야 합니다.

CPU 최적화의 경우 범용 솔루션은 일반적으로 효과적이지 않습니다. 대신 게임이나 장면을 기반으로 가장 까다로운 워크로드를 식별한 다음 관련 로직과 함수를 최적화해야 합니다.

게임 엔진 타이밍 추적 도구

다음 도구를 사용하면 이 분석에 도움이 됩니다.

Unreal Insights

Unreal Engine 프로젝트 내에서 Unreal Insight Tool을 사용하면 프레임을 구성하는 개별 스레드의 타이밍 추적 정보를 분석할 수 있습니다.

예를 들어 GameThread는 일반적으로 CPU 시간의 가장 큰 비율을 사용하며 이는 주로 틱 시간 때문입니다. 또한 틱 시간의 상당 부분이 FActorComponentTickFunction와 연결된 작업에 의해 소비됩니다.

FActorComponentTick를 최적화하려면 계산을 제외하고 카메라의 시야 밖에 있는 캐릭터와 객체에 대해 컬링을 구현해야 합니다. 또한 LOD (세부사항 수준) 기반 애니메이션을 활용하면 성능을 더욱 향상할 수 있습니다.

GameThread, RenderThread, RHIThread 실행 시간을 보여주는 Unreal Insight 트레이스 타임라인
GameThread, RenderThread, RHIThread가 포함된 Unreal 통계 트레이스 (확대하려면 클릭)

Unity Profiler (Unity)

Unity Profiler를 사용한 분석에 따르면 Main Thread가 45ms 이상을 소비하며 PostLateUpdate.FinishFrameRendering이 16.23ms를 차지하여 가장 시간이 많이 소요되는 작업으로 나타납니다. 이 안에서 Inl_RenderCameraStack이 여러 번 호출되는 것이 관찰됩니다. 사용 설정된 카메라의 필요성을 확인하고 그에 따라 최적화하는 것이 좋습니다.

Gfx.WaitForPresentOnGfxThread에서 대기하는 기본 스레드를 보여주는 Unity 프로파일러 타임라인
Unity 프로파일러의 GPU 바운드 예 (확대하려면 클릭)

시스템 수준 프로파일링 도구

다음 프로파일링 도구를 사용하세요.

Perfetto

Perfetto 트레이스를 사용하면 Android 기반 기기에서 각 스레드의 CPU 코어 할당 및 실행 세부정보를 확인할 수 있습니다. 이렇게 하면 스레드 실행 데이터를 분석하여 성능 병목 현상을 식별할 수 있습니다.

CPU 오버헤드 사례

트레이스에 따르면 GameThread와 RenderThread의 워크로드로 인해 RHI 스레드의 QueuePresent가 지연되어 VSync에 따라 CPU 바운드 시나리오가 발생합니다.

GameThread, RenderThread, RHIThread의 실행 시간을 보여주는 Perfetto 트레이스
CPU 실행 세부정보가 포함된 Perfetto 트레이스 (확대하려면 클릭)

GPU 오버헤드 사례

트레이스에 따르면 GPU 완료 자체가 25ms를 초과하며 이는 GPU 바운드 시나리오를 나타냅니다.

GPU 완료를 기다리는 GPU 완료 블록을 보여주는 Perfetto 트레이스
GPU 오버헤드 세부정보가 포함된 Perfetto 트레이스 (확대하려면 클릭)

Simpleperf

현재 CPU 사용량이 가장 높은 함수를 식별하려면 simpleperf를 사용할 수 있습니다. 최적의 결과를 얻으려면 이러한 함수를 정렬하여 사용량이 가장 많은 함수를 먼저 우선순위로 지정하고 해결하는 것이 좋습니다.

CPU 사용량이 가장 높은 함수를 표시하는 Simpleperf 출력
Simpleperf CPU 프로파일링: 함수 호출 계층 구조 및 리소스 사용량 분석 (확대하려면 클릭)

Simpleperf를 사용하면 CPU 시간을 가장 많이 사용하는 함수에 관한 데이터를 검사할 수 있습니다. CPU 사용량을 최적화하려면 CPU를 가장 많이 사용하는 함수부터 시작하세요. 이 예에서 USkeletalMeshComponentActorComponentTickFunctions의 애니메이션과 연결되어 있으며 CPU를 가장 많이 사용합니다.

GPU 최적화

분석 결과 게임이 GPU에 바인딩된 것으로 나타나면 추가 조사가 필요합니다. 이를 위해서는 GPU 최적화 및 분석을 위한 다양한 도구와 기술을 사용해야 합니다.

GPU를 최적화하려면 프레임 디버거를 사용하여 각 장면의 렌더링 파이프라인과 그리기 호출을 분석하세요. 또한 불필요한 작업이나 최적화할 영역을 식별하려면 GPU 아키텍처와 파이프라인 동작을 철저히 이해해야 합니다.

다음 섹션에서는 GPU 최적화 방법과 도구를 설명합니다.

불필요한 RenderPass 삭제

렌더링 성능을 개선하고 GPU 워크로드를 줄이려면 불필요한 렌더링 패스를 삭제하세요. 여기에는 그리기 호출이 없거나 출력이 최종 프레임에 사용되지 않는 렌더링 패스가 포함됩니다.

RenderDoc와 같은 GPU 디버거를 사용하여 렌더링 파이프라인을 분석하고 최적화 기회를 파악합니다.

  1. 그리기 호출 없음: 렌더링 패스에 그리기 호출이 포함되어 있는지 확인합니다. 드로우 호출이 없으면 패스를 삭제합니다.

  2. 사용되지 않는 출력: 후속 패스에서 렌더링 패스 출력(예: 색상 또는 깊이)에 액세스하거나 이를 표시하는지 확인합니다. 그렇지 않으면 패스를 삭제합니다.

  3. 병합 가능한 패스: 병합할 수 있는 패스를 식별합니다.

    • 동일한 프레임 버퍼 또는 첨부파일
    • 호환되는 로드 또는 저장 작업
    • 사이에 종속 항목 장벽이 없음
Vulkan 렌더링 패스와 그리기 호출을 표시하는 RenderDoc 이벤트 브라우저
RenderDoc의 RenderPass 및 GPU 명령 시퀀스 (확대하려면 클릭)

로드 또는 저장 작업 최소화

로드 또는 저장 작업은 메모리를 많이 사용하므로 리소스 집약적입니다. 불필요한 로드-저장 작업을 최소화합니다. 이러한 작업은 RenderPass 내 첨부파일이 필요한 경우에만 실행하세요. 그렇지 않으면 오버헤드를 줄이기 위해 Clear 또는 Don't care 작업으로 대체합니다.

최적화 방법

RenderDoc와 같은 GPU 디버거를 사용하여 렌더링 파이프라인을 분석하고 다음 최적화 기회를 식별합니다.

  1. 로드: 렌더링 패스 첨부파일이 이전 패스나 첨부파일의 데이터를 사용하지 않는 경우 로드 작업은 불필요합니다. 이러한 경우 Don't care 또는 Clear을 사용하면 오버헤드를 줄일 수 있습니다.

  2. 저장: 현재 렌더링 패스 후에 렌더링 패스 첨부파일이 사용되지 않으면 저장 작업이 불필요합니다. 이러한 경우에는 Don't care 또는 Clear을 사용합니다.

  3. 바꾸기: 최종 프레임에 영향을 미치지 않고 현재 로드 또는 저장 설정을 Clear 또는 Don't Care로 바꿀 수 있는지 확인합니다.

이미지 레이아웃과 렌더링 패스를 분석하는 RenderDoc 이벤트 브라우저 및 리소스 인스펙터
RenderDoc 렌더링 파이프라인 분석 (확대하려면 클릭)

조기 Z를 사용 설정하기 위해 삭제 방지

Early-Z는 모바일 플랫폼의 성능을 개선합니다. 하지만 셰이더 내의 discard 명령어가 자동으로 Early-Z를 사용 중지합니다. discard 명령어가 필수적이지 않다면 삭제합니다.

Early-Z 가속

이 최적화는 프래그먼트 셰이더 작업을 크게 줄이고 GPU 성능을 개선합니다.

Early-Z 깊이 및 스텐실 테스트

Early-Z 사용 설정 시와 사용 중지 시의 CPU 및 GPU 성능 측정항목을 비교하는 표
Early-Z 가속의 성능 영향 (확대하려면 클릭)

최적화 방법

RenderDoc와 같은 GPU 디버거를 사용하여 렌더링 파이프라인을 분석하고 다음 최적화 기회를 식별합니다.

  1. 프래그먼트 셰이더에서 discard 사용: discard 키워드는 프래그먼트의 가시성이 미리 알려지지 않기 때문에 GPU가 조기 깊이 테스트를 실행하지 못하도록 합니다.

  2. gl_FragDepth 수정: gl_FragDepth을 동적으로 수정하면 프래그먼트의 깊이가 변경되므로 프래그먼트 처리 전에 최종 깊이를 알 수 없어 Early-Z 최적화가 사용 중지됩니다.

  3. 알파-커버리지 사용 설정: 알파-커버리지가 사용 설정된 경우 (MSAA 렌더링에서 자주 사용됨) 프래그먼트 커버리지는 알파 값에 따라 달라집니다. 이로 인해 심도 테스트가 지연되고 Early-Z가 사용 중지될 수 있습니다.

삭제 셰이더 키워드가 있는 경우와 없는 경우의 픽셀당 프래그먼트 비교
분석을 위한 RenderDoc GPU 디버거 (확대하려면 클릭)

텍스처 형식 최적화

최적의 텍스처 형식 선택은 메모리 소비를 줄이고, 대역폭 효율성을 높이며, 렌더링 성능을 개선합니다. 과도하게 높은 정밀도 형식을 사용하면 시각적 이점을 제공하지 않고 GPU 리소스를 낭비할 수 있습니다.

최적화 방법

RenderDoc와 같은 GPU 디버거를 사용하여 렌더링 파이프라인을 분석하고 다음 최적화 기회를 식별합니다.

  1. 깊이-스텐실 버퍼에 D32S8 대신 D24S8 사용: 깊이-스텐실 버퍼에 D24S8를 사용하면 대부분의 애플리케이션에서 시각적 품질의 차이가 거의 또는 전혀 없이 D32S8에 비해 메모리 소비가 20% 감소합니다.
  2. 색상 텍스처에 ASTC 압축 사용: ASTC 압축은 비압축 형식에 비해 텍스처 메모리 사용량을 최대 8배까지 크게 줄이면서 높은 시각적 품질을 유지합니다.
  3. 전체 부동 소수점 대신 절반 부동 소수점 형식 사용: R16F 또는 RG16F을 사용하여 메모리 대역폭과 스토리지 소비를 줄입니다. 이러한 형식은 후처리 버퍼에 적합합니다.

지오메트리 복잡성 최적화

기하학적 복잡성을 최소화하면 특히 GPU 기능이 제한된 모바일 기기에서 렌더링 성능이 향상됩니다. 여기에는 꼭짓점과 삼각형 수를 줄이고, 객체를 통합하여 그리기 호출을 줄이고, 렌더링되지 않거나 불필요한 지오메트리를 제거하는 작업이 포함됩니다. 메시 단순화, 세부사항 수준 (LOD), 시야각 또는 폐색 컬링과 같은 기술을 사용하면 GPU 워크로드를 크게 줄이고 프레임 속도를 높일 수 있습니다.

최적화 방법

프로파일링 도구와 GPU 디버거(예: RenderDoc, Android GPU 검사기 또는 기타 성능 분석기)를 사용하여 지오메트리 관련 성능 병목 현상을 식별합니다.

  1. 삼각형 수 줄이기: 특히 작거나 멀리 있는 객체의 경우 다각형 사용을 최소화합니다.

  2. 세부정보 레벨 (LOD) 사용: 카메라 거리에 따라 더 간단한 메시가 자동으로 사용됩니다.

  3. 작은 메시 병합: 정적 객체를 통합하여 그리기 호출과 CPU 오버헤드를 줄입니다.

  4. 절두체 및 폐색 컬링: 뷰 외부에 있거나 다른 요소에 의해 가려진 객체의 렌더링을 피합니다.

불필요한 첨부파일 삭제

렌더링 패스 첨부파일 (예: 색상, 깊이, 스텐실)은 사용되지 않더라도 메모리 대역폭과 GPU 리소스를 소비합니다. 불필요하거나 중복된 첨부파일을 삭제하면 특히 모바일 플랫폼에서 성능이 개선되고 전력 소비가 줄어듭니다.

최적화 방법

RenderDoc, Android GPU Inspector 또는 기타 성능 분석기와 같은 프로파일링 도구와 GPU 디버거를 사용하여 지오메트리 관련 성능 병목 현상을 식별합니다.

  1. 실제 사용량 확인: 첨부 파일에 쓰거나 첨부 파일에서 읽는 드로우 호출이나 셰이더가 있나요?
  2. 프레임 출력 분석: RenderDoc 또는 유사한 유틸리티를 사용하여 첨부파일이 최종 이미지에 기여하는지 확인합니다.
  3. 임시 또는 더미 첨부파일 고려: 영구 스토리지가 필요하지 않은 임시 데이터에는 임시 첨부파일이나 'Don't Care' 저장소 작업을 사용해야 합니다.

셰이더 정밀도 최적화

셰이더 내에서 과도하게 높은 정밀도 (예: mediump 또는 lowp 대신 highp)를 사용하면 특히 모바일 GPU에서 GPU 워크로드, 전력 소비, 레지스터 압력이 증가합니다. 변수 (예: 위치, 색상, UV)에 적절한 최저 정밀도를 사용하면 눈에 띄는 시각적 영향 없이 성능을 개선할 수 있습니다.

mediump와 highp 셰이더 정밀도를 사용할 때 CPU와 GPU 성능 측정항목을 비교하는 표
셰이더 정밀도의 성능 영향 (확대하려면 클릭)

최적화 방법

프로파일링 도구와 GPU 디버거(예: RenderDoc, Android GPU 검사기) 또는 기타 성능 분석기를 사용하여 지오메트리 관련 성능 병목 현상을 식별합니다.

  1. 셰이더 코드 검토: 셰이더 변수를 평가하고 깊이 또는 화면 공간 계산과 같이 필요한 경우에만 높은 정밀도가 사용되는지 확인합니다. 높은 정밀도가 필요하지 않은 색상, UV 좌표 또는 값에는 중간 또는 낮은 정밀도를 사용합니다.

  2. GPU 디버거 사용: RenderDoc 또는 모바일 GPU 프로파일러 (예: AGI, Mali/GPU Inspector)와 같은 진단 유틸리티는 정밀도 문제와 관련된 레지스터 사용량 증가 또는 셰이더 정지를 식별합니다.

mediump를 사용하는 셰이더 코드와 함께 16비트 보간을 표시하는 Mali Varying Usage 프로파일러
프로파일링 도구 및 GPU 디버거의 예 (확대하려면 클릭)

뒷면 제거 사용 설정

카메라에서 멀리 떨어진 삼각형 (뒷면)을 렌더링하는 것은 솔리드 객체에 불필요한 경우가 많습니다.

최적화 방법

VK_CULL_MODE_NONE를 사용하면 GPU가 앞면과 뒷면을 모두 렌더링해야 하므로 렌더링 작업 부하가 증가하여 성능에 부정적인 영향을 미칠 수 있습니다.

vkCmdSetCullMode가 VK_CULL_MODE_NONE으로 설정된 Vulkan 명령어 로그
뒷면 컬링이 적용된 디버그 로그 (확대하려면 클릭)

UI 장면에서 오버드로 최소화

특히 UI 장면에서 불필요한 그리기 호출과 렌더링 패스를 없애 렌더링 성능을 향상하고 GPU 워크로드를 줄입니다. 예를 들어 화면 전체에 UI를 오버레이하기 전에 전체 세계를 렌더링하는 UI 장면에서 세계를 렌더링하는 것은 중복됩니다.

최적화 방법

RenderDoc와 같은 GPU 디버거를 사용하여 렌더링 파이프라인을 분석하고 다음 최적화 기회를 식별합니다.

  1. 불필요한 오버드로우가 없는지 확인합니다. 전체 화면이 렌더링될 수 있는 사용자 인터페이스 컨텍스트에서 이전 렌더링 패스가 불필요하게 오버드로되지 않는지 확인합니다.
  2. 성능을 최적화하기 위해 깊이 테스트와 컬링을 사용 설정합니다.
  3. 앞에서 뒤로 렌더링 순서를 고려하세요.
불필요한 오버드로우 렌더링 패스를 식별하는 RenderDoc 이벤트 브라우저 및 텍스처 뷰어
불필요한 그리기 호출 및 렌더링 패스를 제거하는 예시 (확대하려면 클릭)