앱 성능을 개선해보고 싶다는 생각이 들어 찾아보던 도중 Baseline Profile이 있어 이를 적용해보고자 했다.
Baseline Profile의 의미와 적용 과정에서의 트러블 슈팅을 담았다.
Baseline Profile
Baseline Profile을 사용하면 포함된 코드 경로의 해석과 JIT(Just In Time) 컴파일 단계를 피하여 최초 실행 후 코드 실행 속도가 약 30% 향상된다.
사용자가 느끼는 이점으로는 앱 시작 시간 최적화, 상호작용으로 인한 버벅거림 줄임, 전반적인 런타임 시간 개선 등이 있다.
Baseline Profile을 적용하지 않더라도 플레이스토어에서 Cloud Profile을 사용하기는 한다.
다만, Cloud Profile은 업데이트 후 배포되기까지 수 시간에서 수일이 걸리기 때문에 가용성이 제한된다. 즉, 프로필이 완전히 배포될 때까지는 신규 앱 또는 업데이트된 앱 사용자는 최적화된 앱 성능을 경험하지 못하는 것이다.
Baseline Profile의 동작 방식은 위 그림을 보면 이해할 수 있다.
- 앱에 맞는 프로필 규칙이 생성되고 앱에 바이너리 형식으로 컴파일된다. (이를 플레이스토어에 업로드)
- 플레이스토어는 이 프로필을 처리한 다음 APK와 함께 사용자에게 직접 제공한다.
- 이 흐름은 클라우드 프로필 집계와 연동되어 시간이 지남에 따라 앱의 실제 사용 방식을 기반으로 성능을 미세 조정한다.
📍공식문서: https://developer.android.com/topic/performance/baselineprofiles/overview?hl=ko
기준 프로필 개요 | App quality | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. 기준 프로필 개요 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 기준 프로필을 사용하면 포함된 코
developer.android.com
적용하기
이제 Baseline Profile을 적용하는 방법을 알아보자.
먼저 Baseline Profile 전용 모듈을 만들어줘야 한다. 모듈을 만들 때 Baseline Profile Generator를 선택하면 자동적으로 필요한 파일들과 라이브러리를 넣어줄 것이다.
추가된 라이브러리는 아래와 같다.
plugins {
alias(libs.plugins.baselineprofile)
}
dependencies {
baselineProfile(projects.baselineprofile)
implementation(libs.androidx.profileinstaller)
}
자동으로 생성된 파일들로는 BaselineProfileGenerator, StartupBenchmarks가 있다.
BaselineProfileGenerator 클래스는 앱 시작과 여러 이동 및 스크롤 이벤트를 위한 기준 프로필을 만들어 주는 역할을 한다.
generate() 함수 안을 보면, packageName을 통해 테스트 대상이 되는 페키지 네임을 지정하고, includeInStartupProfile = true를 통해 앱의 시작점에 필요한 코드를 Baseline Profile에 넣어준다.
StartupBenchmarks 클래스는 MacrobenchmarkRule()을 사용해 환경을 설정하고, 앱의 시작 속도를 비교해준다.
- startupCompilationNone() : 컴파일 모드가 None.
- startupCompilationBaselineProfiles() : 컴파일 모드가 Partial baseline profiles.
즉, Baseline Profile이 없는 경우와 있는 경우에 대해 앱의 시작 시간이 어떻게 다른지 비교해 주고 있는 것이다.
그리고 모듈을 생성할 때 Use Gradle Managed Device를 설정하지 않으면 에뮬레이터 정보를 따로 추가해 줘야 한다. (난 체크하지 않아서 오류가 생겼던 것 같다.)
baselineprofile 모듈의 build.gradle 파일에 아래와 같이 정보를 넣어주면 된다.
android {
testOptions.managedDevices.devices {
create<ManagedVirtualDevice>("pixel5Api33") {
device = "Pixel 5"
apiLevel = 33
systemImageSource = "google"
}
}
}
baselineProfile {
managedDevices += "pixel5Api33"
useConnectedDevices = false
}
마지막으로 명령어를 통해 프로필을 만들어 주면 된다.
./gradlew :app:generateBaselineProfile
그 다음, 테스트를 실행해주면 성능을 확인해볼 수 있다.
트러블 슈팅
테스트만 run하면 바로 성능이 나올 줄 알았지만 java.lang.AssertionError 오류가 났다..
아래 공식문서에도 나와있는 오류 중 하나인데, EMULATOR는 에뮬레이터로 실행할 경우, 실제 디바이스와 성능 차이가 날 수 있기 때문에 경고를 준 것이다.
Macrobenchmark 계측 인수 | App quality | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. Macrobenchmark 계측 인수 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 다음 계측 인수로 라이브러리의
developer.android.com
그래서 나는 이 오류를 억제해 주는 코드를 넣어서 해결했다.
testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "EMULATOR"
이제는 진짜 성능을 볼 수 있을 줄 알았는데, java.lang.IllegalStateException 에러가 났다..
에러를 타고 들어가보니 앱의 Activity를 찾고 있지 못하는 것 같았다. 그래서 Manifest 쪽을 살펴봤는데 별다른 문제는 없는 것 같아서 고민을 하던 도중, 에뮬레이터와 baselineprofile의 버전이 호환되지 않아서 찾지 못하는 것은 아닐까 하는 의문이 들어 버전을 업데이트를 해줬다.
그랬더니 바로 해결이 되었다!! 테스트를 모두 통과된 것을 확인할 수 있다!!
성능 분석
먼저, 에뮬레이터로 측정했을 때이다.
위에서 언급했다시피, 첫 번째 startupCompilationBaselineProfiles는 BaselineProfile을 돌린 것이고, 두 번째 startupCompilationNone은 아무것도 하지 않은 상태를 의미한다.
나는 이걸 보고 의문이 들었다. 왜냐하면 Baseline Profile이 적용되지 않은 것이 성능이 더 좋게 떴기 때문이다.. 그래서 이상하다 싶었는데 WARNING을 자세히 봐보면 현재 에뮬레이터에서 돌아가고 있으므로, 실기기와 차이가 있을 수 있다고 설명하고 있다. (진짜 차이가 있더라)
그래서 실기기로 테스트 해 보았다.
그랬더니 평균적으로 22%정도 성능이 좋아진 것을 확인할 수 있을 것이다.
이런 유의미한 결과를 만들게 되어 기분이 좋았다!
마치며
처음으로 앱의 성능을 개선해 보면서 그 수치를 직접 눈으로 확인해보니 신기했다. 성능이 개선된다면 사용자에게도 편리하게 느껴질 것이고 앱의 리텐션도 높일 수 있겠다는 생각이 들었다.
앞으로 이렇게 성능을 개선할 수 있는 방법이 있다면 적용해보고 싶다. (클래스 파일 주석을 보면 다른 성능들도 개선할 수 있는 것으로 보인다.)
Baseline Profile을 적용한 전체 코드는 아래 PR 링크를 통해 확인할 수 있다.
📍PR : https://github.com/teamterning/Terning-Android/pull/342
[FEAT/#341] Baseline Profile 적용 by leeeyubin · Pull Request #342 · teamterning/Terning-Android
closed [FEAT] Baseline Profile 적용 #341 ⛳️ Work Description Baseline Profile 적용 리드미 수정 (패키지 구조, 모듈 의존성) 📸 Screenshot 성능 측정 결과는 아래와 같습니다! 전반적으로 개선된 것을 확인할 수
github.com
'Develop > Android' 카테고리의 다른 글
[Android] ProcessPhoenix 오픈소스 뜯어보기 (0) | 2025.02.02 |
---|---|
[Android] SnackBar 디자인시스템 구현기 (Material 뜯어보기) (0) | 2025.01.30 |
[Android] BottomSheet 디자인시스템 구현기 (Material 뜯어보기) (0) | 2025.01.29 |
[Android] Compose Compiler Metrics로 성능 측정하기 (1) | 2024.12.27 |
[Android] 단어 단위의 개행하기 (Compose) (0) | 2024.11.22 |