MacroBenchmark schreiben

Mit der MacroBenchmark-Bibliothek können Sie größere Anwendungsfälle für Ihre App testen, einschließlich App-Start und komplexe UI-Änderungen wie das Scrollen eines RecyclerView oder das Ausführen von Animationen. Wenn Sie kleinere Bereiche Ihres Codes testen möchten, lesen Sie die Mikro-Benchmark-Bibliothek. Auf dieser Seite wird beschrieben, wie Sie die MacroBenchmark-Bibliothek einrichten.

Die Bibliothek gibt Benchmarking-Ergebnisse sowohl an die Android Studio Console als auch an eine JSON-Datei mit mehr Details aus. Außerdem enthält es Trace-Dateien, die Sie in Android Studio laden und analysieren können.

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

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

Projekteinrichtung

Wir empfehlen, MacroBenchmark mit der neuesten Version von Android Studio für Funktionen der IDE zu verwenden, die sich in MacroBenchmark integrieren lassen.

MacroBenchmark-Modul einrichten

Für Makro-Benchmarks ist ein vom Anwendungscode getrenntes com.android.test-Modul erforderlich, das für die Ausführung der Tests verantwortlich ist, mit denen Ihre Anwendung gemessen wird.

In Android Studio ist eine Vorlage verfügbar, um die Einrichtung des MacroBenchmark-Moduls zu vereinfachen. Mit der Vorlage für das Benchmarking-Modul wird in Ihrem Projekt automatisch ein Modul zum Messen der von einem Anwendungsmodul erstellten Anwendung erstellt, einschließlich einer Beispiel-Start-Benchmark.

So erstellen Sie mithilfe der Modulvorlage ein neues Modul:

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

  2. Wählen Sie im Bereich Vorlagen die Option Benchmark aus. Sie können die Zielanwendung (d. h. die zu vergleichende Anwendung) sowie den Paket- und Modulnamen für das neue MacroBenchmark-Modul anpassen.

  3. Klicken Sie auf Fertig.

Vorlage für Benchmark-Modul

Abbildung 1: Vorlage für Benchmarkmodul.

App einrichten

Für das Benchmarking einer Anwendung (auch als Ziel der Macro-Benchmark bezeichnet) muss die Anwendung profileable sein. Dadurch können detaillierte Trace-Informationen gelesen werden, ohne die Leistung zu beeinträchtigen. Der Modulassistent fügt das <profileable>-Tag automatisch der AndroidManifest.xml-Datei der App hinzu.

Achten Sie darauf, dass die Zielanwendung ProfilerInstaller 1.3 oder höher enthält. Diese muss von der MacroBenchmark-Bibliothek zum Aktivieren der Profilerfassung und zum Zurücksetzen sowie zum Leeren des Shader-Caches verwendet werden.

Konfigurieren Sie die Benchmarking-App so nah wie möglich an der Release- oder Produktionsversion. Richten Sie es als nicht debugfähig und vorzugsweise mit aktivierter Reduzierung ein, um die Leistung zu verbessern. In der Regel erstellen Sie dazu eine Kopie der Releasevariante. Diese funktioniert genauso, ist aber lokal mit Schlüsseln zur Fehlerbehebung signiert. Alternativ können Sie Gradle mit initWith anweisen, 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")
    }
}

Groovig

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

So sorgen Sie dafür, dass beim Ausführen des Benchmarks sowohl Builds als auch die richtige Variante Ihrer Anwendung getestet wird (siehe Abbildung 2):

  1. Führen Sie eine Gradle-Synchronisierung durch.
  2. Öffnen Sie das Steuerfeld Varianten erstellen.
  3. Wählen Sie die Benchmark-Variante der App und des MacroBenchmark-Moduls aus.

Benchmark-Variante auswählen

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

Optional: App mit mehreren Modulen einrichten

Wenn deine App mehr als ein Gradle-Modul hat, achte darauf, dass deinen Build-Skripts bekannt ist, welche Build-Variante kompiliert werden soll. Füge dem Build-Typ benchmark der Module :macrobenchmark und :app das Attribut matchingFallbacks hinzu. Die übrigen Gradle-Module können die gleiche Konfiguration wie zuvor haben.

Kotlin

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

    matchingFallbacks += listOf("release")
}

Groovig

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
}

Andernfalls führt der neu hinzugefügte Build-Typ benchmark dazu, dass der Build fehlschlägt, und gibt die folgende Fehlermeldung aus:

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

Wählen Sie bei der Auswahl der Build-Varianten in Ihrem Projekt benchmark für die Module :app und :macrobenchmark sowie release für alle anderen Module in Ihrer App aus, wie in Abbildung 3 dargestellt:

Benchmarkvarianten für Projekt mit mehreren Modulen und ausgewählte Release- und Benchmark-Build-Typen

Abbildung 3: Benchmarkvarianten für Projekt mit mehreren Modulen mit ausgewählten Release- und Benchmark-Build-Typen

Weitere Informationen finden Sie unter Variantensensitives Abhängigkeitsmanagement verwenden.

Optional: Produktvarianten festlegen

Wenn Sie für Ihre App mehrere Produktvarianten festgelegt haben, konfigurieren Sie das Modul :macrobenchmark so, dass bekannt ist, 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"
        // ...
    }
}

Groovig

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

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

Ohne diese Konfiguration kann es zu einem Build-Fehler kommen, der ähnlich wie bei mehreren Gradle-Modulen ist:

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 erfahren Sie, wie Sie das Benchmarking mit mehreren Produktvarianten konfigurieren können.

missingDimensionStrategy verwenden

Wenn in den defaultConfig des :macrobenchmark-Moduls missingDimensionStrategy angegeben wird, erhält das Build-System ein Fallback auf die Flavor-Dimension. Geben Sie an, welche Dimensionen verwendet werden sollen, falls Sie sie im Modul nicht finden. Im folgenden Beispiel wird die Flavor production als Standarddimension verwendet:

Kotlin

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

Groovig

defaultConfig {
    missingDimensionStrategy "environment", "production"
}

Auf diese Weise kann das Modul :macrobenchmark nur die angegebene Produktvariante erstellen und Benchmarking durchführen. Dies ist hilfreich, wenn Sie wissen, dass nur eine Produktsorte die richtige Konfiguration für ein Benchmarking hat.

Produktvarianten im :macroBenchmark-Modul definieren

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

Kotlin

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

Groovig

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

    production {
        dimension 'environment'
    }
}

Nachdem Sie das Projekt definiert und synchronisiert haben, wählen Sie im Bereich Build-Varianten die entsprechende Build-Variante aus, wie in Abbildung 4 dargestellt:

Benchmarkvarianten für Projekt mit Produktvarianten, die „productionBenchmark und Releaseauswahl“ zeigen

Abbildung 4: Benchmarkvarianten für das Projekt mit ausgewählten Produktvarianten, bei denen „productionBenchmark“ und „Release“ ausgewählt sind.

Weitere Informationen finden Sie unter Build-Fehler im Zusammenhang mit dem Variantenabgleich beheben.

Makro-Benchmark-Klasse erstellen

Benchmarktests werden über die MacrobenchmarkRule JUnit4 Rule 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 Zielanwendung angeben können.

Sie müssen mindestens die packageName der Zielanwendung, die metrics, die Sie messen möchten, und die Anzahl der iterations, die die Benchmark ausführen muss, angeben.

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

Informationen zu allen Optionen zum Anpassen der Benchmark 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 Benchmarks auf dieselbe Weise ausführen wie andere @Test. Verwenden Sie dazu die Gutter-Aktion neben Ihrer Testklasse oder -methode (siehe Abbildung 5).

Makro-Benchmark mit Gutter-Aktion neben Testklasse ausführen

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

Sie können alle Benchmarks in einem Gradle-Modul auch über die Befehlszeile ausführen. Dazu führen Sie den Befehl connectedCheck aus:

./gradlew :macrobenchmark:connectedCheck

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

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

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

Benchmarkergebnisse

Nach einer erfolgreichen Benchmarkausführung werden die 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, wie in Abbildung 6 dargestellt:

MacroBenchmark-Start-ups

Abbildung 6: MacroBenchmark-Startergebnisse.

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

Auswahl des Studio-Trace-Prozesses

Abbildung 7: Auswahl des Studio-Trace-Prozesses.

Nachdem die Trace-Datei geladen wurde, zeigt Studio die Ergebnisse im CPU-Profiler-Tool an:

Studio
Trace

Abbildung 8: Studio-Trace

JSON-Berichte und alle Profilerstellungs-Traces werden ebenfalls automatisch vom Gerät auf den Host kopiert. Sie werden auf den 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 Tool Perfetto zum Analysieren einer Trace-Datei verwenden möchten, sind zusätzliche Schritte erforderlich. Mit Perfetto können Sie alle Prozesse auf dem Gerät überprüfen, die während des Trace stattfinden. Der CPU-Profiler von Android Studio beschränkt die Prüfung dagegen auf einen einzigen Prozess.

Wenn Sie die Tests über Android Studio oder die Gradle-Befehlszeile aufrufen, werden die Trace-Dateien automatisch vom Gerät zum Host kopiert. Sie sind auf den Hostcomputer an folgendem Speicherort geschrieben:

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

Wenn sich die Trace-Datei in Ihrem Hostsystem befindet, können Sie sie in Android Studio über das Menü Datei > Öffnen öffnen. Hier sehen Sie die Ansicht des Profiler-Tools aus dem vorherigen Abschnitt.

Konfigurationsfehler

Wenn die Anwendung falsch konfiguriert – debug-fähig oder nicht profilierbar – ist, gibt MacroBenchmark einen Fehler zurück und meldet keine falsche oder unvollständige Messung. Sie können diese Fehler mit dem Argument androidx.benchmark.suppressErrors unterdrücken.

MacroBenchmark gibt auch Fehler zurück, wenn Sie versuchen, einen Emulator oder ein Gerät mit niedrigem Batteriestand zu messen, was die Kernverfügbarkeit und Taktgeschwindigkeit beeinträchtigen kann.

Benchmarks anpassen

Die Funktion measureRepeated akzeptiert verschiedene Parameter, die sich darauf auswirken, welche Messwerte von der Bibliothek erfasst werden, wie Ihre Anwendung gestartet und kompiliert wird oder wie viele Iterationen die Benchmark ausgeführt wird.

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 nützlich sein, Ihre Anwendung mit benutzerdefinierten Trace-Ereignissen zu instrumentieren. Diese werden im restlichen Trace-Bericht verwendet und können dabei helfen, anwendungsspezifische Probleme aufzuzeigen. Weitere Informationen zum Erstellen benutzerdefinierter Trace-Ereignisse finden Sie unter Benutzerdefinierte Ereignisse definieren.

Kompilierungsmodus

Makro-Benchmarks können einen CompilationMode angeben, der definiert, wie viel der Anwendung aus DEX-Bytecode (dem Bytecode-Format innerhalb eines APK) in Maschinencode (ähnlich wie vorkompilierter C++) vorkompiliert werden muss.

Makro-Benchmarks werden standardmäßig mit CompilationMode.DEFAULT ausgeführt. Dadurch wird gegebenenfalls ein Referenzprofil unter Android 7 (API-Level 24) und höher installiert. Wenn Sie Android 6 (API-Level 23) oder niedriger verwenden, kompiliert der Kompilierungsmodus das APK als Standardsystemverhalten vollständig.

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

Unter Android 7 und höher können Sie die CompilationMode anpassen, um den Umfang der Vorkompilierung auf dem Gerät festzulegen, um verschiedene Ebenen der AOT-Kompilierung oder JIT-Caching zu imitieren. Weitere Informationen finden Sie unter CompilationMode.Full, CompilationMode.Partial, CompilationMode.None und CompilationMode.Ignore.

Diese Funktion basiert auf ART-Kompilierungsbefehlen. Für jede Benchmark werden Profildaten vor dem Start gelöscht, um sicherzustellen, dass die Benchmarks nicht gestört werden.

Startmodus

Zum Starten einer Aktivität können Sie einen vordefinierten Startmodus übergeben: COLD, WARM oder HOT. Dieser Parameter ändert den Start der Aktivität und den Prozessstatus zu Beginn des Tests.

Weitere Informationen zu den Starttypen finden Sie unter App-Startzeit.

Produktproben

Ein Beispielprojekt ist im MacroBenchmark-Beispiel des Repositorys auf GitHub verfügbar.

Feedback geben

Mithilfe der öffentlichen Problemverfolgung können Sie Probleme melden oder Funktionsanfragen für Jetpack MacroBenchmark senden.