티스토리 뷰
빈번하게 갱신되는 화면의 경우 어떻게 성능 테스트를 할 수 있을까요? 눈으로 확인했을 때 화면이 버벅이면서 보이거나 끊김 현상이 보이면 당연히 성능이 안 좋다고 판단할 수 있겠지만, 눈으로 확인하는 데는 정확성이 부족할 수 있고 미묘한 차이를 캐치하기 어려울 수 있습니다. 아무래도 가장 좋은 건 데이터, 즉 수치로 확인하는 것이죠.
XCode12부터 UI와 관련된 성능 이슈를 파악하는데 도움을 주는 Instruments - Animation Hitches가 도입되었습니다.
아래 내용은 WWDC21 Hitch 관련 세션을 보고 정리한 글입니다.
일반적으로 디스플레이를 갖는 디바이스의 경우 주사율을 갖습니다. iOS 디바이스의 경우 보통 60Hz의 주사율을 갖고 이는 1초에 60번 화면이 갱신됨을 의미합니다. (물론 몇몇 pro 디바이스의 경우 promotion display라고 해서 최대 120Hz 즉 1초에 120번 화면 갱신이 될 수 있습니다.)
이러한 주사율을 토대로 하나의 프레임이 유지되는 시간은 60Hz 기준 약 16ms, 120Hz 기준 8ms가 됩니다. 정말 찰나의 순간이죠.
Render Loop
iOS 디바이스 화면의 경우 Render Loop에 맞춰 갱신되는데요. 하드웨어는 refresh rate에 맞춰 VSYNC라는 이벤트를 방출하고 새로운 프레임은 이 VSYNC 이벤트에 맞춰 준비되어 있어야 합니다. (만약 제때 준비되지 못하면 이전 화면이 보여 사용자에게는 같은 화면 혹은 버벅이거나 끊기는 화면으로 느껴질 수 있습니다.)
이 Render Loop은 위 이미지와 같이 3단계 프로세스, 5개의 페이즈로 구성됩니다.
즉, 개념적으로는 Event - Commit - Render prepare - Render execute - Display가 60Hz 기준 16ms안에 완료되어야 화면 딜레이나 버벅임 없이 사용자에게 보이게 되는 것이죠. 하지만 *double buffering을 사용함으로써 화면에 디스플레이되고 있는 와중에 다음에 보일 두 개의 프레임을 병렬로 처리하고 있기 때문에 실질적으로는 16ms 보다는 시간적 여유를 가져갈 수 있게 됩니다.
*경우에 따라 hitch를 방지하기 위해 tripple buffering을 사용하기도 합니다. (hitch는 아래에서 설명드립니다.)
📱각 단계별 설명
* App
* Event: 사용자의 터치, 네트워크 콜백, 키보드 등의 이벤트를 처리하고 변경이 필요한 UI를 결정
* Commit: 바뀌어야 하는 UI를 계산하고 랜더링을 위해 Renser Server로 제출
* Render Server
* Render prepare: 다음 VSYNC에서 제출본을 받고 새로운 UI를 GPU를 통해 랜더링 할 준비를 함
* Render execute: GPU를 사용해 UI를 최종 이미지로 그림
* On the display
* Display: 다음 VSYNC에서 사용자에게 최종 이미지인 frame을 디스플레이함
App - Event Phase
App - Commit Phase
Render Server - Rendering prepare phase
Render Server - Rendering execute phase
Hitch
Hitch는 프레임이 스크린에 제때 나타나지 않은 시간 (늦게 나타나는 시간)을 의미합니다.
원인에 따라 Commit hitch와 Render hitch 두 가지 타입으로 구분되는데요 자세히 살펴보면 아래와 같습니다.
1. Commit hitch
앱 프로세스 단계에서 발생하는 경우 (== Event, Commit phase에서 오랜 시간이 걸리는 경우)
App 단계에서 delay가 되면, Render Server는 처리할 process가 없게 되고 다음 VSYNC를 기다리게 됩니다. 이에 따라 frame을 delivery 할 시간 역시 delay 되고 이 delay 된 시간을 “hitch time”이라고 합니다.
1번 케이스 hitch time: 16.67ms
2번 케이스 hitch time: 33.34ms
2. Render hitch
랜더 서버 단계에서 발생하는 경우 (== 랜더링 하는데 오랜 시간이 걸리는 경우)
랜더 서버에서의 프로세스가 오랜 시간 소요되는 경우, 다음 VSYNC에 display 하게되고 이 역시 마찬가지로 hitch time이 발생하게 됩니다.
hitch time: 16.67ms
Hitch 발생 유무 확인과 해결 방법
Instruments Animation Hitches를 사용하면 Render Loop을 시각화하여 볼 수 있고 hitching frame을 파악하는데 도움을 받을 수 있는데요. 이를 토대로 수집한 정보를 가지고 hitch를 개선 / 제거할 수 있습니다.
참고) Instruments 실행 방법: Xcode에서 Cmd + I 로 프로파일 혹은 앱 실행 후 스포트라이트 검색으로 Instruments 별도 실행
Animation Hitches를 사용하여 Recording 하고 앱 구동 후 recording을 마치면 위와 같은 화면을 볼 수 있고 Render Loop 페이즈별 응답 트랙, Hitch duration, Acceptable latency, Hitch Type 등을 볼 수 있습니다.
- Hitches 트랙: hitch와 hitch duration 정보 표시
- User Events 트랙: Hitching frame과 함께 수신된 이벤트 표시
- commits 트랙: commit phase 표시
- Frame Lifetimes 트랙: 히칭 프레임의 lifetime 표시
- Built-In Display 트랙: VSYNC 이벤트와 디스플레이에 나타나는 모든 프레임 표시
Hitches 트랙 하단에 표시되는 Hitch들을 보면 아래와 같이 Acceptable latency 칼럼을 확인할 수 있는데요.
Acceptable latency란 '허용 가능한 대기 시간'으로 Frame Lifetime 시작 시간 ~ Hitch Duration 시작 시간을 의미합니다. (그 이후의 시간은 hitch duration, 아래 이미지 참고)
수집된 데이터를 토대로 결과를 분석해 보면, 먼저 Hitch가 얼마나 발생하고 있는지 시각적으로 파악이 가능하고, Hitch duration을 통해 그 심각성을 판단할 수 있습니다.
Hitch Type 칼럼을 통해서는 왜 Hitch가 발생하는지 원인에 대한 대략적인 힌트를 얻을 수 있는데요. 조금 더 자세히 들여다보기 위해 아래와 같이 해당 Hitch가 발생하는 구간에 대해서만 드래깅 하여 focusing 할 수 있습니다.
Animation Hitches에서는 Time Profiler도 포함하기 때문에 Hitch가 발생하는 해당 구간에서 main thread를 포함한 각각의 thread가 어떤 코드를 처리하고 있는지도 확인할 수 있습니다.
위와 같이 해당 구간에서의 main thread stack trace를 확인해 보면, main thread에서 weight이 큰 로직이 무엇인지 확인할 수 있고, 이에 따라 어떤 부분을 개선하면 좋을지 힌트를 얻을 수 있습니다. 여기서 한 가지 Tip을 드리자면, 아래와 같이 Call Tree 체크 박스를 설정하면 디버깅이 조금 더 수월해집니다.
이렇게 Commit 트랙과, Hitch duration, Hitch Type, Time Profiler를 확인해 보면 어느 단계에서 이슈가 발생하고 있는 건지, 어떤 코드가 문제가 되는 건지 파악 할 수 있고, 이 정보들을 토대로 원인을 제거, 개선하고 다시 테스트하는 식으로 반복하다 보면 끊기거나 delay 되지 않는 화면, 버벅임 없는 화면을 사용자에게 제공할 수 있게 됩니다.
긴 글 읽어주셔서 감사합니다.
참고)
https://developer.apple.com/videos/play/tech-talks/10855/
https://developer.apple.com/videos/play/tech-talks/10856/
'Swift&iOS > iOS' 카테고리의 다른 글
[iOS] Unit Test (0) | 2023.03.30 |
---|---|
[iOS] SwiftUI 뷰와 레이아웃 시스템에 대한 이해 (feat. WWDC) (1) | 2022.12.13 |
[iOS] SwiftUI 학습 순서 (feat. Tutorial & WWDC) (3) | 2022.11.27 |
[iOS] Memory Leak 해결하기 (feat. Instruments leak, Debug Memory Graph) (0) | 2022.10.29 |
[iOS] 웹뷰 Safari 개발자 도구 사용해 디버깅 하기 (0) | 2022.08.07 |