MacroBenchmark schreiben

Verwenden Sie die MacroBenchmark-Bibliothek, um größere Anwendungsfälle Ihrer App zu testen. Dazu gehören das Starten der App und komplexe UI-Änderungen wie das Scrollen eines RecyclerView oder das Ausführen von Animationen. Wenn Sie kleinere Bereiche Ihres Codes testen möchten, finden Sie entsprechende Informationen unter MicroBenchmark-Bibliothek. Auf dieser Seite wird beschrieben, wie Sie die MacroBenchmark-Bibliothek einrichten.

Die Bibliothek gibt Benchmarking-Ergebnisse sowohl an die Android Studio-Konsole als auch in eine JSON-Datei mit weiteren Details aus. Außerdem finden Sie dort Trace-Dateien, 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.

Sie können MacroBenchmark zum Generieren von Basisprofilen verwenden. Richten Sie zuerst die MacroBenchmark-Bibliothek ein, dann können Sie ein Baseline-Profil erstellen.

Projekteinrichtung

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

MacroBenchmark-Modul einrichten

Makro-Benchmarks erfordern ein vom Anwendungscode getrenntes com.android.test-Modul, mit dem die Tests ausgeführt werden, mit denen die Anwendung gemessen wird.

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

Gehen Sie wie folgt vor, um die Modulvorlage zum Erstellen eines neuen Moduls zu verwenden:

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

  2. Wählen Sie im Bereich Templates (Vorlagen) die Option Benchmark aus. Sie können die Zielanwendung, also die Anwendung, die für das Benchmarking verwendet werden soll, sowie den Paket- und Modulnamen für das neue MacroBenchmark-Modul anpassen.

  3. Klicken Sie auf Fertig.

Benchmark-Modulvorlage

Abbildung 1: Benchmarkmodulvorlage.

App einrichten

Zum Benchmarking einer Anwendung, die als Ziel des MacroBenchmarks bezeichnet wird, muss sie profileable sein. So können detaillierte Trace-Informationen gelesen werden, ohne die Leistung zu beeinträchtigen. Der Modulassistent fügt der Datei AndroidManifest.xml der App automatisch das Tag <profileable> hinzu.

Die Ziel-App muss ProfilerInstaller 1.3 oder höher enthalten. Dies ist erforderlich, damit die MacroBenchmark-Bibliothek das Erfassen und Zurücksetzen von Profilen sowie das Leeren des Shader-Caches aktivieren kann.

Konfigurieren Sie die Benchmark-App so nah wie möglich an der Release-Version oder Produktion. Richten Sie es als nicht Debug-fähig und möglichst mit aktivierter Reduzierung ein, um die Leistung zu verbessern. Dazu erstellen Sie in der Regel eine Kopie der Release-Variante. Diese hat dieselbe Leistung, ist aber lokal mit Debug-Schlüsseln 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")
    }
}

Cool

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 der Benchmark die richtige Variante Ihrer Anwendung erstellt und getestet wird (siehe Abbildung 2):

  1. Führen Sie eine Gradle-Synchronisierung durch.
  2. Öffnen Sie den Bereich Build-Varianten.
  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 Ihre App mehr als ein Gradle-Modul hat, müssen Ihre Build-Skripts wissen, welche Build-Variante kompiliert werden soll. Fügen Sie dem Build-Typ benchmark der Module :macrobenchmark und :app das Attribut matchingFallbacks hinzu. Die übrigen Gradle-Module können dieselbe Konfiguration wie zuvor haben.

Kotlin

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

    matchingFallbacks += listOf("release")
 }

Cool

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
 }

Andernfalls schlägt der neu hinzugefügte Build-Typ benchmark fehl 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 (siehe Abbildung 3):

Benchmarkvarianten für Projekte mit mehreren Modulen mit ausgewählten Release- und Benchmark-Build-Typen

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

Weitere Informationen finden Sie unter Variantensensitive Abhängigkeitsverwaltung verwenden.

(Optional) Produkt-Geschmacksrichtungen einrichten

Wenn Sie in Ihrer Anwendung mehrere Produkt-Varianten festgelegt haben, konfigurieren Sie das Modul :macrobenchmark so, dass es weiß, welche Produkt-Geschmacksrichtung Ihrer Anwendung Sie erstellen und vergleichen möchten.

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

Kotlin

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

Cool

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

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

Ohne diese Konfiguration erhalten Sie möglicherweise einen Build-Fehler wie bei mehreren Gradle-Modulen:

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, falls sie im Modul nicht aufgeführt sind. Im folgenden Beispiel wird der Flavor production als Standarddimension verwendet:

Kotlin

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

Cool

defaultConfig {
    missingDimensionStrategy "environment", "production"
}

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

Definieren Sie Produktsorten im :macroBenchmark-Modul

Wenn Sie andere Produktvarianten entwickeln und vergleichen möchten, definieren Sie diese im Modul :macrobenchmark. Geben Sie die ID auf ähnliche Weise wie im Modul :app an, weisen Sie aber nur productFlavors einem dimension zu. Es sind keine weiteren Einstellungen erforderlich:

Kotlin

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

Cool

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

Benchmark-Varianten für ein Projekt mit Produkt-Sorten, in der die
Produktions-Benchmark und der Release ausgewählt sind

Abbildung 4: Benchmarkvarianten für das Projekt mit Produkt-Geschmacksrichtungen, wobei „productionBenchmark“ und „release“ ausgewählt sind.

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

MakroBenchmark-Klasse erstellen

Benchmarktests werden über die API für MacrobenchmarkRule JUnit4-Regeln in der MacroBenchmark-Bibliothek bereitgestellt. Sie enthält die Methode measureRepeated, 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 zu messende metrics und die Anzahl der iterations angeben, die die Benchmark ausführen muss.

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ühre den Test in Android Studio aus, um die Leistung deiner App auf deinem Gerät zu messen. Sie können die Benchmarks genauso wie andere @Test ausführen, indem Sie die gutter-Aktion neben Ihrer Testklasse oder -methode verwenden, wie in Abbildung 5 gezeigt.

Führe Makro-Benchmark mit Gutteraktion neben der Testklasse aus.

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, indem Sie den Befehl connectedCheck ausführen:

./gradlew :macrobenchmark:connectedCheck

Mit dem folgenden Befehl können Sie einen einzelnen Test 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 erfolgreicher Benchmarkausführung werden Messwerte direkt in Android Studio angezeigt und für die CI-Nutzung in einer JSON-Datei ausgegeben. Jede gemessene Iteration erfasst einen separaten System-Trace. Sie können diese Trace-Ergebnisse öffnen, indem Sie auf die Links im Bereich Testergebnisse klicken, wie in Abbildung 6 dargestellt:

MacroBenchmark-Startergebnisse

Abbildung 6: Startergebnisse für MacroBenchmark

Wenn der Trace geladen ist, werden Sie von Android Studio aufgefordert, den zu analysierenden Prozess auszuwählen. Die Auswahl enthält vorab den Zielanwendungsprozess, wie in Abbildung 7 gezeigt:

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. Diese 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 eine Trace-Datei mit dem Perfetto-Tool analysieren möchten, sind zusätzliche Schritte erforderlich. Mit Perfetto können Sie alle Prozesse überprüfen, die während des Trace auf dem Gerät stattfinden, während der CPU-Profiler von Android Studio die Prüfung auf einen einzelnen Prozess beschränkt.

Wenn Sie die Tests über Android Studio oder über die Gradle-Befehlszeile aufrufen, werden die Trace-Dateien automatisch vom Gerät auf den Host kopiert. Diese werden auf dem 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 Datei > Öffnen im Menü öffnen. Dies zeigt die Profiler-Tool-Ansicht aus dem vorherigen Abschnitt.

Konfigurationsfehler

Wenn die Anwendung falsch konfiguriert ist – Debug-fä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.

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

Benchmarks anpassen

Die measureRepeated-Funktion akzeptiert verschiedene Parameter, die beeinflussen, welche Messwerte die Bibliothek erfasst, wie Ihre App gestartet und kompiliert wird oder wie viele Iterationen der 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 MakroBenchmark-Messwerte erfassen.

Trace-Daten mit benutzerdefinierten Ereignissen verbessern

Es kann nützlich sein, die Anwendung mit benutzerdefinierten Trace-Ereignissen zu instrumentieren, die zusammen mit dem Rest des Trace-Berichts angezeigt werden und auf Probleme hinweisen, die für Ihre Anwendung spezifisch sind. Weitere Informationen zum Erstellen benutzerdefinierter Trace-Ereignisse finden Sie unter Benutzerdefinierte Ereignisse definieren.

CompilationMode (Kompilierungsmodus)

In Makro-Benchmarks kann ein CompilationMode angegeben werden, der definiert, wie viel von der Anwendung aus dem DEX-Bytecode (dem Bytecode-Format innerhalb eines APKs) in Maschinencode vorkompiliert werden muss (ähnlich wie bei vorkompilierter C++-Version).

Standardmäßig werden Makro-Benchmarks mit CompilationMode.DEFAULT ausgeführt, wodurch ein Baseline-Profil (falls verfügbar) unter Android 7 (API-Level 24) und höher installiert wird. Wenn du Android 6 (API-Level 23) oder niedriger verwendest, wird das APK im Kompilierungsmodus vollständig als Standardsystemverhalten kompiliert.

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

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

Diese Funktion basiert auf ART-Kompilierungsbefehlen. Jede Benchmark löscht Profildaten vor dem Start, um Störungen zwischen den Benchmarks zu vermeiden.

Startmodus

Wenn Sie eine Aktivität starten möchten, können Sie einen vordefinierten Startmodus übergeben: COLD, WARM oder HOT. Mit diesem Parameter werden der Start der Aktivität und der Prozessstatus zu Beginn des Tests geändert.

Weitere Informationen zu den Arten des Starts finden Sie unter App-Startzeit.

Produktproben

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

Feedback geben

Informationen zum Melden von Problemen oder von Funktionsanfragen für Jetpack MacroBenchmark finden Sie in der öffentlichen Problemverfolgung.