Baseline Profiles와 앱 성능 최적화
Baseline Profiles와 앱 성능 최적화
Baseline Profiles는 프로파일 가이드 최적화(Profile Guided Optimization, PGO)의 한 형태로, 사용자가 접하는 핵심 코드 경로에 대해 AOT(Ahead-of-Time) 컴파일을 가능하게 함으로써 첫 실행부터 안드로이드 앱의 성능을 높여 줍니다. Baseline Profiles가 없는 경우, 안드로이드 런타임(ART)은 코드를 먼저 인터프리터 모드로 실행한 뒤, JIT(Just-in-Time) 컴파일을 통해 점진적으로 최적화합니다. 이 과정에서 초기 사용자는 상대적으로 느린 성능을 경험하게 됩니다. Baseline Profiles는 이 최적화 과정을 설치 시점으로 앞당겨, 개선 효과를 결정론적(deterministic)이고 재현 가능하게 만들어 줍니다.
이 레슨을 마치고 나면 다음 내용을 이해하실 수 있습니다.
- Baseline Profiles가 설치 시점에 AOT 컴파일을 수행하는 원리
- Macrobenchmark 라이브러리를 활용한 프로파일 생성 방법
- Baseline Profiles와 Startup Profiles의 차이점 및 각각의 최적화 영역
- Baseline Profiles가 제공하는 측정 가능한 성능 개선 효과
- 릴리스 빌드 파이프라인에 Baseline Profiles를 적용하는 방법
Baseline Profiles의 동작 원리
Baseline Profiles가 적용되지 않은 상태에서 ART는 계층적 컴파일(tiered compilation) 방식을 사용합니다. 첫 실행 시 모든 코드가 인터프리터 모드로 동작하며, 이는 네이티브 컴파일된 코드보다 상당히 느립니다. 사용자가 앱과 상호작용하는 과정에서 ART는 자주 실행되는 메서드, 즉 "핫(hot)" 메서드를 식별하고 JIT 컴파일을 통해 네이티브 코드로 변환합니다. 이러한 점진적 최적화 방식은 앱이 여러 번 실행될수록 빨라지지만, 초기 세션에서는 체감할 수 있을 만큼 느린 성능을 보입니다.
Baseline Profiles는 이 워밍업 기간을 우회합니다. 개발 단계에서 앱 시작, 화면 내비게이션, 스크롤 등 사용자 흐름을 시뮬레이션하여 프로파일을 생성하는데, Macrobenchmark 라이브러리가 이러한 흐름에서 실행되는 메서드를 기록하고 .prof 파일로 컴파일하여 APK 또는 AAB에 번들링합니다.
Google Play에서 앱을 설치하면, ART는 해당 프로파일을 읽어 목록에 포함된 메서드에 대해 AOT 컴파일을 수행합니다. 따라서 인터프리터 모드에서 시작하여 JIT 컴파일이 동작할 때까지 기다리는 대신, 가장 많이 사용되는 경로에 대해 네이티브 컴파일된 코드로 앱이 실행됩니다. 컴파일이 런타임이 아닌 설치 시점에 이루어지므로 사용자에게는 어떠한 성능 비용도 발생하지 않습니다.
실무에서 첫 릴리스 직후 사용자 이탈률이 높다면, 초기 성능 문제가 원인일 가능성이 있습니다. Baseline Profiles는 이러한 "첫인상" 문제를 근본적으로 해결해 주는 도구입니다.
Baseline Profiles가 없는 경우의 컴파일 파이프라인
Baseline Profiles가 제공하는 가치를 제대로 이해하려면, 전체 컴파일 파이프라인의 동작 과정을 먼저 살펴볼 필요가 있습니다.
프로파일 없이 앱을 설치하면, ART는 DEX 바이트코드를 그대로 저장합니다. 첫 실행 시 ART가 바이트코드를 직접 인터프리팅하며, 사용자가 앱과 상호작용하는 동안 JIT 컴파일러가 핫 메서드를 식별하여 메모리 내에서 네이티브 코드로 변환합니다. 하지만 이 JIT 컴파일된 코드는 프로세스가 종료되면 사라집니다.
백그라운드에서 ART는 주기적으로 관찰된 핫 메서드 프로파일을 디스크에 기록합니다. 이후 재설치하거나 유휴 유지보수(idle maintenance) 시점에 ART가 이 프로파일을 사용하여 AOT 컴파일을 수행하고, 프로파일에 포함된 메서드를 영구적인 네이티브 코드로 변환합니다. 결과적으로 앱이 완전한 최적화 상태에 도달하려면, 여러 세션에 걸친 실제 사용이 필요합니다.
Baseline Profiles는 이 파이프라인을 단축합니다. 설치 시점에 프로파일을 제공하므로 ART가 즉시 AOT 컴파일을 수행하며, 첫 세션부터 네이티브 컴파일된 코드로 앱이 실행됩니다.
Baseline Profile 생성하기
최적화하려는 흐름을 실행하는 테스트를 작성하여 Baseline Profile을 정의합니다. 다음은 앱 시작과 스크롤 동작을 프로파일에 기록하는 예제입니다.
@OptIn(ExperimentalBaselineProfilesApi::class)
class BaselineProfileGenerator {
@get:Rule
val rule = BaselineProfileRule()
@Test
fun appStartupAndScroll() {
// Baseline Profile 수집 시작
rule.collect(packageName = PACKAGE_NAME) {
// 앱 시작 후 메인 Activity가 완전히 로드될 때까지 대기
startActivityAndWait()
device.findObject(By.text("HOME"))
.clickAndWait(Until.newWindow(), 1_000)
// RecyclerView 스크롤 시뮬레이션으로 스크롤 경로도 프로파일에 포함
device.findObject(By.res("myRecyclerView"))
.apply {
fling(Direction.DOWN)
fling(Direction.UP)
}
}
}
}