Macrobenchmark を作成する

Macrobenchmark ライブラリは、アプリの起動や複雑な UI 操作(RecyclerView のスクロールやアニメーションの実行など)のようなアプリ内の比較的大きな領域に対応するユースケースをテストするために使用します。比較的小さな領域のコードをテストする場合は、Microbenchmark ライブラリを参照してください。

ライブラリは、Android Studio コンソールと JSON ファイルの両方に詳細情報付きのベンチマーク結果を出力します。Android Studio に読み込んで分析できるトレース ファイルも提供します。

また、継続的インテグレーションでベンチマークを実行するで説明しているように、継続的インテグレーション(CI)環境で Macrobenchmark ライブラリを使用することもできます。

プロジェクトの設定

Macrobenchmark は、Android Studio の最新バージョン(Bumblebee 2021.1.1 以降)で使用することをおすすめします。このバージョンの IDE は、Macrobenchmark を統合する新機能を備えているからです。

Macrobenchmark モジュールを設定する

マクロ ベンチマークを行うには、アプリを測定するテストを実行するために、アプリコードとは別個の com.android.test モジュールが必要です。

Bumblebee 以降

Android Studio Bumblebee 2021.1.1 には、Macrobenchmark モジュールの設定を簡素化するために使用できるテンプレートが用意されています。ベンチマーク モジュール テンプレートを使用すると、アプリ モジュールによってビルドされたアプリを測定するためのモジュール(サンプル起動ベンチマークなど)が、プロジェクト内に自動的に作成されます。

モジュール テンプレートを使用して新しいモジュールを作成する手順は次のとおりです。

  1. Android Studio の [Project] パネルでプロジェクトまたはモジュールを右クリックして、[New] > [Module] をクリックします。

  2. [Templates] ペインで [Benchmark] を選択します。

  3. ターゲット アプリ(ベンチマーク対象のアプリ)に加えて、新しい Macrobenchmark モジュールのパッケージ名とモジュール名をカスタマイズできます。

  4. [Finish] をクリックします。

ベンチマーク モジュール テンプレート

Arctic Fox

Arctic Fox では、ライブラリ モジュールを作成してそれをテスト モジュールに変換します。

  1. Android Studio の [Project] パネルでプロジェクトまたはモジュールを右クリックして、[New] > [Module] をクリックします。
  2. [Templates] ペインで [Android Library] を選択します。
  3. モジュール名には「macrobenchmark」と入力します。
  4. [Minimum SDK] を [API 23: Android M] に設定します。
  5. [Finish] をクリックします。

新しいライブラリ モジュールを構成する

Gradle ファイルを変更する

Macrobenchmark モジュールの build.gradle を次のようにカスタマイズします。

  1. プラグインを com.android.library から com.android.test に変更します。
    apply plugin 'com.android.test'
  2. 必要なテスト モジュール プロパティを android {} ブロックに追加します。

    Groovy

    android {
        // ...
        // Note that your module name may have different name
        targetProjectPath = ":app"
        // Enable the benchmark to run separately from the app process
        experimentalProperties["android.experimental.self-instrumenting"] = true
    
        buildTypes {
            // declare a build type to match the target app's build type
            benchmark {
                debuggable = true
                signingConfig = debug.signingConfig
            }
        }
    }
      

    Kotlin

    android {
        // ...
        // Note that your module name may have different name
        targetProjectPath = ":app"
        // Enable the benchmark to run separately from the app process
        experimentalProperties["android.experimental.self-instrumenting"] = true
    
        buildTypes {
            // declare a build type to match the target app's build type
            create("benchmark") {
                isDebuggable = true
                signingConfig = signingConfigs.getByName("debug")
            }
        }
    }
      

  3. testImplementation または androidTestImplementation という名前の依存関係をすべて implementation に変更します。
  4. Macrobenchmark ライブラリへの依存関係を追加します。
    implementation 'androidx.benchmark:benchmark-macro-junit4:1.1.0-beta03'
  5. このモジュールに対して benchmark buildType のみを許可します。android{} ブロックの後、dependencies{} ブロックの前に、以下の行を追加します。

    Groovy

    androidComponents {
        beforeVariants(selector().all()) {
            // enable only the benchmark buildType, since we only want to measure close to release performance
            enabled = buildType == 'benchmark'
        }
    }
      

    Kotlin

    androidComponents {
        beforeVariants {
            // enable only the benchmark buildType, since we only want to measure close to release performance
            it.enable = it.buildType == "benchmark"
        }
    }
      
  6. ディレクトリ構造を簡素化します。

    com.android.test モジュールには、すべてのテスト用のソース ディレクトリが 1 つだけあります。他のソース ディレクトリ(src/testsrc/androidTest など)は使用しないので、削除します。

アプリを設定する

アプリ(マクロ ベンチマークの「ターゲット」と呼びます)のベンチマークを行うには、そのアプリを profileable にして、詳細なトレース情報を読み取れるようにする必要があります。これは、アプリの AndroidManifest.xml<application> タグで有効にします。

<!-- enable profiling by macrobenchmark -->
<profileable
    android:shell="true"
    tools:targetApi="q" />

できる限りリリース バージョン(製品版)に近くなるようにベンチマーク対象のアプリを構成します。アプリはデバッグ不可として設定します。パフォーマンスを高めるために、圧縮をオンにすることをおすすめします。そのためには、通常、リリース バリアントのコピーを作成します。これは同じ処理を行いますが、デバッグキーを使用してローカルで署名されます。または、initWith を使用して Gradle に処理を指示することもできます。

Groovy

buildTypes {
    release {
        minifyEnabled true
        shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }

    benchmark {
        initWith buildTypes.release
        signingConfig signingConfigs.debug

Kotlin

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

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

Gradle 同期を実行し、左側の [Build Variants] パネルを開いて、アプリと Macrobenchmark モジュールの両方のベンチマーク バリアントを選択します。これにより、ベンチマークを実行すると、確実にアプリの正しいバリアントをビルドしてテストできるようになります。

ベンチマーク バリアントを選択する

マルチモジュール アプリを設定する

アプリに複数の Gradle モジュールがある場合は、コンパイルするビルド バリアントをビルド スクリプトが認識できるようにする必要があります。そうしないと、新しく追加された benchmark buildType が原因でビルドが失敗し、次のエラー メッセージが表示されます。

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

この問題を解決するには、:macrobenchmark モジュールと :app モジュールの benchmark buildType に matchingFallbacks プロパティを追加します。残りの Gradle モジュールについては、以前と同じ構成で問題ありません。

Groovy

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
}

Kotlin

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

    matchingFallbacks += listOf('release')
}

プロジェクト内のビルド バリアントを選択する際は、:app:macrobenchmark の各モジュールには benchmark を、アプリ内の他のモジュールには release を選択します。次の画像をご覧ください。

release と benchmark の buildTypes が選択されたマルチモジュール プロジェクトのベンチマーク バリアント

詳細については、バリアント識別による依存関係の管理をご覧ください。

Macrobenchmark クラスを作成する

ベンチマーク テストは、Macrobenchmark ライブラリの MacrobenchmarkRule JUnit4 Rule 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 = 5,
        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 Studio 内からテストを実行して、デバイス上のアプリのパフォーマンスを測定します。次の画像に示すように、テストクラスまたはテストメソッドの横にあるガター アクションを使用して、他の @Test を実行する場合と同じようにベンチマークを実行できます。

テストクラスの横にあるガター アクションを使用してマクロ ベンチマークを実行する

または、コマンドラインから connectedCheck コマンドを実行して、Gradle モジュール内のすべてのベンチマークを実行することもできます。

./gradlew :macrobenchmark:connectedCheck

単一のテストを実行するには、次のようにします。

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

継続的インテグレーションでベンチマークを実行およびモニタリングする方法については、CI でベンチマークを実行するをご覧ください。

ベンチマークの結果

ベンチマークの実行が成功すると、指標は Android Studio 内に直接表示されます。また、JSON ファイルの CI 使用状況にも出力されます。測定される反復処理は、それぞれが個別のシステム トレースをキャプチャします。結果トレースを開くには、次の画像に示すように、[Test Results] ペインにあるいずれかのリンクをクリックします。

Macrobenchmark の起動結果

トレースが読み込まれると、Android Studio によって、分析するプロセスの選択を求められます。選択するターゲット アプリのプロセスは事前入力されます。

Studio トレース プロセスの選択

トレース ファイルが読み込まれると、Studio は CPU Profiler ツールで結果を表示します。

Studio トレース

手動でトレース ファイルにアクセスする

以前のバージョン(Arctic Fox 2020.3.1 より前)の Android Studio を使用している場合、または Perfetto ツールを使用してトレース ファイルを分析する場合は、追加の手順が必要です。Perfetto では、トレース中にデバイスで実行されているすべてのプロセスを検査できます。これに対して、Android Studio の CPU Profiler では、検査は単一のプロセスに限定されます。

Android Studio から、または Gradle コマンドラインからテストを呼び出した場合、トレース ファイルはデバイスからホストに自動的にコピーされます。レポートは、ホストマシンの次の場所に書き込まれます。

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

ホストシステムにトレース ファイルが作成されたら、Android Studio の [File] > [Open] メニューからトレース ファイルを開くことができます。前のセクションで示したプロファイラ ツールのビューが表示されます。

構成エラー

アプリが誤って(デバッグ可能またはプロファイル不可に)構成されている場合、Macrobenchmark は不正確または不完全な測定をレポートするのではなく、エラーをスローします。androidx.benchmark.suppressErrors 引数を使用すると、このようなエラーの出力を抑制できます。

エミュレータまたは電池容量の少ないデバイスで測定しようとした場合も、コアの可用性とクロック速度が損なわれる可能性があるため、エラーがスローされます。

ベンチマークをカスタマイズする

measureRepeated 関数は、ライブラリが収集する指標、アプリの起動とコンパイルの方法、ベンチマークの実行対象となる反復処理の数に影響を及ぼすさまざまなパラメータを受け取ります。

指標をキャプチャする

指標は、ベンチマークから抽出される主要な情報タイプです。指定できるオプションは、StartupTimingMetricFrameTimingMetricTraceSectionMetric です。これらのオプションについて詳しくは、指標のキャプチャに関するページをご覧ください。

カスタム イベントを使用してトレースデータを改善する

場合によっては、カスタム トレース イベントを使用したアプリのインストルメント化が有用です。カスタム トレース イベントは他のトレース レポートに表示され、アプリ固有の問題を特定するために役立ちます。カスタム トレース イベントの作成方法については、カスタム イベントを定義するガイドをご覧ください。

CompilationMode

マクロ ベンチマークでは、CompilationMode を指定し、アプリを DEX バイトコード(APK 内のバイトコード形式)からマシンコード(プリコンパイル後の C++ のようなコード)にプリコンパイルする量を定義できます。

デフォルトでは、マクロ ベンチマークは CompilationMode.DEFAULT で実行されます。この場合、Android 7(API レベル 24)以降ではベースライン プロファイル(利用可能な場合)がインストールされます。Android 6(API レベル 23)以前では、このコンパイル モードの場合、デフォルトのシステム動作として APK はフルコンパイルされます。

ターゲット アプリにベースライン プロファイルと ProfileInstaller ライブラリの両方が含まれている場合は、ベースライン プロファイルをインストールできます。

Android 7 以降では、CompilationMode をカスタマイズすることにより、デバイス上のプリコンパイルの量を調整して、さまざまなレベルの事前(AOT)コンパイルまたは JIT キャッシュ処理を模倣できます。CompilationMode.FullCompilationMode.PartialCompilationMode.None をご覧ください。

この機能は、ART コンパイル コマンドをベースにして構築されています。ベンチマーク間の干渉が起こらないようにするため、各ベンチマークは開始前にプロファイル データを消去します。

StartupMode

アクティビティの起動を実行するには、事前定義された起動モード(COLDWARMHOTのいずれか)を渡します。このパラメータにより、テスト開始時のアクティビティの起動方法とプロセスの状態が変更されます。

起動の種類について詳しくは、Android Vitals の起動に関するドキュメントをご覧ください。

サンプル

サンプル プロジェクトは、GitHub の android/performance-samples リポジトリの一部として入手できます。

フィードバックを送信する

Jetpack Macrobenchmark に関する問題の報告または機能リクエストの送信については、公開されている Issue Tracker をご利用ください。