유니티 Profiler와 최적화
Stray라는 프로젝트를 진행하면서 게임 개발에서는 빠질 수 없는 최적화를 시도해볼 때가 되어 공부를 시작하게 되었다.
유니티에서는 Profiler라는 성능 분석 용 툴을 제공하는데 이를 공부하며 같이 최적화에 대해서도 어느 정도 익혀보려고 한다.
목차
최적화
- 프로파일링
- GPU 프로파일링
- 업스케일링 샘플링
- 텍스쳐 최적화
- Frame Debuger
- Memory Profiler
- Memory Debuger
- 최적화 관련 팁
최적화
- 목표 플랫폼 및 상세 기능의 선행 조사가 필수임
- 프로토타입 단계에서는 최적화를 신경쓰지 않고 개발하기
프로파일링
의미
- 프로그램에서 실행 속도 및 안정성 개선을 위해 CPU 및 메모리의 사용량과 함수의 실행 시간과 같은 요소를 추적하는 것
주의사항
개발 중 자주 하기
- 나중 단계에서 할 경우 작업 강도가 높아짐
추측에 의한 최적화를 시도하지 않기
디버거와 같은 툴을 적극적으로 사용하기
목표 플랫폼에서의 프로파일링은 필수임
- 에디터서의 프로파일링은 단순 참고용임(IOS/AOS등 OS마다 성능 차이를 보일수 있음)
자동화된 테스트 환경을 구축하기
목표 프레임을 명시해주기(운영체제마다 기본값이 다를수있음)
수직 동기화 여부를 확인하기(강제로 프레임을 낮추는 효과가 있음)
GPU 프로파일링
- 하단에 있는 문서의 최신 기준인 2022.1 에디터 기준으로 DirectX 11과 12에서만 사용이 가능함
- Windows > Analysis > Profiler 메뉴에서 프로파일링 창을 열 수 있다
의미
위의 사진을 자세히 보면 어디서 GPU에 DrawCall을 했는지와 횟수, 사용시간 등을 보여주고 있다.
관련 개념
FillRate = 화면의 픽셀수 x 프래그먼트쉐이더 복잡도 x 오버드로우
- 화면의 픽셀수: 화면 해상도
- 프래그먼트 쉐이더 복잡도: 쉐이더가 얼마나 무거운지 판단하는 척도
- 오버드로우: 픽셀이 얼마나 중첩되어 그려지는지 나타내는 척도
장점
- 플레이어를 빌드 할 필요가 없으므로, 빠른 프로파일링에 유리함
단점
- 오버헤드의 영향을 받아 결과의 정확도 감소에 영향을 미칠 수 있음
더 세부적인 정보를 원한다면 아래의 링크를 참조하기를 바람
업스케일링 샘플링
- 해상도를 줄이는 대신 UI 크기를 유지하여 최적화를 하는 기법
- 유니티의 URP에서는 Render Scale이라는 항목으로 구현되어있다.
텍스쳐 최적화
- 유니티 상에서 이미지를 사용할때 원본 포맷이 뭐든지 상관없이 GPU가 사용가능한 포맷으로 전환되므로 텍스쳐 세팅만 잘 하는경우 문제가 없음
포맷
PVRTC
크기: 4bpp, 2bpp(픽셀 당 사용할 사용할 bit 크기 선택)
주로 아이폰에서 사용됨
원리:
1) 원본 이미지를 4x4 블록 단위 크기로 변환하여 크기를 줄임
2) 2개의 대표 색상을 선택
3) 1:1 해상도로 Modulation Data에 옮겨 조합하여 처리함
단점:
- 4x4픽셀로 처리하므로 블러키 현상이 발생하여 이미지가 뭉개지므로, 레트로 스타일 게임에서는 추천하지 않음
ETC
크기:
ETC1: 4bpp
ETC2: 4, 8pp
원리:
- PVRTC와 유사하게 블록 단위로 처리되지만, 이미지를 색상과 밝기로 나누어 합성하여 처리함
- 색상은 낮은 해상도로, 밝기는 1:1 해상도로 뽑아 합성함
단점:
- 블럭 단위로 색이 더러워져 보일 수 있음
- ETC2에서는 ETC1보다 완화되어 보임
이외에도 다양한 확장자가 있으나, 공식 문서에서 자세하게 설명되어있는 관계로 링크로 대체한다
해상도
- 4x4 사이즈로 처리되므로 2^n의 사이즈로 처리되어야 함(POT)
- 크기 종류: 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048…
- 이외의 값을 입력 시, 유니티에서 자동으로 크기를 키워 처리하므로 버려지는 공간이 발생함
- ASTC에서는 5x5, 12x12와 같이 블록의 크기를 자유롭게 선택이 가능함
- 블럭 단위로 색이 더러워져 보일 수 있음
Frame Debuger
의미
Frame Debuger의 정의는 실행 중인 게임을 특정 프레임 시점에서 정지하여 해당 프레임에 렌더링되는 각 드로우 콜을 보여주는 툴
- 다음은 유니티에서 기본으로 제공하고있는 3D Sample Scene(HDRP) 템플릿에서의 Frame Debuger의 모습이다
Windows > Analysis > Frame Debuger 메뉴에서 디버거 창을 열 수 있다
더 세부적인 정보를 원한다면 아래의 링크를 참조하기를 바람
Memory Profiler Module
- Windows > Analysis > Profiler 메뉴에서 프로파일링 창을 열수 있다
더 세부적인 정보를 원한다면 아래의 링크를 참조하기를 바람
Memory Debuger
Windows > Analysis > Memory Profiler 메뉴에서 디버거 창을 열 수 있다
- 유니티 버전에 따라 설치 방법이 다르므로, 다음의 링크를 참고하길 바란다
최적화 관련 팁
메모리 관리
모바일 게임일수록 메모리 최적화의 중요성이 높아짐
ETC12를 이용한 압축을 이용할때 기기가 ES 3.0 이상을 지원하는지 확인하기
OpenGL ES2.0에서 ETC2를 사용시 압축이 해제되어 메모리 사용량이 다시 증가함(4mb -> 16mb)
ES2.0 기기가 목표일 경우, Build Settings에서 Compress using ETC1 옵션을 켜주기
(Sprite&UI에서만 지원하며, Packing Tag가 필수임)
- 오디오는 Load Type을 지정하여 메모리 절약이 가능하다
Decompress On Load: 반응 속도가 빠르지만, 로딩 이후 압축을 풀어 재생하므로 오리지널 크기 그대로 메모리에 올라간다는 보장이 X
압축 해제 시, 압축 유지보다 10배 이상의 메모리를 사용하므로 용량이 작은 파일에만 적합함
Compress In Memory: 메모리에 압축 상태로 유지했다가, 재생시 압축을 해제
압축 해제 시, 메모리를 많이 사용하는 고용량의 파일에만 사용해야 함
Streaming: 사운드를 즉시 디코딩 하는 방
디스크에서 증가 식으로 읽어 압축 데이터를 버퍼에 넣어 메모리 사용 최소화함
- 유니티 상에서는 같은 파일인지 확인하는 기능이 없으므로 중복 파일이 없도록 주의하기(폰트, 텍스쳐….)
- Memory Profiler에서 중복 파일이 있는지 확인이 가능함
- Mesh를 사용시 Read/Write Enable 옵션이 꺼져있는지 확인하기
- 스크립트를 통하여 Mesh에 접근 가능 여부를 선택하는 옵션으로 GPU, CPU 메모리에 중복으로 올라가므로 필요 없으면 끄기
에셋 관리 방법
- 에셋 타입 / 플랫폼 별로 설정하기
- 올바른 텍스쳐 포맷을 선택하기
- 메시 임포트 옵션을 선택하기
- 오디오 압축하여 사용하기
프로그래밍과 코드 아키텍쳐
- Awake, OnEnable, Update와 같은 이벤트 함수의 호출 순서를 알아놓기
- 적절한 TargetFrameRate
- 장르/상황 별로 설정하기
- Adaptive Performance 사용하기
- 비동기 로딩을 사용하기
- 에셋 로드와 같은 로딩은 비동기로 처리하여 성능을 높일 수 있음
- 사용하지않는 Monobehaviors 메소드 제거하기
- Start, Update, FixedUpdate….
- Update를 사용하는 것보단 매니저 패턴을 이용하기
- 비용이 높은 API 호출은 최소화하기
- GameObject.Find()
- transform.find, 인스펙터에서 지정, FindWithTag…. 으로 대체 가능
- GameObject.GetComponent
- TryGetComponent()가 더 호출 비용이 낮음
- GameObject.Find()
- 스트링 오퍼레이션 주의하기
- Debug.Log() 주의
- 디버그 클래스 사용 or Conditional로 조건을 지정하거나 사용 후 제거하여야 빌드 할때 제외됨
- allocationg API 주의
- s가 붙은 API들은 배열로 할당하여 지정하므로 호출 비용이 높음
- 정적 데이터 파싱 주의하기
- Json/XML: 스크립터블 오브젝트
안드로이드의 표준 텍스쳐 포맷 ↩



