Unity 검색

A red mannequin in a 3d setting
A red mannequin in a 3d setting
다루는 주제
공유

유니티의 프로파일링 툴 제품군을 활용하면 개발자로서 갖추어야 할 전문 개발 기술을 다듬을 수 있습니다. 철저한 프로파일링으로 게임의 성능을 크게 향상할 수 있도록 새로 출간된 Unity 게임 프로파일링 종합 가이드 전자책에 담긴 여러 핵심 팁을 소개합니다.

생생한 게임 경험을 제공하려면 원활한 성능이 필수적이며, 적절한 성능을 확보하기 위해서는 게임을 프로파일링해야 합니다. 프로파일링을 할 때는 사용할 툴과 사용 방법 외에 사용 시점까지 파악해야 합니다.

최근에 유니티에서는 내부 및 외부 전문가들이 힘을 합쳐 고급 프로파일링을 주제로 하는 70페이지 이상 분량의 가이드를 제작했습니다. 여러 베스트 프랙티스 중에도 특히 Unity에서 애플리케이션을 프로파일링하는 방법과 성능 병목 현상을 파악하는 방법에 관한 조언과 지식을 집대성한 전자책입니다. 

해당 전자책에 담긴 몇 가지 유용한 팁을 살펴보겠습니다.

프로파일링이 필요한 시점

애플리케이션의 성능이 저하된 이유나, 코드에서 과도한 메모리를 할당하는 이유를 밝힌다는 점에서 프로파일링은 탐정이 하는 일과 비슷합니다.

프로파일링 툴은 궁극적으로 Unity 프로젝트에서 내부적으로 발생하는 일을 파악하도록 돕습니다. 하지만 심각한 성능 문제가 나타난 이후에야 프로파일링을 시작하면 곤란합니다.

프로파일링은 게임을 출시하기 직전이 아니라 프로젝트 개발 초기에 계획해야만 가장 큰 혜택을 볼 수 있으며, 이는 지속적이고 선제적이며 반복적인 과정입니다. 조기에 자주 프로파일링하면 팀 전체가 프로젝트의 '성능 시그니처'를 파악하고 정립할 수 있습니다. 예를 들어, 성능이 급락한 경우 상황이 안 좋아진 시점을 쉽게 찾아 문제를 빠르게 해결할 수 있습니다.

또한 다음과 같은 간단한 3단계 절차를 통해 작은 단위로 쪼개 전후 성능을 비교할 수도 있습니다. 먼저, 대규모 변경 이전에 프로파일링을 통해 기준을 정합니다. 그 후에는 개발 도중 프로파일링으로 성능과 예산 사용을 추적하고, 마지막으로 변경이 구현된 후에 프로파일링하여 원하는 효과를 얻을 수 있었는지 확인합니다.

Unity 에디터 내에서 프로파일링하는 것이 아니라, 게임 개발 빌드의 프로파일링을 목표로 해야 합니다. 이는 다음 두 가지 이유 때문입니다.

  1. 스탠드얼론 개발 빌드의 성능 및 메모리 사용 데이터가 에디터 내에서 게임을 프로파일링한 결과보다 훨씬 정확합니다. 프로파일러 창이 에디터 자체에서 데이터를 기록하기 때문이며, 이는 왜곡된 결과를 가져올 수 있습니다.
  2. 어떤 성능 문제는 게임이 타겟 하드웨어 또는 운영 체제에서 실행 중일 때에만 발생하기도 하며, 에디터 내에서만 프로파일링할 경우에는 이러한 문제를 놓치게 됩니다.

여러 프로파일링 툴

빌드를 타겟 기기에서 실행해 프로파일링하고 각 타겟 플랫폼의 하드웨어에 알맞은 툴을 사용할 때 가장 정확한 프로파일링 결과를 얻을 수 있습니다.

Unity에는 에디터와 하드웨어 모두에서 코드를 분석하고 최적화할 수 있는 여러 강력한 무료 프로파일링 툴이 포함되어 있으며, Arm, Apple, Sony, Microsoft 등에서도 각 플랫폼에 적합하게 제작된 뛰어난 기본 프로파일링 툴을 제공합니다. 이러한 툴을 조합해 사용하면 모든 타겟 기기에서 보다 종합적으로 애플리케이션 성능을 파악할 수 있습니다.

프로파일링 툴 페이지에서 제공되는 모든 툴을 확인하세요.

유니티의 프로파일링 툴은 에디터와 패키지 관리자에서 사용할 수 있습니다. 각 툴은 프로세스의 다양한 부분을 프로파일링하는 데 특화되어 있습니다(부분별로 프로파일링하여 통합하는 워크플로). 다음에서 소개하는 프로파일링 툴의 사용법을 익혀 두면 매우 유용하게 사용할 수 있을 것입니다.

  • Unity Profiler는 가장 처음에 사용하기 좋으며 가장 많이 사용하게 될 툴입니다. Unity 에디터와 플레이 모드에서 애플리케이션의 성능을 측정하며, 개발 모드에 있는 애플리케이션을 실행하는 기기와 연결됩니다. Unity Profiler는 애플리케이션 성능에 관한 데이터를 수집하고 표시합니다. 이러한 데이터의 예로 오디오와 물리, 렌더링과 애니메이션에 이르는 다양한 작업에 사용되는 CPU 점유 시간을 들 수 있습니다. 다음 프로파일링 기초 강좌를 확인해 보세요.
  • Memory Profiler를 사용하면 메모리 성능에 대한 심층적인 분석 정보를 확보하여 프로젝트와 에디터의 어떤 부분에서 메모리 사용량을 줄일 수 있는지 파악할 수 있습니다. Memory Profiler는 현재 프리뷰 상태이며, Unity 2022 LTS에서 검증된 버전이 될 것이라 예상됩니다.
  • Profile Analyzer는 Unity 프로파일러 프레임에서 프레임과 마커 데이터를 모두 집계하고 시각화하며, 이를 통해 수많은 프레임에 걸친 동작을 살펴볼 수 있습니다(Unity Profiler에서 이미 제공되는 단일 프레임 분석을 보완). 또한 두 개의 프로파일링 데이터세트를 비교해 변경 사항이 애플리케이션 성능에 어떤 영향을 미쳤는지 파악하는 데 도움을 주기도 합니다.
  • Frame Debugger를 사용하면 실행 중인 게임을 특정 프레임에서 멈춘 다음 해당 프레임의 렌더링에 사용된 개별 드로우 콜을 확인할 수 있습니다. 디버거에서 제공하는 드로우 콜 목록 기능을 활용하면 드로우 콜을 한 번에 하나씩 살펴볼 수 있으므로 그래픽 요소가 씬을 어떻게 구성하고 있는지 확인할 수도 있습니다.
  • Profiling Core 패키지는 Unity Profiler 캡처에 맥락 정보를 추가하는 API를 제공합니다.

툴 사용 방법

아래 플로차트는 유니티의 시니어 엔지니어이자 고급 프로파일링 전자책의 공저자인 Steve McGreal이 정리한 대략적인 개요로, 참고 자료로 자유롭게 사용하시기 바랍니다.

툴을 사용하는 방법에 관한 자세한 설명은 전자책에서 확인할 수 있으며, 이 플로차트는 워크플로에서 고려해야 하는 주요한 세 가지 사항을 설명합니다.

Flowchart for how to use the Profiler for pinpointing where to focus optimization efforts

여기에서 위 차트를 인쇄 가능한 PDF 버전으로 다운로드할 수 있습니다. 각 프로파일링 툴을 사용하는 방법은 포스팅 마지막의 리소스 링크를 참고하세요.

프레임 예산 준수 여부 확인

게이머는 보통 프레임 속도 또는 초당 프레임 수를 기준으로 성능을 측정합니다. 하지만 이보다는 밀리초(ms) 단위의 프레임 시간을 사용하는 것이 바람직합니다.

예를 들어, 런타임에서 59개의 프레임을 렌더링하는 데 0.75초가 걸리고, 다음 프레임의 렌더링에 0.25초가 걸리는 게임이 있다고 해 보겠습니다. 평균적으로는 60fps의 프레임 속도이므로 괜찮아 보이지만, 마지막 프레임을 렌더링할 때 1/4초가 걸리므로 플레이어는 끊김 현상을 경험하게 됩니다.

게임을 프로파일링하고 최적화할 때 프레임당 주어진 시간 예산을 최대한 준수해야 합니다. 이는 부드럽고 끊김이 없는 플레이어 경험을 구현하는 데 있어 매우 중요한 요소입니다. 각 프레임은 타겟 fps에 따른 시간 예산을 가집니다. 30fps가 목표인 애플리케이션은 프레임 속도를 항상 프레임당 33.33ms(1000ms/30fps) 미만으로 유지해야 합니다. 마찬가지로 목표가 60fps라면 프레임당 시간 예산은 16.66ms입니다.

최신 콘솔 및 PC 게임에서는 60fps 이상의 프레임 속도를 목표로 합니다. VR 게임의 경우에는 플레이어에게 멀미나 불편한 느낌을 유발할 수 있으므로, 높은 프레임 속도를 일관되게 유지하는 것이 실제로 더 중요합니다. 모바일 게임에서도 실행하는 기기가 과열되지 않도록 제한적인 프레임 예산을 적용해야 할 수 있습니다. 예를 들어, CPU와 GPU가 프레임 사이에 쿨다운할 수 있도록 21~22ms 정도의 프레임 예산(30 fps)만을 목표로 하는 모바일 게임이 있을 수 있습니다.

Unity Profiler를 사용해 프레임 예산을 준수하는지 여부를 확인하세요. 아래 이미지는 지속적으로 프로파일링과 최적화가 실행되고 있는 Unity 모바일 게임의 프로파일링 캡처 이미지입니다. 이 게임은 캡처에서 볼 수 있듯이 고사양 휴대전화에서는 60fps, 중/저사양 휴대전화에서는 30fps의 프레임 속도를 목표로 합니다.

Profiler framerate snapshot

이 게임은 30fps에 필요한 최대 22ms의 프레임 예산 내에서 과열 없이 안정적으로 실행됩니다. WaitForTargetfps가 렌더 스레드와 워커 스레드의 VSync 및 회색 대기 시간까지 메인 스레드의 마지막 부분에 존재한다는 점을 알 수 있습니다. 또한 Gfx의 종료 시간에는 VBlank 인터벌도 볼 수 있습니다. 한 프레임에서 다음 프레임으로 넘어가며 측정할 수 있도록 프레임마다 타임라인 영역 또는 타임 룰러 위에 타임스케일을 표시한 것을 볼 수 있습니다.

배터리 사용량과 서멀 스로틀링을 고려한 예산 조정까지 포함해 프레임 예산 내에 있다면 일단 성능 프로파일을 성공적으로 마무리한 것입니다. 이제 메모리 사용량도 예산 내에 있는지 살펴보겠습니다.

게임이 프레임 예산을 벗어났다면 이제 병목 현상이 일어나는 구간을 찾아야 합니다. 다시 말해, CPU 또는 GPU가 가장 오래 점유되는 위치를 포착해야 합니다. CPU라면 어떤 스레드의 사용량이 가장 많은지 찾아내면 됩니다. 바로 그 위치에서 병목이 발생합니다.

프로파일링의 요점은 최적화를 위해 병목을 식별하는 것입니다. 추측에만 의존한다면 게임에서 병목 현상이 발생하지 않는 부분을 최적화하게 되어 결과적으로 아무 것도 개선할 수 없게 됩니다. 어떤 '최적화'는 심지어 게임의 전체적인 성능에 악영향을 끼칠 수도 있습니다.

CPU 메인 스레드 의존 여부 확인

메인 스레드에서는 기본적으로 모든 게임 로직과 스크립트가 작동합니다. 물리, 애니메이션, UI, 렌더링 같은 기능과 시스템이 바로 이곳에서 실행됩니다.

아래 스크린샷은 메인 스레드에 의존하는 프로젝트의 전형을 보여줍니다.

Capture from a project that is main thread-bound
메인 스레드에 의존하는 프로젝트의 캡처

렌더 스레드와 워커 스레드는 이전 예시에서와 같이 프레임 예산 내에 있지만, 여기에서는 메인 스레드가 분명히 전체 프레임에서 계속 사용되고 있음을 알 수 있습니다. 프레임 끝 부분에 있는 약간의 Profiler 오버헤드를 고려하더라도, 메인 스레드가 45ms 이상 사용되고 있으며, 이는 이 프로젝트의 프레임 속도가 22fps 미만이라는 사실을 나타냅니다. 메인 스레드가 대기 상태로 VSync를 기다리고 있음을 제시하는 마커가 없으므로 전체 프레임 동안 사용되는 것을 알 수 있습니다.

이제 조사해야 할 사항은 가장 긴 시간을 사용하는 프레임을 찾고 그 이유를 파악하는 것입니다. 가장 큰 비용을 찾고 해결하려면 Unity Profiler와 Profile Analyzer를 모두 사용해야 합니다. 병목 현상은 일반적으로 물리, 최적화되지 않은 스크립트, 가비지 컬렉터(GC), 애니메이션, 카메라, UI 등에서 발생합니다. 문제의 원인을 바로 명확하게 파악할 수 없다면 Deep Profiling, Call Stacks를 활성화하거나 네이티브 CPU 프로파일러를 사용해 보세요.

95페이지에 달하는 유니티의 성능 최적화 가이드에서는 흔히 발생하는 문제를 파악하고 대비할 수 있는 방안을 제시합니다.

CPU 렌더 스레드 의존 여부 확인

렌더링 프로세스 중 메인 스레드는 씬을 검사하고 카메라 컬링, 뎁스 정렬, 드로우 콜 배칭을 수행하여 렌더링할 대상 목록을 정리합니다. 정리된 목록은 렌더 스레드로 전달되어, Unity 내부의 플랫폼 중립적 표현에서 특정 플랫폼의 GPU를 지시하는 데 필요한 그래픽 API 호출로 변환됩니다.

아래의 Profiler 캡처에서 Gfx.WaitForPresentOnGfxThread 마커를 보면 메인 스레드가 현재 프레임에서 렌더링을 시작하기 전에 렌더 스레드를 기다리고 있는 모습을 확인할 수 있습니다.

A render thread-bound scenario on Profiler
렌더 스레드 의존적 시나리오

여기에서 렌더 스레드는 이전 프레임의 드로우 콜 명령을 계속 제출하며, 메인 스레드로부터 새로운 드로우 콜을 허용할 준비는 되어 있지 않습니다. 렌더 스레드는 Camera.Render에서 시간을 소모합니다.

Rendering Profiler 모듈은 모든 프레임에 대한 드로우 콜 배치와 SetPass 호출 수를 공유합니다. 렌더 스레드가 GPU에 발행한 드로우 콜 배치를 조사하기에 가장 적합한 툴은 Frame Debugger입니다. 일반적으로 렌더 스레드 병목 현상이 발생하는 원인에는 바람직하지 않은 드로우 콜 배칭, 한 씬에 여러 활성 카메라 사용, 비효율적인 카메라 컬링 등이 있습니다.

CPU 워커 스레드 의존 여부 확인

메인 또는 렌더 스레드 이외의 CPU 스레드에 의존하는 것은 그리 흔한 문제는 아니지만, 데이터 지향 기술 스택(DOTS)을 사용하는 프로젝트, 특히 C# Job System을 사용해 메인 스레드에서 워커 스레드로 작업이 이전되는 경우에 발생할 수 있습니다.

다음은 에디터 내 플레이 모드의 캡처로, CPU에서 파티클 유체 시뮬레이션을 실행하는 DOTS 프로젝트를 나타냅니다.

A DOTS-based project, heavy on simulation, bound by worker threads
워커 스레드에 바인딩되어 무거운 시뮬레이션을 실행하는 DOTS 기반 프로젝트

위 캡처에서 볼 수 있듯이 워커 스레드가 잡으로 빼곡하게 채워져 있습니다. 이는 많은 양의 작업이 메인 스레드에서 이전되었음을 나타냅니다. 메인 스레드에 있는 48.14ms의 프레임 시간과 35.57ms의 회색 WaitForJobGroupID 마커는 이 CPU의 단일 프레임 내에서 실제로 가능한 수준보다 많은 작업을 워커 스레드에서 수행하고 있음을 나타냅니다.

WaitForJobGroupID는 메인 스레드가 워커 스레드에서 비동기식으로 실행하기로 예정한 잡이 있음을 보여줍니다. 하지만 워커 스레드에서 실행을 끝내기 전에 메인 스레드에서는 잡의 결과가 필요합니다. WaitForJobGroupID 아래의 파란색 프로파일러 마커는 대기하는 동안 시간을 아끼기 위해 잡을 실행하는 메인 스레드를 보여 줍니다.

프로젝트에 따라 이 예시처럼 잡이 병렬로 실행되지 않을 수도 있습니다. 하나의 워커 스레드에서 긴 잡이 하나만 실행될 수도 있습니다. 이 경우 예정된 잡과 해당 잡을 완료하는 데 필요한 시간이 충분히 분리되어 있다면 괜찮습니다. 그렇지 않을 경우에는 위 스크린샷처럼 메인 스레드가 멈춰서 잡이 완료될 때까지 대기하게 됩니다.

CPU Usage Profiler 모듈의 타임라인 뷰에서 Flow Events 기능을 사용하면 잡이 예약된 시점과 메인 스레드가 그 결과를 필요로 하는 시점을 확인할 수 있습니다. 효율적인 DOTS 코드 작성에 관한 자세한 내용은 DOTS 베스트 프랙티스를 참조하세요.

GPU 의존 여부 확인

Gfx.WaitForPresentOnGfxThread 같은 프로파일러 마커에서 보듯 메인 스레드가 렌더 스레드를 기다리느라 시간을 소비한다는 사실을 알 수 있었습니다. 하지만 렌더 스레드 역시 Gfx.PresentFrame 또는 .WaitForLastPresent 같은 마커를 표시할 수 있습니다. 이는 애플리케이션이 GPU 의존적이라는 의미입니다. 따라서 전반적인 성능을 개선하려면 GPU 병목 현상에 대한 최적화에 집중해야 합니다.

다음은 Vulkan 그래픽 API를 사용하는 Samsung Galaxy S7의 캡처입니다. 이 예시에서 Gfx.PresentFrame에 소요된 시간 중 일부는 VSync 대기와 관련이 있겠지만, 프로파일러 마커의 길이가 과도하게 길다는 것은 GPU가 이전 프레임의 렌더링을 끝내기를 기다리는 데 대부분의 시간이 사용되었음을 나타냅니다.

A capture from a GPU-bound mobile game
GPU 의존적 모바일 게임의 캡처

애플리케이션이 GPU 의존적인 것으로 보이면 Frame Debugger를 사용해 GPU로 전송되는 드로우 콜 배치를 빠르게 파악할 수 있습니다. 하지만 이 툴로는 구체적인 GPU 타이밍 정보를 알 수 없고, 씬이 구성된 방식만 확인할 수 있습니다.

GPU 병목 현상의 원인을 세심하게 알아보려면 적절한 GPU 프로파일러를 사용하여 GPU 캡처를 살펴보시기 바랍니다. 타겟 하드웨어와 선택한 그래픽 API에 따라 다른 툴이 사용됩니다.

일반적인 GPU 성능 저하 원인에는 비효율적인 셰이더, 많은 비용이 소요되는 후처리 효과, 투명한 오버드로우(주로 파티클 효과 또는 UI), 크거나 압축되지 않은 텍스처, 폴리곤 수가 과도하게 높은 메시, 지나치게 높은 출력 해상도(예: 4K 렌더링) 등이 있습니다.

무료 전자책 다운로드

A promotion of a profiling e-book

성능 최적화와 프로파일링은 매우 광범위한 주제입니다. 자세한 정보가 필요하다면 유니티에서 최근에 발표한 Unity 게임 프로파일링 종합 가이드 전자책을 확인해 보세요. 유니티의 통합 지원 서비스 팀을 비롯한 여러 전문가들이 공동으로 작성한 80여 페이지 분량의 유용한 팁을 얻을 수 있습니다.

이번 가이드는 모바일PC/콘솔 성능 최적화에 관한 100페이지 분량의 가이드 제작에 도움을 주었던 전문가들이 참여했으며, 초기에 병목 현상이 발생하지 않도록 하기 위한 실용적인 팁으로 가득합니다. 더 많은 리소스가 필요하다면 물리, UI, 오디오 설정, 모바일 또는 콘솔의 그래픽 및 에셋, 메모리 및 코드 아키텍처에 관한 이전 블로그 시리즈를 살펴보세요.

엔지니어와 전문가의 도움을 받고 프로젝트 가이드를 제공받고 싶다면 여기에서 Unity Success 플랜을 확인하세요.

프로파일링 웨비나 일정

3D model with robot figure on the right

새로운 종합 프로파일링 팁 웨비나에서는 SYBO Games, Arm, 그리고 유니티의 전문가가 Unity와 네이티브 프로파일링 도구를 사용해 모바일 게임의 일반적인 성능 관련 문제를 파악하는 팁을 알려드립니다. 

이 웨비나에서는 다음과 같은 내용을 다룹니다.

  • 간결하고 효과적인 코드를 작성하고 메모리 사용량을 최적화해 다양한 성능의 기기에서 원활하게 실행될 수 있도록 하는 방법
  • 모바일 기기에서 배터리 사이클을 보존하기 위한 열 제어 관리
  • 게임 개발의 모든 단계에 적용되는 프로파일링 전략과 테스트를 통해 확실한 방법론을 정립하는 방법 
  • Android 프로파일링에 관한 전문가의 인사이트 

2022년 6월 14일 오전 11시(동부 표준시)/오전 8시(태평양 표준시)에 라운드테이블 세션 및 라이브 Q&A에 참여하세요.

원하는 내용을 찾지 못하셨나요?

Unity 애플리케이션 성능 최적화에 대해 도움을 드릴 수 있도록 자세히 알고 싶은 최적화 주제가 있다면 포럼에서 알려주세요. 또한 보다 향상된 전자책과 기타 학습 자료를 제공할 수 있도록 선호하는 학습 방법을 공유해주세요.

다루는 주제
포럼에서 토론에 참여하기