MacroBenchmark schreiben

Mit der Macrobenchmark-Bibliothek können Sie größere Anwendungsfälle Ihrer App testen, darunter das Starten der App und komplexe UI-Manipulationen wie das Scrollen einer RecyclerView oder das Ausführen von Animationen. Wenn Sie kleinere Bereiche Ihres Codes testen möchten, lesen Sie den Abschnitt zur Microbenchmark-Bibliothek. Auf dieser Seite wird beschrieben, wie Sie die Macrobenchmark-Bibliothek einrichten.

Die Bibliothek gibt Benchmarking-Ergebnisse sowohl in der Android Studio-Konsole als auch in einer JSON-Datei mit weiteren Details aus. Außerdem werden Trace-Dateien bereitgestellt, die Sie in Android Studio laden und analysieren können.

Verwenden Sie die Macrobenchmark-Bibliothek in einer Continuous Integration-Umgebung (CI), wie unter Benchmark in Continuous Integration beschrieben.

Mit Macrobenchmark können Sie Baseline-Profile erstellen. Richten Sie zuerst die Macrobenchmark-Bibliothek ein. Anschließend können Sie ein Baseline-Profil erstellen.

Projekt einrichten

Wir empfehlen, Macrobenchmark mit der neuesten Version von Android Studio zu verwenden, um die IDE-Funktionen nutzen zu können, die in Macrobenchmark integriert sind.

Macrobenchmark-Modul einrichten

Für Makrobenchmarks ist ein com.android.test-Modul erforderlich, das getrennt von Ihrem App-Code für die Ausführung der Tests zuständig ist, mit denen Ihre App gemessen wird.

In Android Studio ist eine Vorlage verfügbar, um die Einrichtung von Macrobenchmark-Modulen zu vereinfachen. Mit der Benchmarking-Modulvorlage wird automatisch ein Modul in Ihrem Projekt erstellt, mit dem die von einem App-Modul erstellte App gemessen werden kann. Es enthält auch einen Beispiel-Benchmark für den Start.

So erstellen Sie ein neues Modul mit der Modulvorlage:

  1. Klicken Sie in Android Studio im Bereich Project mit der rechten Maustaste auf Ihr Projekt oder Modul und wählen Sie New > Module aus.

  2. Wählen Sie im Bereich Vorlagen die Option Benchmark aus. Sie können die Ziel-App (die App, die getestet werden soll) sowie den Paket- und Modulnamen für das neue Macrobenchmark-Modul anpassen.

  3. Klicken Sie auf Fertig.

Benchmark-Modulvorlage

Abbildung 1: Benchmark-Modulvorlage.

App einrichten

Um eine App zu benchmarken – die Ziel-App des Macrobenchmarks – muss die App profileable sein. Dadurch können detaillierte Trace-Informationen gelesen werden, ohne die Leistung zu beeinträchtigen. Der Modul-Assistent fügt das Tag <profileable> automatisch in die AndroidManifest.xml-Datei der App ein.

Die Zielanwendung muss ProfilerInstaller 1.3 oder höher enthalten. Die Macrobenchmark-Bibliothek benötigt diese Version, um das Erfassen von Profilen, das Zurücksetzen und das Löschen des Shader-Cache zu ermöglichen.

Konfigurieren Sie die Benchmark-App so, dass sie der Release-Version oder der Produktionsversion so weit wie möglich entspricht. Richten Sie sie als nicht debugfähig ein und aktivieren Sie nach Möglichkeit die Minimierung, um die Leistung zu verbessern. In der Regel erstellen Sie dazu eine Kopie der Release-Variante, die dieselbe Leistung erbringt, aber lokal mit Debug-Schlüsseln signiert wird. Alternativ können Sie initWith verwenden, um Gradle anzuweisen, dies für Sie zu tun:

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")
    }
}

Damit beim Ausführen des Benchmarks sowohl die richtige Variante Ihrer App erstellt als auch getestet wird (siehe Abbildung 2), gehen Sie so vor:

  1. Führen Sie eine Gradle-Synchronisierung durch.
  2. Öffnen Sie den Bereich Build-Varianten.
  3. Wählen Sie die Benchmark-Variante sowohl der App als auch des Macrobenchmark-Moduls aus.

Benchmark-Variante auswählen

Abbildung 2: Wählen Sie die Benchmark-Variante aus.

(Optional) App mit mehreren Modulen einrichten

Wenn Ihre App mehrere Gradle-Module hat, müssen Sie in Ihren Build-Skripten angeben, welche Build-Variante kompiliert werden soll. Fügen Sie die Eigenschaft matchingFallbacks dem Build-Typ benchmark Ihrer Module :macrobenchmark und :app hinzu. Die restlichen Gradle-Module können dieselbe Konfiguration wie zuvor haben.

Kotlin

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

    matchingFallbacks += listOf("release")
 }

Groovy

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
 }

Andernfalls schlägt der Build aufgrund des neu hinzugefügten benchmark-Buildtyps fehl und es wird die folgende Fehlermeldung angezeigt:

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

Wählen Sie beim Auswählen der Build-Varianten in Ihrem Projekt benchmark für :app- und :macrobenchmark-Module und release für alle anderen Module in Ihrer App aus (siehe Abbildung 3):

Benchmark-Varianten für Multi-Modul-Projekt mit ausgewählten Build-Typen „Release“ und „Benchmark“

Abbildung 3: Benchmark-Varianten für ein Multi-Modul-Projekt mit ausgewählten Release- und Benchmark-Build-Typen.

Weitere Informationen finden Sie unter Variant-aware dependency management.

(Optional) Produktvarianten einrichten

Wenn Sie in Ihrer App mehrere Produktvarianten festgelegt haben, konfigurieren Sie das :macrobenchmark-Modul so, dass es weiß, welche Produktvariante Ihrer App erstellt und getestet werden soll.

In den Beispielen auf dieser Seite werden die beiden Produktvarianten im Modul :app verwendet: demo und production, wie im folgenden Snippet gezeigt:

Kotlin

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

Groovy

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

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

Ohne diese Konfiguration erhalten Sie möglicherweise einen Build-Fehler, der dem bei mehreren Gradle-Modulen ähnelt:

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:
           ...

In den beiden folgenden Abschnitten wird beschrieben, wie Sie Benchmarking mit mehreren Produktvarianten konfigurieren.

missingDimensionStrategy verwenden

Wenn Sie missingDimensionStrategy im defaultConfig des Moduls :macrobenchmark angeben, wird das Build-System angewiesen, auf die Flavor-Dimension zurückzugreifen. Geben Sie an, welche Dimensionen verwendet werden sollen, wenn Sie sie nicht im Modul finden. Im folgenden Beispiel wird die Variante production als Standarddimension verwendet:

Kotlin

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

Groovy

defaultConfig {
    missingDimensionStrategy "environment", "production"
}

So kann das :macrobenchmark-Modul nur den angegebenen Produkt-Flavor erstellen und testen. Das ist hilfreich, wenn Sie wissen, dass nur ein Produkt-Flavor die richtige Konfiguration für Benchmarks hat.

Produktvarianten im Modul „:macrobenchmark“ definieren

Wenn Sie andere Produktvarianten erstellen und testen möchten, definieren Sie sie im Modul :macrobenchmark. Geben Sie sie ähnlich wie im Modul :app an, weisen Sie productFlavors aber nur einer dimension zu. Es sind keine weiteren Einstellungen erforderlich:

Kotlin

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

Groovy

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

    production {
        dimension 'environment'
    }
}

Nachdem Sie das Projekt definiert und synchronisiert haben, wählen Sie die entsprechende Build-Variante im Bereich Build Variants aus (siehe Abbildung 4):

Benchmark-Varianten für Projekt mit Produktvarianten, in denen „productionBenchmark“ und „release“ ausgewählt sind

Abbildung 4: Benchmark-Varianten für das Projekt mit ausgewählten Produktvarianten „productionBenchmark“ und „release“.

Weitere Informationen finden Sie unter Build-Fehler im Zusammenhang mit dem Abgleich von Varianten beheben.

Makrobenchmark-Klasse erstellen

Benchmark-Tests werden über die MacrobenchmarkRule-JUnit4-Regel-API in der Macrobenchmark-Bibliothek bereitgestellt. Sie enthält eine measureRepeated-Methode, mit der Sie verschiedene Bedingungen für die Ausführung und das Benchmarking der Ziel-App festlegen können.

Sie müssen mindestens die packageName der Ziel-App, die zu messenden metrics und die Anzahl der iterations angeben, die für den Benchmark ausgeführt werden sollen.

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;
            }
        );
    }
}

Alle Optionen zum Anpassen von Benchmarks finden Sie im Abschnitt Benchmarks anpassen.

Benchmark ausführen

Führen Sie den Test in Android Studio aus, um die Leistung Ihrer App auf Ihrem Gerät zu messen. Sie können die Benchmarks auf dieselbe Weise ausführen wie jede andere @Test. Verwenden Sie dazu die Gutter-Aktion neben Ihrer Testklasse oder ‑methode, wie in Abbildung 5 dargestellt.

Makrobenchmark mit Gutter-Aktion neben der Testklasse ausführen

Abbildung 5: Führen Sie Macrobenchmark mit der Gutter-Aktion neben der Testklasse aus.

Sie können auch alle Benchmarks in einem Gradle-Modul über die Befehlszeile ausführen, indem Sie den Befehl connectedCheck ausführen:

./gradlew :macrobenchmark:connectedCheck

Sie können einen einzelnen Test ausführen, indem Sie Folgendes eingeben:

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

Informationen zum Ausführen und Überwachen von Benchmarks in der kontinuierlichen Integration finden Sie unter Benchmark in Continuous Integration.

Benchmark-Ergebnisse

Nach einem erfolgreichen Benchmarklauf werden Messwerte direkt in Android Studio angezeigt und für die CI-Nutzung in einer JSON-Datei ausgegeben. Bei jeder gemessenen Iteration wird ein separater System-Trace erfasst. Sie können diese Trace-Ergebnisse öffnen, indem Sie auf die Links im Bereich Testergebnisse klicken (siehe Abbildung 6):

Ergebnisse für den Macrobenchmark-Start

Abbildung 6 Ergebnisse für den Kaltstart von Makrobenchmarks.

Wenn der Trace geladen ist, werden Sie in Android Studio aufgefordert, den zu analysierenden Prozess auszuwählen. Die Auswahl ist bereits mit dem Ziel-App-Prozess ausgefüllt, wie in Abbildung 7 dargestellt:

Studio-Trace-Prozess auswählen

Abbildung 7. Auswahl des Studio-Trace-Prozesses.

Nachdem die Tracedatei geladen wurde, werden die Ergebnisse in Studio im CPU-Profiler-Tool angezeigt:

Studio
Trace

Abbildung 8. Studio-Trace.

JSON-Berichte und alle Profiling-Traces werden ebenfalls automatisch vom Gerät auf den Host kopiert. Sie werden auf dem Hostcomputer am folgenden Speicherort geschrieben:

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

Manuell auf Trace-Dateien zugreifen

Wenn Sie das Perfetto-Tool zum Analysieren einer Tracedatei verwenden möchten, sind zusätzliche Schritte erforderlich. Mit Perfetto können Sie alle Prozesse untersuchen, die während des Traces auf dem Gerät ausgeführt werden. Der CPU-Profiler von Android Studio beschränkt die Untersuchung auf einen einzelnen Prozess.

Wenn Sie die Tests über Android Studio oder über die Gradle-Befehlszeile aufrufen, werden die Tracedateien automatisch vom Gerät auf den Host kopiert. Sie werden auf dem Hostcomputer am folgenden Speicherort gespeichert:

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

Wenn Sie die Tracedatei auf Ihrem Hostsystem haben, können Sie sie in Android Studio über File > Open (Datei > Öffnen) im Menü öffnen. Dadurch wird die Profiler-Tool-Ansicht aus dem vorherigen Abschnitt angezeigt.

Konfigurationsfehler

Wenn die App falsch konfiguriert ist (debugfähig oder nicht profilierbar), gibt Macrobenchmark einen Fehler zurück, anstatt eine falsche oder unvollständige Messung zu melden. Sie können diese Fehler mit dem Argument androidx.benchmark.suppressErrors unterdrücken.

Bei dem Versuch, einen Emulator oder ein Gerät mit niedrigem Akkustand zu messen, gibt Macrobenchmark ebenfalls Fehler zurück, da dies die Verfügbarkeit von Kernen und die Taktfrequenz beeinträchtigen kann.

Benchmarks anpassen

Die Funktion measureRepeated akzeptiert verschiedene Parameter, die beeinflussen, welche Messwerte die Bibliothek erfasst, wie Ihre App gestartet und kompiliert wird und wie viele Iterationen der Benchmark durchläuft.

Messwerte erfassen

Messwerte sind die wichtigsten Informationen, die aus Ihren Benchmarks extrahiert werden. Folgende Messwerte sind verfügbar:

Weitere Informationen zu Messwerten finden Sie unter Makro-Benchmark-Messwerte erfassen.

Trace-Daten mit benutzerdefinierten Ereignissen verbessern

Es kann hilfreich sein, Ihre App mit benutzerdefinierten Trace-Ereignissen zu instrumentieren. Diese werden im restlichen Trace-Bericht angezeigt und können helfen, Probleme zu identifizieren, die speziell für Ihre App gelten. Weitere Informationen zum Erstellen benutzerdefinierter Trace-Ereignisse finden Sie unter Benutzerdefinierte Ereignisse definieren.

CompilationMode

In Makrobenchmarks kann ein CompilationMode angegeben werden, der definiert, wie viel der App aus DEX-Bytecode (dem Bytecode-Format in einem APK) in Maschinencode (ähnlich wie vorkompilierter C++) vorkompiliert werden muss.

Standardmäßig werden Macrobenchmarks mit CompilationMode.DEFAULT ausgeführt. Dadurch wird ein Baseline-Profil (falls verfügbar) auf Geräten mit Android 7 (API-Level 24) und höher installiert. Wenn Sie Android 6 (API-Level 23) oder früher verwenden, wird das APK standardmäßig im Kompilierungsmodus vollständig kompiliert.

Sie können ein Baseline-Profil installieren, wenn die Ziel-App sowohl ein Baseline-Profil als auch die ProfileInstaller-Bibliothek enthält.

Unter Android 7 und höher können Sie die CompilationMode anpassen, um die Menge der Vorabkompilierung auf dem Gerät zu beeinflussen und verschiedene Stufen der Ahead-of-Time-Kompilierung (AOT) oder des JIT-Caching zu simulieren. Weitere Informationen findest du unter CompilationMode.Full, CompilationMode.Partial, CompilationMode.None und CompilationMode.Ignore.

Diese Funktion basiert auf ART-Kompilierungsbefehlen. Bei jedem Benchmark werden die Profildaten vor dem Start gelöscht, um Störungen zwischen den Benchmarks zu vermeiden.

StartupMode

Um eine Aktivität zu starten, können Sie einen vordefinierten Startmodus übergeben: COLD, WARM oder HOT. Dieser Parameter ändert, wie die Aktivität gestartet wird und wie der Prozessstatus zu Beginn des Tests aussieht.

Weitere Informationen zu den Arten von Startvorgängen finden Sie unter App-Startzeit.

Produktproben

Ein Beispielprojekt ist im Macrobenchmark Sample des Repositorys auf GitHub verfügbar.

Feedback geben

Wenn Sie Probleme melden oder Funktionsanfragen für Jetpack Macrobenchmark einreichen möchten, verwenden Sie die öffentliche Problemverfolgung.