" /> 유니티 Profiler와 최적화 | BlackWerf's Blog
포스트

유니티 Profiler와 최적화

참고한 영상

Stray라는 프로젝트를 진행하면서 게임 개발에서는 빠질 수 없는 최적화를 시도해볼 때가 되어 공부를 시작하게 되었다.

유니티에서는 Profiler라는 성능 분석 용 툴을 제공하는데 이를 공부하며 같이 최적화에 대해서도 어느 정도 익혀보려고 한다.


목차

  • 최적화

    • 프로파일링
    • GPU 프로파일링
    • 업스케일링 샘플링
    • 텍스쳐 최적화
    • Frame Debuger
    • Memory Profiler
    • Memory Debuger
    • 최적화 관련 팁


최적화

  • 목표 플랫폼 및 상세 기능의 선행 조사가 필수임
  • 프로토타입 단계에서는 최적화를 신경쓰지 않고 개발하기

프로파일링

의미

  • 프로그램에서 실행 속도 및 안정성 개선을 위해 CPU 및 메모리의 사용량과 함수의 실행 시간과 같은 요소를 추적하는 것


주의사항

  • 개발 중 자주 하기

    • 나중 단계에서 할 경우 작업 강도가 높아짐
  • 추측에 의한 최적화를 시도하지 않기

  • 디버거와 같은 툴을 적극적으로 사용하기

    • 예시) 유니티 에디터의 프로파일러

      absolute
              위의 사진은 현재 팀으로 작업 중인 프로젝트 내의 Profiler의 모습이다


  • 목표 플랫폼에서의 프로파일링은 필수임

    • 에디터서의 프로파일링은 단순 참고용임(IOS/AOS등 OS마다 성능 차이를 보일수 있음)
  • 자동화된 테스트 환경을 구축하기

  • 목표 프레임을 명시해주기(운영체제마다 기본값이 다를수있음)

  • 수직 동기화 여부를 확인하기(강제로 프레임을 낮추는 효과가 있음)


GPU 프로파일링

  • 하단에 있는 문서의 최신 기준인 2022.1 에디터 기준으로 DirectX 11과 12에서만 사용이 가능함
  • Windows > Analysis > Profiler 메뉴에서 프로파일링 창을 열 수 있다

의미

  • 게임의 어떤 부분이 GPU를 얼마나 오래 사용했는지 표시하는 프로파일러

  • 단위: ms

    absolute
            위의 사진은 유니티에서의 GPU Profiler의 모습이다

위의 사진을 자세히 보면 어디서 GPU에 DrawCall을 했는지와 횟수, 사용시간 등을 보여주고 있다.

관련 개념

  • FillRate = 화면의 픽셀수 x 프래그먼트쉐이더 복잡도 x 오버드로우

    • 화면의 픽셀수: 화면 해상도
    • 프래그먼트 쉐이더 복잡도: 쉐이더가 얼마나 무거운지 판단하는 척도
    • 오버드로우: 픽셀이 얼마나 중첩되어 그려지는지 나타내는 척도

    장점

    • 플레이어를 빌드 할 필요가 없으므로, 빠른 프로파일링에 유리함

    단점

    • 오버헤드의 영향을 받아 결과의 정확도 감소에 영향을 미칠 수 있음


    더 세부적인 정보를 원한다면 아래의 링크를 참조하기를 바람

    유니티 GPU 프로파일러 공식 문서


업스케일링 샘플링

  • 해상도를 줄이는 대신 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의 모습이다

Image Alt 텍스트

Windows > Analysis > Frame Debuger 메뉴에서 디버거 창을 열 수 있다


더 세부적인 정보를 원한다면 아래의 링크를 참조하기를 바람

유니티 Frame Debuger 공식 문서


Memory Profiler Module

  • Windows > Analysis > Profiler 메뉴에서 프로파일링 창을 열수 있다


더 세부적인 정보를 원한다면 아래의 링크를 참조하기를 바람

유니티 메모리 프로파일러 모듈 공식 문서

Memory Debuger

  • Windows > Analysis > Memory Profiler 메뉴에서 디버거 창을 열 수 있다

    • 유니티 버전에 따라 설치 방법이 다르므로, 다음의 링크를 참고하길 바란다

    Image Alt 텍스트

최적화 관련 팁

메모리 관리

  • 모바일 게임일수록 메모리 최적화의 중요성이 높아짐

    • 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()가 더 호출 비용이 낮음
  • 스트링 오퍼레이션 주의하기
  • Debug.Log() 주의
    • 디버그 클래스 사용 or Conditional로 조건을 지정하거나 사용 후 제거하여야 빌드 할때 제외됨
  • allocationg API 주의
    • s가 붙은 API들은 배열로 할당하여 지정하므로 호출 비용이 높음
  • 정적 데이터 파싱 주의하기
    • Json/XML: 스크립터블 오브젝트
  1. 안드로이드의 표준 텍스쳐 포맷 

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.