Simpleperf를 사용하여 기기의 성능을 평가하세요. Simpleperf는 Android의 애플리케이션 및 네이티브 프로세스를 위한 네이티브 프로파일링 도구입니다. CPU 프로파일러를 사용하면 앱 CPU 사용량과 스레드 활동을 실시간으로 확인할 수 있습니다.
사용자가 확인 가능한 두 가지 성능 지표가 있습니다.
- 눈에 띄는 예측 가능한 성능. 사용자 인터페이스(UI)가 프레임을 건너뛰거나 60FPS에서 일정하게 렌더링되나요? 아티팩트 또는 팝핑 없이 오디오가 재생되나요? 사용자가 화면을 터치한 순간부터 효과가 화면에 표시되는 시점까지의 지연 시간은 어느 정도인가요?
- 더 긴 작업에 요구되는 시간(예: 애플리케이션 열기).
첫 번째 지표는 두 번째 지표보다 훨씬 더 눈에 띕니다. 일반적으로 사용자는 버벅거림을 눈치채지만 두 기기를 나란히 보고 있지 않은 이상 500ms 및 600ms 애플리케이션 시작 시간의 차이를 인지할 수 없습니다. 터치 지연 시간은 즉시 눈에 띄며 기기에 대한 인식에 상당한 영향을 미칩니다.
결과적으로 빠른 기기의 시스템에서는 UI 파이프라인이 가장 중요합니다. UI 파이프라인의 작동을 유지하는 데 필요한 요소를 제외한다면 말입니다. 즉, UI 파이프라인은 유동적 UI에 필요 없는 다른 모든 작업을 선점해야 합니다. 유동적 UI를 유지하기 위해서는 UI 작업이 실행 가능한 경우 백그라운드 동기화, 알림 전달 및 유사 작업이 모두 지연되어야 합니다. 유동적 UI의 유지를 위해서라면 더 긴 작업(HDR+ 런타임, 애플리케이션 시작 등)의 성능을 포기하는 것도 나쁘지 않습니다.
용량 대 지터
기기 성능 고려 시 의미 있는 두 가지 측정항목은 용량 및 지터입니다.
용량
용량은 기기가 특정 시간 동안 보유하는 특정 리소스의 총 크기입니다. CPU 리소스, GPU 리소스, I/O 리소스, 네트워크 리소스, 메모리 대역폭 또는 모든 유사한 측정항목이 포함될 수 있습니다. 전체 시스템 성능을 살펴보는 경우에는 개별 구성요소를 추상화하고 성능을 결정하는 단일 측정항목을 가정하는 것이 유용할 수 있습니다. 특히 새 기기를 조정하는 경우에는 해당 기기에서 실행된 워크로드가 고정될 가능성이 높기 때문에 더욱 유용할 수 있습니다.
시스템 용량은 온라인 컴퓨팅 리소스에 따라 다릅니다. CPU/GPU 주파수 변경은 주된 용량 변경 수단이지만 온라인 CPU 코어 수를 변경하는 등의 다른 수단도 있습니다. 따라서 시스템 용량은 전력 소비와 일치합니다. 용량이 변화하면 전력 소비에도 항상 유사한 변화가 일어납니다.
특정 시간에 요구되는 용량은 주로 실행 중인 애플리케이션에 의해 결정됩니다. 결과적으로 플랫폼은 특정 워크로드에 필요한 용량을 조정하기 위해 할 수 있는 일이 거의 없으며, 이를 위한 수단은 런타임 개선으로 제한됩니다(Android 프레임워크, ART, Bionic, GPU 컴파일러/드라이버, 커널).
지터
워크로드에 필요한 용량은 쉽게 확인할 수 있지만 지터는 훨씬 모호한 개념입니다. 빠른 시스템에 대한 장애 요소로서의 지터에 대한 유용한 소개 글은 사라진 슈퍼컴퓨터 성능의 사례: ASCl Q의 프로세서 8,192개에서 최적의 성능 달성을 참고하세요. 이는 ASCI Q 슈퍼컴퓨터가 기대에 못 미치는 성능을 발휘한 이유를 조사한 내용이며, 대규모 시스템 최적화를 위한 유용한 소개서입니다.
이 페이지에서는 ASCI Q 문서에서 노이즈라 부르는 요소를 설명하기 위해 지터라는 용어를 사용합니다. 지터는 인지 가능한 작업이 실행되지 못하게 막는 임의의 시스템 동작입니다. 이는 꼭 실행해야 하는 작업인 경우가 많지만 작업이 특정 시간에 실행되도록 하는 엄격한 시기 제한사항은 없을 수 있습니다. 임의로 발생하므로 특정 워크로드에 대한 지터의 존재를 반증하기가 매우 어렵습니다. 또한 지터의 알려진 원인이 특정 성능 문제의 원인임을 증명하기도 쉽지 않습니다. 추적 또는 로깅과 같은 지터의 원인을 진단하는 데 가장 흔히 사용되는 도구는 자체적인 지터를 야기할 수 있습니다.
Android의 실제 구현에서 경험할 수 있는 지터의 원인은 다음과 같습니다.
- 스케줄러 지연
- 인터럽트 핸들러
- 선점 또는 인터럽트가 사용 중지된 상태에서 너무 길게 실행되는 드라이버 코드
- 장기 실행 중인 softirqs
- 잠금 경합(애플리케이션, 프레임워크, 커널 드라이버, 바인더 잠금, mmap 잠금)
- 우선순위가 낮은 스레드가 파일의 잠금을 유지하여 우선순위가 높은 스레드가 실행되지 않도록 하는 파일 설명자 경합
- 코드 지연이 발생할 수 있는 작업 대기열에서 UI에 중요한 코드를 실행
- CPU 유휴 전환
- 로깅
- I/O 지연
- 불필요한 프로세스 생성(예: CONNECTIVITY_CHANGE 브로드캐스트)
- 여유 메모리 부족으로 인한 페이지 캐시 스래싱
용량 증가에 따라 특정 지터 기간에 요구되는 시간이 감소하거나 감소하지 않을 수도 있습니다. 예를 들어 드라이버가 i2c 버스 전체의 판독을 기다리는 동안 인터럽트를 사용 중지 상태로 유지하면 CPU가 384MHz이든 2GHz이든 고정된 시간이 소요됩니다. 지터와 관련이 있는 경우에는 용량을 늘리는 것이 성능 개선을 위한 방법이 될 수 없습니다. 결과적으로 더 빠른 프로세서는 지터로 인해 제한된 상황에서는 성능을 개선하지 않는 경우가 일반적입니다.
마지막으로, 지터는 용량과 달리 거의 전적으로 시스템 공급업체의 영역 내에 속합니다.
메모리 소모
통상적으로 메모리 소모는 저조한 성능의 원인입니다. 소모 자체는 성능 문제가 아니지만 lowmemorykiller 오버헤드, 서비스 재시작 및 페이지 캐시 스래싱을 통해 지터를 야기할 수 있습니다. 메모리 소모를 줄이면 저조한 성능의 직접적인 원인을 피할 수 있지만 이러한 원인을 예방하는 다른 타겟팅된 개선사항이 있을 수도 있습니다. 예를 들어 프레임워크를 고정하면 얼마 후에 프레임워크가 페이지 인될 때 페이지 아웃이 되지 않도록 예방할 수 있습니다.
초기 기기 성능 분석
작동은 하지만 성능은 저조한 시스템에서 시작한 후 사용자의 눈에 보이는 저조한 성능에 관한 개별 사례를 참고하여 시스템 동작을 해결하려고 시도하는 것은 안정적인 전략이 아닙니다. 일반적으로 저조한 성능은 지터처럼 재현이 쉽지 않거나 애플리케이션 문제입니다. 따라서 이 전략은 변수가 많은 전체 시스템에서는 효과를 발휘할 수 없습니다. 결과적으로는 원인을 오인하여 시스템 전체의 성능 문제를 체계적으로 해결할 수 있는 기회를 놓치고 미미한 개선만 이루기 쉽습니다.
대신 새 기기를 불러올 때는 다음과 같은 일반적인 접근 방식을 사용하세요.
- 모든 드라이버가 실행 중이고 몇몇 기본적인 주파수 거버너 설정을 포함하는 UI로 시스템 부팅을 가져옵니다. 주파수 거버너 설정을 변경하는 경우에는 아래의 모든 단계를 반복합니다.
- 커널이
sched_blocked_reason
tracepoint는 물론 프레임이 화면으로 전달될 때 이를 보여주는 디스플레이 파이프라인의 다른 tracepoint까지 지원하는지 확인합니다. - 전체 UI 파이프라인의 긴 트레이스(IRQ를 통한 입력 수신부터 최종 스캔아웃까지)를 취하는 동시에 가볍고 일정한 워크로드를 실행합니다(예: TouchLatency의 UiBench 또는 볼 테스트).
- 가볍고 일정한 워크로드에서 감지된 프레임 드롭을 고정합니다.
- 한 번에 20초 이상 드롭된 프레임 없이 실행할 수 있을 때까지 3, 4단계를 반복합니다.
- 사용자가 볼 수 있는 버벅거림의 다른 원인으로 넘어갑니다.
기기 불러오기 초반에 실행 가능한 다른 간단한 작업은 다음과 같습니다.
- 커널에 sched_blocked_reason tracepoint 패치가 있는지 확인합니다. 이 tracepoint는 systrace의 sched trace 카테고리로 사용 설정되며, 스레드가 무중단 절전 모드로 전환될 때 절전 모드를 실행하는 기능을 제공합니다. 이 기능이 성능 분석에 매우 중요한 이유는 무중단 절전 모드가 지터의 가장 일반적인 지표이기 때문입니다.
- GPU 및 디스플레이 파이프라인과 관련된 트레이스가 충분한지 확인합니다. 최근의 Qualcomm SOC에는 tracepoint가 다음을 사용하여 사용 설정됩니다.
adb shell "echo 1 > /d/tracing/events/kgsl/enable"
adb shell "echo 1 > /d/tracing/events/mdss/enable"
이러한 이벤트는 systrace를 실행하면 사용 설정 상태를 유지합니다. 따라서 트레이스에서 mdss_fb0
섹션의 디스플레이 파이프라인(MDSS)에 관한 추가 정보를 확인할 수 있습니다. Qualcomm SOC에서는 표준 systrace 화면에 GPU에 관한 추가 정보가 표시되지 않지만 결과는 트레이스 자체에 존재합니다(자세한 내용은 systrace 이해하기를 참고하세요).
이러한 유형의 디스플레이 추적에서는 프레임이 화면에 전달되었음을 직접적으로 나타내는 단일 이벤트를 가져오는 것이 좋습니다. 거기서부터는 프레임 시간에 정상적으로 도달했는지 파악할 수 있습니다. 이벤트 Xn이 이벤트 Xn-1 이후에 16.7ms보다 적게 발생하는 경우(디스플레이가 60Hz라는 가정하에)에는 버벅거림이 발생하지 않았음을 알 수 있습니다. SOC가 이러한 신호를 제공하지 않으면 공급업체에 문의하여 신호를 가져오세요. 확정적인 프레임 완료 신호가 없으면 지터를 디버깅하기가 매우 어렵습니다.
합성 벤치마크 사용
합성 벤치마크는 기기의 기본 기능이 존재하는지를 확인하는 데 유용합니다. 하지만 벤치마크를 인지된 기기 성능의 프록시로 취급하는 것은 유용하지 않습니다.
SOC와의 경험에 따라 SOC 간의 합성 벤치마크 성능 차이는 인지 가능한 UI 성능의 유사한 차이와 상호 관련이 없습니다(드롭된 프레임 수, 99번째 백분위수 프레임 시간 등). 합성 벤치마크는 용량 전용 벤치마크입니다. 지터는 벤치마크의 일괄 연산에서 시간을 훔치는 방식으로만 이러한 벤치마크의 측정된 성능에 영향을 미칩니다. 결과적으로 합성 벤치마크 점수는 사용자가 인지한 성능의 측정항목으로는 대부분 관련성이 없습니다.
UI의 1,000프레임을 렌더링하고 총 렌더링 시간을 보고하는 벤치마크 X를 실행하는 2개의 SOC를 고려해 보세요(점수는 낮을수록 좋음).
- SOC 1은 10ms 안에 벤치마크 X의 각 프레임을 렌더링하고 10,000점을 기록합니다.
- SOC 2는 프레임의 99%를 1ms로 렌더링하지만 프레임의 1%는 100ms로 렌더링하고 훨씬 높은 점수인 19,900점을 기록합니다.
벤치마크가 실제 UI 성능을 나타내는 경우 SOC 2는 사용할 수 없게 됩니다. 새로고침 빈도가 60Hz라고 가정하면 SOC 2는 작업의 1.5초마다 프레임 버벅거림을 경험하게 됩니다. 한편 SOC 1(벤치마크 X에 따른 더 낮은 SOC)은 완벽한 유동성을 지니게 됩니다.
버그 신고 사용
버그 신고는 간혹 성능 분석에 유용할 수 있지만 너무 무겁기 때문에 산발적인 버벅거림 문제를 디버깅하는 데에는 거의 도움이 되지 않습니다. 버그 신고는 특정 시점에 시스템이 어떤 작업을 실행하고 있었는지에 관한 어느 정도의 단서는 제공할 수 있습니다(특히, 버벅거림이 애플리케이션 전환을 중심으로 발생하여 버그 신고에 로깅되는 경우). 또한 버그 신고는 시스템의 좀 더 광범위한 문제로 인해 유효 용량이 감소할 수 있는 경우도 나타낼 수 있습니다(예: 열 제한 또는 메모리 조각화).
TouchLatency 사용
비정상적인 동작의 여러 예는 Pixel 및 Pixel XL에 주로 사용되는 주기적인 워크로드인 TouchLatency에서 비롯됩니다. 이는 frameworks/base/tests/TouchLatency
에서 제공되며 터치 지연 시간 및 공 튕기기, 이렇게 두 가지 모드를 포함합니다(오른쪽 상단의 버튼을 클릭하여 모드 전환 가능).
공 튀기기 테스트는 표시되는 과정처럼 단순하며, 사용자 입력과 상관없이 공이 화면을 중심으로 계속해서 튕깁니다. 또한 이 테스트는 완벽하게 실행하기가 압도적으로 어렵지만 프레임 드롭 없는 실행에 근접할수록 기기의 상태는 더 좋습니다. 공 튀기기 테스트가 까다로운 이유는 비록 단순한 테스트이기는 하지만 매우 낮은 클럭에서 실행되는 완벽한 일관성을 지닌 워크로드이기 때문입니다. 여기서는 기기에 주파수 거버너가 있다고 가정하며, 대신 기기가 고정된 클럭에서 실행되는 경우 공 튀기기 테스트를 처음 실행할 때 CPU/GPU를 거의 최소 수준으로 다운클럭해야 합니다. 시스템이 중단되고 클럭이 유휴에 가깝게 드롭되면 프레임당 요구되는 CPU/GPU 시간이 증가합니다. 공을 보고 버벅거림이 있는지 확인할 수 있으며, systrace에서 누락된 프레임도 볼 수 있습니다.
워크로드가 매우 일관적인 만큼 UI 파이프라인 대신 각 프레임이 누락되는 동안 시스템에서 정확히 무엇이 실행되고 있는지를 추적하여 사용자에게 표시되는 워크로드에 비해 훨씬 쉽게 지터의 원인을 대부분 식별할 수 있습니다. 낮은 클럭은 지터로 인해 프레임이 드롭될 확률을 높여 지터의 효과를 증폭시킵니다. 결과적으로는 TouchLatency가 60FPS에 근접할수록 재현이 어렵고 산발적인 대규모 애플리케이션의 버벅거림을 야기하는 비정상적인 시스템 동작이 발생할 가능성이 감소합니다.
지터는 대부분의 경우 클럭 속도의 변화가 없습니다. 따라서 다음과 같은 이유로 지터를 진단하려면 매우 낮은 클럭에서 실행되는 테스트를 사용해야 합니다.
- 모든 지터의 클럭 속도에 변화가 없는 것은 아니며, 다수의 원인은 단순히 CPU 시간만 소비합니다.
- 거버너는 비 UI 작업을 실행하는 데 소비된 시간으로 인해 프레임 드롭 언저리까지 밀릴 때까지 다운클럭을 통해 기한에 근접한 평균 프레임 시간을 가져와야 합니다.