Macrobenchmark 작성

앱 시작과 복잡한 UI 조작(RecyclerView 스크롤 또는 애니메이션 실행)과 같이 앱의 대규모 사용 사례를 테스트하는 데 Macrobenchmark 라이브러리를 사용합니다. 코드의 작은 영역을 테스트하려면 Microbenchmark 라이브러리를 참고하세요. 이 페이지에서는 Macrobenchmark 라이브러리를 설정하는 방법을 보여줍니다.

라이브러리는 Android 스튜디오 콘솔과 JSON 파일 양쪽에 자세한 정보가 포함된 벤치마킹 결과를 출력합니다. 또한 Android 스튜디오에서 로드하고 분석할 수 있는 트레이스 파일도 제공합니다.

지속적 통합의 벤치마크에 설명된 대로 지속적 통합(CI) 환경에서 Macrobenchmark 라이브러리를 사용하세요.

Macrobenchmark를 사용하여 기준 프로필을 생성할 수 있습니다. 먼저 Macrobenchmark 라이브러리를 설정하고 기준 프로필을 생성하면 됩니다.

프로젝트 설정

Macrobenchmark와 통합된 IDE 기능을 사용하려면 최신 버전의 Android 스튜디오에서 Macrobenchmark를 사용하는 것이 좋습니다.

Macrobenchmark 모듈 설정

Macrobenchmark는 앱 코드와 분리되어 앱 측정 테스트 실행을 담당하는 com.android.test 모듈이 필요합니다.

Android 스튜디오에는 Macrobenchmark 모듈 설정을 간소화할 수 있는 템플릿이 있습니다. 벤치마킹 모듈 템플릿은 샘플 시작 벤치마크를 포함해 앱 모듈에서 빌드한 앱을 측정할 수 있는 모듈을 프로젝트에 자동으로 생성합니다.

모듈 템플릿을 사용하여 새 모듈을 만들려면 다음 단계를 따르세요.

  1. Android 스튜디오의 Project 패널에서 프로젝트 또는 모듈을 마우스 오른쪽 버튼으로 클릭하고 New > Module을 선택합니다.

  2. Template 창에서 Benchmark를 선택합니다. 새로운 Macrobenchmark 모듈의 패키지 및 모듈 이름 외에도 타겟 앱(벤치마킹할 앱)을 맞춤설정할 수 있습니다.

  3. Finish를 클릭합니다.

벤치마크 모듈 템플릿

그림 1. 벤치마크 모듈 템플릿

앱 설정

Macrobenchmark의 타겟이라고 하는 앱을 벤치마킹하려면 앱이 profileable이어야 합니다. 그래야 성능에 영향을 주지 않고 자세한 트레이스 정보를 읽을 수 있습니다. 모듈 마법사가 앱의 AndroidManifest.xml 파일에 자동으로 <profileable> 태그를 추가합니다.

타겟 앱에 ProfilerInstaller 1.3 이상이 포함되어 있는지 확인합니다. 이는 Macrobenchmark 라이브러리에서 프로필 캡처와 재설정, 셰이더 캐시 삭제를 사용 설정하는 데 필요합니다.

벤치마크된 앱은 가능한 한 출시 버전(또는 프로덕션)에 가깝게 구성합니다. 앱을 디버깅이 불가능하고 가급적 압축되도록 설정하면 성능이 향상됩니다. 일반적으로 이 작업은 동일하게 실행되지만 디버그 키로 로컬에서 서명된 출시 변형의 복사본을 만들어 진행합니다. 또는 initWith를 사용하여 Gradle에 작업을 실행하도록 지시할 수 있습니다.

Kotlin

buildTypes {
    getByName("release") {
        isMinifyEnabled = true
        isShrinkResources = true
        proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))
    }

    create("benchmark") {
        initWith(getByName("release"))
        signingConfig = signingConfigs.getByName("debug")
    }
}

Groovy

buildTypes {
    getByName("release") {
        isMinifyEnabled = true
        isShrinkResources = true
        proguardFiles(
            getDefaultProguardFile("proguard-android-optimize.txt"),
            "proguard-rules.pro"
        )
        // In real app, this would use its own release keystore
        signingConfig = signingConfigs.getByName("debug")
    }
}

벤치마크를 실행하여 그림 2와 같이 앱의 올바른 변형을 빌드하고 테스트할 수 있도록 하려면 다음을 실행하세요.

  1. Gradle 동기화를 실행합니다.
  2. Build Variants 패널을 엽니다.
  3. 앱 및 Macrobenchmark 모듈의 벤치마크 변형을 모두 선택합니다.

벤치마크 변형 선택

그림 2. 벤치마크 변형 선택

(선택사항) 다중 모듈 앱 설정

앱에 Gradle 모듈이 2개 이상 있는 경우 빌드 스크립트는 컴파일할 빌드 변형을 알고 있어야 합니다. matchingFallbacks 속성을 :macrobenchmark:app 모듈의 benchmark 빌드 유형에 추가합니다. 나머지 Gradle 모듈은 이전과 동일한 구성이면 됩니다.

Kotlin

create("benchmark") {
    initWith(getByName("release"))
    signingConfig = signingConfigs.getByName("debug")

    matchingFallbacks += listOf("release")
}

Groovy

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
}

해당하는 변형을 모르면 새로 추가된 benchmark 빌드 유형으로 인해 빌드가 실패하고 다음과 같은 오류 메시지가 표시됩니다.

> Could not resolve project :shared.
     Required by:
         project :app
      > No matching variant of project :shared was found.
      ...

프로젝트에서 빌드 변형을 선택할 때는 그림 3과 같이 :app:macrobenchmark 모듈에는 benchmark를, 앱에 있는 기타 다른 모듈에는 release를 선택하세요.

빌드 유형으로 release 및 benchmark가 선택된 다중 모듈 프로젝트의 벤치마크 변형

그림 3. 빌드 유형으로 release 및 benchmark가 선택된 다중 모듈 프로젝트의 벤치마크 변형

자세한 내용은 변형 인식 종속 항목 관리 사용을 참고하세요.

(선택사항) 제품 버전 설정

앱에 여러 제품 버전이 설정되어 있는 경우 빌드 및 벤치마킹할 앱 제품 버전을 알 수 있도록 :macrobenchmark 모듈을 구성하세요.

이 페이지의 예에서는 다음 스니펫과 같이 :app 모듈에서 두 제품 버전 demoproduction을 사용합니다.

Kotlin

flavorDimensions += "environment"
productFlavors {
    create("demo") {
        dimension = "environment"
        // ...
    }
    create("production") {
        dimension = "environment"
        // ...
    }
}

Groovy

flavorDimensions 'environment'
productFlavors {
    demo {
        dimension 'environment'
        // ...
    }

    production {
        dimension 'environment'
        // ...
    }
}

이 구성이 없으면 여러 Gradle 모듈과 유사한 빌드 오류가 발생할 수 있습니다.

Could not determine the dependencies of task ':macrobenchmark:connectedBenchmarkAndroidTest'.
> Could not determine the dependencies of null.
   > Could not resolve all task dependencies for configuration ':macrobenchmark:benchmarkTestedApks'.
      > Could not resolve project :app.
        Required by:
            project :macrobenchmark
         > The consumer was configured to find a runtime of a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'benchmark', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.3.0'. However we cannot choose between the following variants of project :app:
             - demoBenchmarkRuntimeElements
             - productionBenchmarkRuntimeElements
           All of them match the consumer attributes:
           ...

다음 두 섹션에서는 여러 제품 버전으로 벤치마킹을 구성하는 방법을 보여줍니다.

MissingDimensionStrategy 사용

:macrobenchmark 모듈의 defaultConfig에서 missingDimensionStrategy를 지정하면 빌드 시스템에 이 버전 차원으로 대체할 것을 지시하게 됩니다. 모듈에서 차원을 찾을 수 없는 경우 어느 차원을 사용할지 지정합니다. 다음 예에서는 production 버전을 기본 차원으로 사용합니다.

Kotlin

defaultConfig {
    missingDimensionStrategy("environment", "production")
}

Groovy

defaultConfig {
    missingDimensionStrategy "environment", "production"
}

이렇게 하면 :macrobenchmark 모듈이 지정된 제품 버전만 빌드하고 벤치마킹할 수 있습니다. 이는 하나의 제품 버전에만 벤치마킹할 올바른 구성이 있는 경우에 유용합니다.

:macrobenchmark 모듈에서 제품 버전 정의

다른 제품 버전을 빌드하고 벤치마킹하려면 :macrobenchmark 모듈에서 제품 버전을 정의하세요. :app 모듈에서와 마찬가지로 지정하되 dimensionproductFlavors만 할당합니다. 다른 설정은 필요하지 않습니다.

Kotlin

flavorDimensions += "environment"
productFlavors {
    create("demo") {
        dimension = "environment"
    }
    create("production") {
        dimension = "environment"
    }
}

Groovy

flavorDimensions 'environment'
productFlavors {
    demo {
        dimension 'environment'
    }

    production {
        dimension 'environment'
    }
}

프로젝트를 정의하고 동기화한 후에는 그림 4와 같이 Build Variants 창에서 관련 빌드 변형을 선택합니다.

제품 버전이 있는 프로젝트의 벤치마크 변형에서 productionBenchmark 및 출시 버전이 선택되어 있음

그림 4. 제품 버전이 있는 프로젝트의 벤치마크 변형에서 'productionBenchmark' 및 'release'가 선택되어 있음

자세한 내용은 변형 매칭과 관련된 빌드 오류 해결을 참고하세요.

Macrobenchmark 클래스 만들기

벤치마크 테스트는 Macrobenchmark 라이브러리의 MacrobenchmarkRule JUnit4 규칙 API를 통해 제공됩니다. 이 API에는 타겟 앱이 실행되고 벤치마크되어야 하는 다양한 조건을 지정할 수 있는 measureRepeated 메서드가 포함되어 있습니다.

개발자가 지정해야 하는 항목은 타겟 앱의 packageName, 측정할 metrics, 벤치마크가 실행되어야 하는 iterations 횟수입니다.

Kotlin

@LargeTest
@RunWith(AndroidJUnit4::class)
class SampleStartupBenchmark {
    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()

    @Test
    fun startup() = benchmarkRule.measureRepeated(
        packageName = TARGET_PACKAGE,
        metrics = listOf(StartupTimingMetric()),
        iterations = DEFAULT_ITERATIONS,
        setupBlock = {
            // Press home button before each run to ensure the starting activity isn't visible.
            pressHome()
        }
    ) {
        // starts default launch activity
        startActivityAndWait()
    }
}

Java

@LargeTest
@RunWith(AndroidJUnit4.class)
public class SampleStartupBenchmark {
    @Rule
    public MacrobenchmarkRule benchmarkRule = new MacrobenchmarkRule();

    @Test
    public void startup() {
        benchmarkRule.measureRepeated(
            /* packageName */ TARGET_PACKAGE,
            /* metrics */ Arrays.asList(new StartupTimingMetric()),
            /* iterations */ 5,
            /* measureBlock */ scope -> {
                // starts default launch activity
                scope.startActivityAndWait();
                return Unit.INSTANCE;
            }
        );
    }
}

벤치마크 맞춤설정에 관한 모든 옵션은 벤치마크 맞춤설정 섹션을 참고하세요.

벤치마크 실행

Android 스튜디오 내에서 테스트를 실행하여 기기에서 앱 성능을 측정합니다. 그림 5와 같이 테스트 클래스 또는 메서드 옆의 여백 작업을 사용하여 다른 @Test를 실행하는 것과 동일한 방식으로 벤치마크를 실행할 수 있습니다.

테스트 클래스 옆의 여백 작업으로 Macrobenchmark 실행

그림 5. 테스트 클래스 옆의 여백 작업으로 Macrobenchmark 실행

다음과 같이 connectedCheck 명령어를 실행하여 명령줄에서 Gradle 모듈의 모든 벤치마크를 실행할 수도 있습니다.

./gradlew :macrobenchmark:connectedCheck

다음을 실행하여 단일 테스트를 실행할 수 있습니다.

./gradlew :macrobenchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.macrobenchmark.startup.SampleStartupBenchmark#startup

지속적 통합에서 벤치마크를 실행하고 모니터링하는 방법에 관한 자세한 내용은 지속적 통합의 벤치마크를 참고하세요.

벤치마크 결과

벤치마크 실행이 완료되면 측정항목이 Android 스튜디오에 직접 표시되고 CI 사용을 위해 JSON 파일로 출력됩니다. 측정된 반복마다 별개의 시스템 트레이스가 캡처됩니다. 그림 6과 같이 Test Results 창에 있는 링크를 클릭하여 이러한 트레이스 결과를 열 수 있습니다.

Macrobenchmark 시작 결과

그림 6. Macrobenchmark 시작 결과

트레이스가 로드되면 분석할 프로세스를 선택하라는 메시지가 Android 스튜디오에 표시됩니다. 그림 7과 같이 선택 항목이 타겟 앱 프로세스로 자동 입력됩니다.

스튜디오 트레이스 프로세스 선택

그림 7. 스튜디오 트레이스 프로세스 선택

트레이스 파일이 로드되면 스튜디오의 CPU 프로파일러 도구에 결과가 표시됩니다.

스튜디오 트레이스

그림 8. 스튜디오 트레이스

JSON 보고서와 모든 프로파일링 트레이스도 기기에서 호스트로 자동 복사됩니다. 호스트 머신의 다음 위치에 기록됩니다.

project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/

수동으로 트레이스 파일에 액세스

Perfetto 도구를 사용하여 트레이스 파일을 분석하려면 추가 단계가 필요합니다. Perfetto는 트레이스 중에 기기에서 발생한 모든 프로세스를 검사하는 반면, Android 스튜디오의 CPU 프로파일러는 검사를 단일 프로세스로 제한합니다.

Android 스튜디오 또는 Gradle 명령줄에서 테스트를 호출하면 트레이스 파일이 기기에서 호스트로 자동 복사됩니다. 호스트 머신의 다음 위치에 기록됩니다.

project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/TrivialStartupBenchmark_startup[mode=COLD]_iter002.perfetto-trace

호스트 시스템에 트레이스 파일이 있으면 메뉴에서 File > Open을 선택하여 Android 스튜디오에서 열 수 있습니다. 그러면 이전 섹션에 표시된 프로파일러 도구 뷰가 표시됩니다.

구성 오류

앱이 잘못 구성(디버그 가능 또는 프로파일링 불가)되면 Macrobenchmark는 부정확하거나 불완전한 측정을 보고하는 대신 오류를 반환합니다. androidx.benchmark.suppressErrors 인수를 사용하여 이러한 오류를 억제할 수 있습니다.

Macrobenchmark는 에뮬레이터를 측정하려고 하거나 기기에 배터리가 부족한 경우에도 코어 가용성 및 클럭 속도가 저하될 수 있기 때문에 오류를 반환합니다.

벤치마크 맞춤설정

measureRepeated 함수는 라이브러리가 수집하는 측정항목, 앱의 시작 및 컴파일 방식 또는 벤치마크가 실행되는 반복 횟수에 영향을 미치는 다양한 매개변수를 허용합니다.

측정항목 캡처

측정항목은 벤치마크에서 추출된 기본 정보 유형입니다. 사용 가능한 측정항목은 다음과 같습니다.

측정항목에 관한 자세한 내용은 Macrobenchmark 측정항목 캡처를 참고하세요.

맞춤 이벤트로 트레이스 데이터 개선

맞춤 트레이스 이벤트로 앱을 계측하는 것이 유용할 수 있습니다. 트레이스 보고서의 나머지 부분에 표시되는 맞춤 트레이스 이벤트는 앱의 특정 문제를 파악하는 데 도움이 될 수 있습니다. 맞춤 트레이스 이벤트의 생성 방법에 관한 자세한 내용은 맞춤 이벤트 정의를 참고하세요.

CompilationMode

Macrobenchmark는 CompilationMode를 지정할 수 있습니다. 이 값은 DEX 바이트 코드(APK 내 바이트 코드 형식)에서 기계어 코드(사전 컴파일된 C++와 유사)로 미리 컴파일되어야 하는 앱의 양을 정의합니다.

기본적으로 Macrobenchmark는 Android 7(API 수준 24) 이상에서 기준 프로필(사용 가능한 경우)을 설치하는 CompilationMode.DEFAULT로 실행됩니다. Android 6(API 수준 23) 이하를 사용 중인 경우 컴파일 모드는 APK를 기본 시스템 동작으로 완전히 컴파일합니다.

타겟 앱에 기준 프로필과 ProfileInstaller 라이브러리가 모두 포함되어 있다면 기준 프로필을 설치할 수 있습니다.

Android 7 이상에서는 CompilationMode를 맞춤설정하여 다양한 수준의 AOT(Ahead-Of-Time) 컴파일 또는 JIT 캐싱을 모방하도록 기기 내 사전 컴파일 양에 영향을 줄 수 있습니다. CompilationMode.Full, CompilationMode.Partial, CompilationMode.None, CompilationMode.Ignore를 참고하세요.

이 기능은 ART 컴파일 명령어를 기반으로 빌드됩니다. 각 벤치마크는 벤치마크 간의 간섭을 방지하기 위해 벤치마크가 시작하기 전에 프로필 데이터를 삭제합니다.

StartupMode

활동 시작을 실행하려면 사전 정의된 시작 모드(COLD, WARM 또는 HOT)를 전달하면 됩니다. 이 매개변수는 활동 시작 방식과 테스트 시작 시의 프로세스 상태를 변경합니다.

시작 유형에 관한 자세한 내용은 앱 시작 시간을 참고하세요.

샘플

샘플 프로젝트는 GitHub에 있는 저장소의 Macrobenchmark 샘플에서 확인할 수 있습니다.

의견 보내기

Jetpack Macrobenchmark에 관한 문제를 보고하거나 기능 요청을 제출하려면 공개 Issue Tracker를 참고하세요.