Macrobenchmark を作成する

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

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

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

ベースライン プロファイルは、Macrobenchmark を使用して生成できます。以下のガイドに沿って Marcobenchmark ライブラリを設定してから、ベースライン プロファイルを作成してください。

プロジェクトの設定

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

Macrobenchmark モジュールを設定する

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

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

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

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

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

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

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

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

アプリを設定する

アプリ(マクロ ベンチマークの「ターゲット」)のベンチマークを行うには、そのアプリを profileable にして、パフォーマンスに影響を与えずに詳細なトレース情報を読み取れるようにする必要があります。モジュール ウィザードを使用すると、アプリの AndroidManifest.xml ファイルに <profileable> タグが自動的に追加されます。

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

Groovy

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

    create("benchmark") {
        initWith(release)
        signingConfig = signingConfigs.getByName("debug")
        proguardFiles("benchmark-rules.pro")
    }
}

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 モジュールを構成して、ビルドとベンチマークを行うアプリのプロダクト フレーバーをモジュールが認識できるようにする必要があります。この構成を行わないと、複数の 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:
           ...

このガイドでは、次のスニペットに示すように、:app モジュールで 2 つのプロダクト フレーバー(demoproduction)を使用します。

Groovy

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

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

Kotlin

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

複数のプロダクト フレーバーでベンチマークを構成するには、以下の 2 つの方法があります。

missingDimensionStrategy を使用する

:macrobenchmark モジュールの defaultConfigmissingDimensionStrategy を指定すると、ビルドシステムに対してフレーバー ディメンションにフォールバックするよう指示できます。モジュールにディメンションが見つからない場合は、使用するディメンションを指定する必要があります。次の例では、デフォルトのディメンションとして production フレーバーを使用しています。

Groovy

defaultConfig {
    missingDimensionStrategy "environment", "production"
}

Kotlin

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

このように、:macrobenchmark モジュールは指定されたプロダクト フレーバーのビルドとベンチマークのみを行うことができます。これは、ベンチマーク対象の適切な構成を持つプロダクト フレーバーが 1 つのみであることがわかっている場合に便利です。

:macrobenchmark モジュールでプロダクト フレーバーを定義する

他のプロダクト フレーバーをビルドしてベンチマークを行う場合は、:macrobenchmark モジュールでそれらを定義する必要があります。指定方法は :app モジュールの場合と似ていますが、productFlavorsdimension に割り当てるだけです。他の設定は必要ありません。

Groovy

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

    production {
        dimension 'environment'
    }
}

Kotlin

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

プロジェクトを定義して同期したら、[Build Variants] ペインから目的のビルド バリアントを選択します。

productionBenchmark と release が選択された、プロダクト フレーバーを含むプロジェクトのベンチマーク バリアント

詳しくは、バリアント マッチングに関連するビルドエラーを解決するをご覧ください。

Macrobenchmark クラスを作成する

ベンチマーク テストは、Macrobenchmark ライブラリの MacrobenchmarkRule JUnit4 Rule 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 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 トレース

JSON レポートとプロファイリング トレースも、デバイスからホストに自動的にコピーされます。レポートは、ホストマシンの次の場所に書き込まれます。

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

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

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 をご利用ください。