Jetpack Benchmark 라이브러리를 사용하여 Android 스튜디오 내에서 Kotlin 기반 또는 자바 기반 코드를 빠르게 벤치마킹할 수 있습니다. 이 라이브러리는 준비 작업을 처리하고 코드 성능과 할당 수를 측정하며 Android 스튜디오 콘솔과 JSON 파일 모두에 자세한 정보가 포함된 벤치마킹 결과를 출력합니다.
사용 사례로는 RecyclerView
스크롤, 데이터베이스 쿼리 실행, 코드에서 더 빠르게 처리하고자 하는 느린 부분 측정 등이 있습니다.
지속적 통합에서 벤치마크 실행의 설명대로 지속적 통합(CI) 환경에서 라이브러리를 사용할 수 있습니다.
벤치마킹하려는 프로젝트에서 AndroidX를 아직 채택하지 않은 경우 Android 스튜디오를 사용해 기존 프로젝트 이전을 참고하세요.
빠른 시작
이 섹션에서는 코드를 모듈로 이동할 필요 없이 벤치마킹을 시도하는 빠른 단계를 제공합니다. 이 단계에는 정확한 성능 결과를 위해 디버깅을 중지하는 작업이 포함되므로 변경사항을 소스 제어 시스템에 커밋하지 않지만, 일회성으로 측정을 하려는 경우에는 유용할 수 있습니다.
일회성 벤치마킹을 빠르게 실행하려면 다음 단계를 따르세요.
라이브러리를 모듈의
build.gradle
파일에 추가합니다.project_root/module_dir/build.gradle
Groovy
dependencies { androidTestImplementation 'androidx.benchmark:benchmark-junit4:1.1.0-alpha13' }
Kotlin
dependencies { androidTestImplementation("androidx.benchmark:benchmark-junit4:1.1.0-alpha13") }
테스트 매니페스트에서 디버깅을 중지하려면 다음과 같이
<application>
요소를 업데이트하여 디버깅을 일시적으로 강제 중지합니다.project_root/module_dir/src/androidTest/AndroidManifest.xml
<!-- Important: disable debuggable for accurate performance results --> <application android:debuggable="false" tools:ignore="HardcodedDebugMode" tools:replace="android:debuggable"/>
벤치마크를 추가하려면
androidTest
디렉터리의 테스트 파일에BenchmarkRule
인스턴스를 추가합니다. 벤치마크 작성에 관한 자세한 내용은 벤치마크 작성을 참고하세요.다음 코드 스니펫은 JUnit 테스트에 벤치마크를 추가하는 방법을 보여줍니다.
Kotlin
@RunWith(AndroidJUnit4::class) class MyBenchmark { @get:Rule val benchmarkRule = BenchmarkRule() @Test fun benchmarkSomeWork() = benchmarkRule.measureRepeated { doSomeWork() } }
자바
@RunWith(AndroidJUnit4.class) class MyBenchmark { @Rule public BenchmarkRule benchmarkRule = new BenchmarkRule(); @Test public void benchmarkSomeWork() { final BenchmarkState state = benchmarkRule.getState(); while (state.keepRunning()) { doSomeWork(); } } }
벤치마킹하는 경우
벤치마크를 작성하기 전에 코드를 프로파일링하는 것이 좋습니다. 그러면 최적화할 가치가 있는 높은 비용의 작업을 찾는 데 도움이 됩니다. 작업 실행 중에 발생하는 상황을 표시하여 작업이 느린 이유를 노출할 수도 있습니다. 우선순위가 낮은 스레드에서 실행, 디스크 액세스 권한으로 인한 절전 모드, 비용이 많이 드는 함수의 예기치 않은 호출(예: 비트맵 디코딩)을 예로 들 수 있습니다.
TraceCompat API(또는 -ktx
래퍼)를 통해 맞춤 트레이스 포인트를 추가하면 Android 스튜디오 CPU 프로파일러 또는 Systrace에서 확인할 수 있습니다.
Kotlin
fun proccessBitmap(bitmap: Bitmap): Bitmap { trace("processBitmap") { // perform work on bitmap... } }
자바
public Bitmap processBitmap(Bitmap bitmaptest) { TraceCompat.beginSection("processBitmap"); try { // perform work on bitmap... } finally { TraceCompat.endSection(); } }
벤치마킹 대상
벤치마크는 앱에서 여러 번 실행되는 CPU 작업에 가장 유용합니다. 좋은 예로는 RecyclerView
스크롤, 데이터 변환/처리 및 반복적으로 사용되는 코드 조각이 있습니다.
다른 유형의 코드는 벤치마킹으로 측정하기 더 어렵습니다. 벤치마크는 루프에서 실행되기 때문에 자주 실행되지 않거나 여러 번 호출될 때 다르게 실행되는 코드는 벤치마킹에 적합하지 않을 수 있습니다.
캐싱
캐시만 측정하는 것을 피하세요. 예를 들어, 맞춤 뷰의 레이아웃 벤치마크가 레이아웃 캐시의 성능만 측정할 수 있는데, 이러한 상황을 피하려면 각 루프에 서로 다른 레이아웃 매개변수를 전달하면 됩니다. 그러나 파일 시스템 성능을 측정하는 등의 다른 경우에는 OS가 루프에 있는 동안 파일 시스템을 캐시하기 때문에 이것이 어려울 수 있습니다.
자주 실행되지 않는 코드
애플리케이션 시작 중에 한 번만 실행되는 코드는 Android 런타임(ART)에서 JIT로 컴파일되지 않을 가능성이 큽니다. 따라서 이 코드가 타이트 루프에서 실행될 때 이를 microbenchmark로 벤치마킹하는 것은 성능을 측정하는 현실적인 방법이 아닙니다.
이러한 종류의 코드를 벤치마킹하려면 앱 실행과 스크롤 성능 같은 보다 높은 수준의 사용자 상호작용 측정을 지원하는 Jetpack Macrobenchmark를 사용하는 것이 좋습니다.
전체 프로젝트 설정
일회성이 아닌 정기적인 벤치마킹을 실행하도록 벤치마킹을 설정하려면 벤치마크를 자체 모듈로 격리합니다. 이렇게 하면 debuggable
을 false
로 설정하는 것과 같은 구성이 다른 일반 테스트와 분리됩니다.
벤치마크 모듈을 추가하려면 먼저 벤치마킹하려는 코드와 리소스를 라이브러리 모듈에 추가합니다(아직 추가되지 않은 경우).
이 샘플에서는 이러한 방식으로 프로젝트를 설정하는 방법의 예를 제공합니다.
Android 스튜디오 속성 설정
Android 스튜디오 3.5를 사용하는 경우 벤치마크 모듈 마법사 지원을 사용하도록 Android 스튜디오 속성을 수동으로 설정해야 합니다. Android 스튜디오 3.6 이상에서는 이런 설정이 필요 없습니다.
Android 스튜디오 템플릿을 벤치마킹에 사용할 수 있도록 하려면 다음 단계를 따르세요.
Android 스튜디오 3.5에서 Help > Edit Custom Properties를 클릭합니다.
열린 파일에 다음 행을 추가합니다.
npw.benchmark.template.module=true
파일을 저장하고 닫습니다.
Android 스튜디오를 다시 시작합니다.
새 모듈 만들기
벤치마킹 모듈 템플릿이 벤치마킹 설정을 자동으로 구성합니다.
모듈 템플릿을 사용하여 새 모듈을 만들려면 다음 단계를 따르세요.
프로젝트 또는 모듈을 마우스 오른쪽 버튼으로 클릭하고 New > Module을 선택합니다.
Benchmark Module을 선택하고 Next를 클릭합니다.
그림 1. 벤치마크 모듈
모듈 이름을 입력하고 언어를 선택한 다음 Finish를 클릭합니다.
벤치마크 디렉터리가 추가되고
debuggable
이false
로 설정된 상태로 벤치마킹용으로 사전 구성된 모듈이 생성됩니다.
벤치마크 작성
벤치마크는 표준 계측 테스트입니다. 벤치마크를 만들려면 라이브러리에서 제공되는 BenchmarkRule
클래스를 사용하세요. 활동을 벤치마킹하려면 ActivityTestRule
또는 ActivityScenarioRule
을 사용합니다. UI 코드를 벤치마킹하려면 @UiThreadTest
를 사용합니다.
다음 코드는 샘플 벤치마크를 보여줍니다.
Kotlin
@RunWith(AndroidJUnit4::class) class ViewBenchmark { @get:Rule val benchmarkRule = BenchmarkRule() @Test fun simpleViewInflate() { val context = ApplicationProvider.getApplicationContext<Context>() val inflater = LayoutInflater.from(context) val root = FrameLayout(context) benchmarkRule.measureRepeated { inflater.inflate(R.layout.test_simple_view, root, false) } } }
자바
@RunWith(AndroidJUnit4::class) public class ViewBenchmark { @Rule public BenchmarkRule benchmarkRule = new BenchmarkRule(); @Test public void simpleViewInflate() { Context context = ApplicationProvider.getApplicationContext<Context>(); final BenchmarkState state = benchmarkRule.getState(); LayoutInflater inflater = LayoutInflater.from(context); FrameLayout root = new FrameLayout(context); while (state.keepRunning()) { inflater.inflate(R.layout.test_simple_view, root, false); } } }
다음 코드 샘플과 같이 측정하지 않을 코드 섹션의 타이밍을 중지할 수 있습니다.
Kotlin
@Test fun bitmapProcessing() = benchmarkRule.measureRepeated { val input: Bitmap = runWithTimingDisabled { constructTestBitmap() } processBitmap(input) }
자바
@Test public void bitmapProcessing() { final BenchmarkState state = benchmarkRule.getState(); while (state.keepRunning()) { state.pauseTiming(); Bitmap input = constructTestBitmap(); state.resumeTiming(); processBitmap(input); } }
벤치마크 실행에 관한 자세한 내용은 벤치마크 실행을 참고하세요.
벤치마크 실행
Android 스튜디오에서 @Test
를 실행하는 것처럼 벤치마크를 실행하세요. Android 스튜디오 3.4 이상에서는 콘솔에 전송된 출력을 볼 수 있습니다.
벤치마크를 실행하려면 모듈에서 benchmark/src/androidTest
로 이동하고 Control
+Shift
+F10
(Mac의 경우 Command
+Shift
+R
)을 누릅니다. 그림 2에서와 같이 벤치마크 결과가 콘솔에 표시됩니다.
그림 2. Android 스튜디오의 벤치마킹 출력
정기적으로 명령줄에서 connectedCheck
를 실행합니다.
./gradlew benchmark:connectedCheck
데이터 수집
추가 측정항목 및 기기 정보가 포함된 전체 벤치마크 보고서는 JSON 형식으로 되어 있습니다.
기본적으로 androidx.benchmark
Gradle 플러그인이 JSON 출력을 사용 설정합니다. Gradle 기반이 아닌 빌드 환경에서 수동으로 JSON 출력을 사용 설정하려면 true
로 설정된 계측 인수 androidx.benchmark.output.enable
을 전달합니다.
다음은 adb shell am instrument
명령어 사용의 예입니다.
adb shell am instrument -w -e "androidx.benchmark.output.enable" "true" com.android.foo/androidx.benchmark.junit4.AndroidBenchmarkRunner
기본적으로 JSON 보고서는 기기의 디스크에서 테스트 APK의 외부 공유 다운로드 폴더에 작성되며 일반적으로 다음 위치에 있습니다.
/storage/emulated/0/Download/app_id-benchmarkData.json
계측 인수 additionalTestOutputDir
을 사용하여 기기에서 벤치마크 보고서가 저장되는 위치를 구성할 수 있습니다.
adb shell am instrument -w -e "androidx.benchmark.output.enable" "true" -e "additionalTestOutputDir" "/path_to_a_directory_on_device_test_has_write_permissions_to/" com.android.foo/androidx.benchmark.junit4.AndroidBenchmarkRunner
JSON 보고서가 기기에서 호스트로 복사됩니다. 이러한 보고서는 다음의 호스트 머신에 작성됩니다.
project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/app_id-benchmarkData.json
Android Gradle 플러그인 3.6 이상
Gradle을 사용하여 명령줄에서 벤치마크를 실행하는 경우 Android Gradle 플러그인 3.6 이상을 사용하는 프로젝트는 프로젝트의 gradle.properties
파일에 다음 플래그를 추가할 수 있습니다.
android.enableAdditionalTestOutput=true
이렇게 하면 실험용 Android Gradle 플러그인 기능이 API 16 이상을 실행하는 기기의 벤치마크 보고서를 가져올 수 있습니다.
Android Gradle 플러그인 3.5 이하
이전 버전의 Android Gradle 플러그인을 사용하는 사용자의 경우 androidx.benchmark
Gradle 플러그인은 기기에서 호스트로의 JSON 벤치마크 보고서 복사를 처리합니다.
AGP 3.5 이하를 사용하며 API 수준 29 이상을 타겟팅하는 경우 벤치마크의 androidTest
디렉터리에 있는 Android 매니페스트에 플래그를 추가하여 레거시 외부 저장소 동작을 사용 설정해야 합니다.
<manifest ... > <!-- This attribute is "false" by default on apps targeting Android 10. --> <application android:requestLegacyExternalStorage="true" ... > ... </application> </manifest>
자세한 내용은 범위 지정 저장소를 일시적으로 선택 해제를 참고하세요.
클록 안정성
휴대기기의 클록은 높은 상태(성능을 위해)에서 낮은 상태(전원을 절약하기 위해 또는 기기에 열이 발생하는 경우)까지 동적으로 변경됩니다. 이와 같이 변화하는 클록으로 인해 벤치마크 숫자가 크게 달라질 수 있으므로 라이브러리에서 이 문제를 처리하는 방법을 제공합니다.
클록 잠금(루팅이 필요함)
클록 잠금은 안정적인 성능을 얻는 가장 좋은 방법입니다. 클록을 잠그면 클록이 기기를 과열시킬 만큼 높아지거나 벤치마크가 CPU를 완전히 활용하지 않는 경우 낮아지지 않습니다. 클록을 잠그는 것은 안정적인 성능을 보장하는 가장 좋은 방법이지만 adb
루팅이 필요하기 때문에 대부분의 기기에서 지원되지 않습니다.
클록을 잠그려면 제공된 도우미 플러그인을 기본 build.gradle
파일의 최상위 프로젝트 클래스 경로에 추가하세요.
Groovy
buildscript { ... dependencies { ... classpath "androidx.benchmark:benchmark-gradle-plugin:1.1.0-alpha13" } }
Kotlin
buildscript { ... dependencies { ... classpath("androidx.benchmark:benchmark-gradle-plugin:1.1.0-alpha13") } }
벤치마크 모듈의 build.gradle
에 플러그인을 적용하세요.
Groovy
plugins { id 'com.android.app' id 'androidx.benchmark' } ...
Kotlin
plugins { id("com.android.app") id("androidx.benchmark") ... }
이렇게 하면 ./gradlew lockClocks
및 ./gradlew unlockClocks
를 비롯한 벤치마킹 Gradle 작업이 프로젝트에 추가됩니다. 이러한 작업을 사용하여 adb를 통해 기기의 CPU를 잠그거나 잠금 해제하세요.
adb에 여러 기기가 표시되면 환경 변수 ANDROID_SERIAL
을 사용하여 Gradle 작업이 작동할 기기를 지정하세요.
ANDROID_SERIAL=device-id-from-adb-devices ./gradlew lockClocks
지속적인 성능 모드
Window.setSustainedPerformanceMode()
는 앱에서 더 낮은 최대 CPU 주파수를 선택할 수 있도록 하는 기능이며 일부 기기에서 지원됩니다. 지원되는 기기에서 실행되는 경우 벤치마크 라이브러리는 이 API를 사용하는 동시에 자체 활동을 실행하여 열 제한을 방지하고 결과를 안정화합니다.
이 기능은 Gradle 플러그인에서 설정된 testInstrumentationRunner
를 통해 기본적으로 사용 설정됩니다. 맞춤 실행기를 사용하려면 AndroidBenchmarkRunner
를 서브클래스로 만들어 testInstrumentationRunner
로 사용할 수 있습니다.
벤치마크가 다른 앱 드로잉 없이 포그라운드에서 실행될 수 있도록 실행기가 불투명한 전체 화면 활동을 시작합니다.
자동 실행 일시중지
클록 잠금 및 지속적인 성능이 모두 사용되지 않으면 라이브러리에서 자동 열 제한 감지를 실행합니다. 사용 설정된 경우 내부 벤치마크가 주기적으로 실행되어 CPU 성능을 저하할 정도로 기기 온도가 높아진 시기를 확인합니다. CPU 성능 저하가 감지되면 라이브러리가 실행을 일시중지하여 기기의 열을 식히고 현재 벤치마크를 다시 시도합니다.
구성 오류
라이브러리는 다음 조건을 감지하여 프로젝트 및 환경이 출시 당시의 정확한 성능을 제공하도록 설정되었는지 확인합니다.
Debuggable
이false
로 설정되어 있습니다.- 에뮬레이터가 아닌 실제 기기가 사용됩니다.
- 기기가 루팅된 경우 시계가 잠깁니다.
- 기기의 배터리 수준이 충분합니다.
위의 검사 중 하나라도 실패하면 벤치마크에서 오류가 발생하여 부정확한 측정을 방지합니다.
이러한 오류를 경고로 표시하지 않고 이로 인해 오류가 발생하거나 벤치마크가 중지되지 않도록 하려면 억제할 오류 유형을 쉼표로 구분된 목록으로 계측 인수 androidx.benchmark.suppressErrors
에 전달하세요.
adb shell am instrument -w -e "androidx.benchmark.suppressErrors" "DEBUGGABLE" com.android.foo/androidx.benchmark.junit4.AndroidBenchmarkRunner
Gradle에서 다음과 같이 설정할 수 있습니다.
Groovy
android { defaultConfig { testInstrumentationRunnerArgument 'androidx.benchmark.suppressErrors', 'DEBUGGABLE' } }
Kotlin
android { defaultConfig { testInstrumentationRunnerArguments(mapOf( "androidx.benchmark.suppressErrors" to "DEBUGGABLE" )) } }
오류를 억제하면 벤치마크가 잘못 구성된 상태로 실행될 수 있지만 테스트 이름 앞에 오류를 추가하여 벤치마크의 출력이 의도적으로 손상됩니다. 즉, 디버그 가능한 벤치마크가 위와 같이 억제되면 테스트 이름 앞에는 DEBUGGABLE_
이 추가됩니다.
프로파일링
벤치마크를 프로파일링하여 측정된 코드가 느리게 실행되는 이유를 조사할 수 있습니다.
벤치마크 모듈의 build.gradle
파일에 다음을 추가하세요.
Groovy
android { defaultConfig { // must be one of: 'None', 'StackSampling', or 'MethodTracing' testInstrumentationRunnerArgument 'androidx.benchmark.profiling.mode', 'StackSampling' } }
Kotlin
android { defaultConfig { // must be one of: 'None', 'StackSampling', or 'MethodTracing' testInstrumentationRunnerArgument = mapOf( "androidx.benchmark.profiling.mode", "StackSampling" ) } }
벤치마크를 실행하면 출력 .trace
파일이 JSON 결과와 함께 호스트의 디렉터리에 복사됩니다. Android 스튜디오에서 File > Open을 사용하여 이 파일을 열고 CPU 프로파일러에서 프로파일링 결과를 검사합니다.
메서드 추적
메서드 추적을 사용하면 메서드 트레이스를 캡처하기 전에 준비 작업을 통해 벤치마크가 호출한 모든 메서드를 기록합니다. 성능 결과는 각 메서드 시작/종료 캡처의 오버헤드에 크게 영향을 받습니다.
스택 샘플링
스택 샘플링을 사용하면 준비가 완료된 후 벤치마크가 호출 스택을 샘플링합니다. 계측 인수를 사용하여 샘플링 주파수와 샘플링 지속 시간을 제어할 수 있습니다.
Android 10(API 29) 이상에서 스택 샘플링은 Simpleperf를 사용하여 C++ 코드를 비롯한 앱 호출 스택을 샘플링합니다. Android 9(API 28) 이하에서는 Debug.startMethodTracingSampling을 사용하여 스택 샘플을 캡처합니다.
메서드 추적 및 샘플링을 사용하는 방법을 자세히 알아보려면 CPU 프로파일링 구성을 참고하세요.
벤치마킹 샘플
다음 프로젝트에서 샘플 벤치마크 코드를 사용할 수 있습니다.
샘플 프로젝트는 다음과 같습니다.
BenchmarkSample: 벤치마크 모듈을 사용하여 코드 및 UI를 측정하는 방법을 보여주는 독립 실행형 샘플입니다.
PagingWithNetworkSample:
RecyclerView
성능을 벤치마킹하는 방법을 보여주는 Android 아키텍처 구성요소 샘플입니다.WorkManagerSample:
WorkManager
작업자를 벤치마킹하는 방법을 보여주는 Android 아키텍처 구성요소 샘플입니다.
추가 리소스
탐색에 관해 자세히 알아보려면 다음 추가 리소스를 참고하세요.
블로그
의견 보내기
벤치마킹을 사용할 때 문제를 보고하거나 기능 요청을 제출하려면 공개 Issue Tracker를 참고하세요.