Bei größeren Projekten oder Projekten, die viel benutzerdefinierte Build-Logik implementieren, müssen Sie sich möglicherweise genauer mit dem Build-Prozess befassen, um Engpässe zu finden.
Dazu können Sie ein Profil erstellen, wie lange Gradle für die Ausführung der einzelnen Phasen des Build-Lebenszyklus und der einzelnen Build-Aufgaben benötigt. Wenn Ihr Build-Profil beispielsweise zeigt, dass Gradle zu viel Zeit für die Konfiguration Ihres Projekts benötigt, kann es sein, dass Sie benutzerdefinierte Build-Logik aus der Konfigurationsphase verschieben müssen.
Wenn die Aufgabe mergeDevDebugResources einen großen Teil der Build-Zeit in Anspruch nimmt, kann dies darauf hindeuten, dass Sie entweder Ihre Bilder in WebP konvertieren oder PNG-Crunching deaktivieren müssen.
Wenn Sie Android Studio 4.0 oder höher verwenden, können Sie Probleme mit der Build-Leistung am besten mit dem Build Analyzer untersuchen.
Außerdem gibt es zwei Optionen, um ein Profil für Ihren Build außerhalb von Android Studio zu erstellen:
Das eigenständige
gradle-profiler-Tool, ein robustes Tool für die detaillierte Analyse Ihres Builds.Die Gradle-Option
--profile, ein praktisches Tool, das über die Gradle-Befehlszeile verfügbar ist.
Eigenständiges gradle-profiler-Tool verwenden
Um die Projekteinrichtung zu finden, die die beste Build-Geschwindigkeit bietet, sollten Sie den Gradle-Profiler verwenden, ein Tool zum Erfassen von Profiling- und Benchmarking-Informationen für Gradle-Builds. Mit dem Gradle-Profiler können Sie Build-Szenarien erstellen und mehrmals ausführen. So werden große Abweichungen zwischen den Ergebnissen vermieden und die Ergebnisse sind reproduzierbar.
Der Benchmarking-Modus sollte verwendet werden, um Informationen zu sauberen und inkrementellen Builds zu erfassen. Der Profiling-Modus kann verwendet werden, um detailliertere Informationen zu den Ausführungen zu erfassen, einschließlich CPU-Snapshots.
Zu den Projektkonfigurationen für das Benchmarking gehören:
- Plug-in-Versionen
- Gradle-Versionen
- JVM-Einstellungen (Heap-Größe, PermGen-Größe, automatische Speicherbereinigung usw.)
- Anzahl der Gradle-Worker (
org.gradle.workers.max) - Plug-in-spezifische Optionen zur weiteren Leistungsoptimierung
Erste Schritte
- Installieren Sie gradle-profiler gemäß dieser Anleitung.
- Ausführen:
gradle-profiler --benchmark --project-dir <root-project> :app:assembleDebug
Dadurch wird ein vollständig aktueller Build getestet, da --benchmark die Aufgabe mehrmals ausführt, ohne das Projekt zwischendurch zu ändern. Anschließend wird im Verzeichnis profile-out/ ein HTML-Bericht mit den Build-Zeiten generiert.
Es gibt andere Szenarien, die für Benchmarks nützlicher sein können:
- Codeänderungen im Methodentext einer Klasse, in der Sie den Großteil Ihrer Arbeit erledigen.
- API-Änderungen in einem Modul, das im gesamten Projekt verwendet wird. Diese Änderungen sind zwar seltener als Änderungen an Ihrem eigenen Code, haben aber größere Auswirkungen und es ist sinnvoll, sie zu messen.
- Layoutänderungen, um die Iteration an der Benutzeroberfläche zu simulieren.
- Stringbearbeitungen, um die Arbeit mit Übersetzungen zu simulieren.
- Bereinigen Sie Builds, um Änderungen am Build selbst zu simulieren (z.B. Aktualisierung des Android-Gradle-Plug-ins, Gradle-Update oder Änderungen am eigenen Build-Code unter
buildSrc).
Um diese Anwendungsfälle zu vergleichen, können Sie ein Szenario erstellen, das für die Ausführung von gradle-profiler verwendet wird und entsprechende Änderungen an Ihren Quellen vornimmt. In den folgenden Abschnitten werden einige gängige Szenarien beschrieben.
Profilerstellung für verschiedene Arbeitsspeicher-/CPU-Einstellungen
Wenn Sie verschiedene Speicher- und CPU-Einstellungen vergleichen möchten, können Sie mehrere Szenarien mit unterschiedlichen Werten für org.gradle.jvmargs erstellen. Sie können beispielsweise Szenarien erstellen:
# <root-project>/scenarios.txt
clean_build_2gb_4workers {
tasks = [":app:assembleDebug"]
gradle-args = ["--max-workers=4"]
jvm-args = ["-Xmx2048m"]
cleanup-tasks = ["clean"]
}
clean_build_parallelGC {
tasks = [":app:assembleDebug"]
jvm-args = ["-XX:+UseParallelGC"]
cleanup-tasks = ["clean"]
}
clean_build_G1GC_4gb {
tasks = [":app:assembleDebug"]
jvm-args = ["-Xmx4096m", "-XX:+UseG1GC"]
cleanup-tasks = ["clean"]
}
Wenn Sie gradle-profiler --benchmark --project-dir
<root-project> --scenario-file scenarios.txt ausführen, werden drei Szenarien ausgeführt. Sie können dann vergleichen, wie lange :app:assembleDebug für jede dieser Konfigurationen dauert.
Profiling verschiedener Gradle-Plug-in-Versionen
Wenn Sie herausfinden möchten, wie sich die Änderung der Version des Gradle-Plug-ins auf die Build-Zeiten auswirkt, erstellen Sie ein Szenario für das Benchmarking. Dazu ist eine gewisse Vorbereitung erforderlich, damit die Plug-in-Version aus dem Szenario eingefügt werden kann. Ändern Sie die Datei „build.gradle“ im Stammverzeichnis:
# <root-project>/build.gradle
buildscript {
def agpVersion = providers.systemProperty("agpVersion").forUseAtConfigurationTime().orNull ?: '4.1.0'
ext.kotlin = providers.systemProperty('kotlinVersion').forUseAtConfigurationTime().orNull ?: '1.4.0'
dependencies {
classpath "com.android.tools.build:gradle:$agpVersion"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin"
}
}
Sie können jetzt die Versionen des Android Gradle-Plug-ins und des Kotlin Gradle-Plug-ins in der Szenariodatei angeben und das Szenario eine neue Methode zu den Quelldateien hinzufügen lassen:
# <root-project>/scenarios.txt
non_abi_change_agp4.1.0_kotlin1.4.10 {
tasks = [":app:assembleDebug"]
apply-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
System-properties {
"agpVersion" = "4.1.0"
"kotlinVersion" = "1.4.10"
}
non_abi_change_agp4.2.0_kotlin1.4.20 {
tasks = [":app:assembleDebug"]
apply-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
System-properties {
"agpVersion" = "4.2.0-alpha16"
"kotlinVersion" = "1.4.20"
}
Profil für einen inkrementellen Build erstellen
Die meisten Builds sind inkrementell. Daher ist dies eines der wichtigsten Szenarien für die Profilerstellung. Der Gradle-Profiler bietet umfassende Unterstützung für die Profilerstellung für inkrementelle Builds. Sie kann Änderungen an einer Quelldatei automatisch anwenden, indem sie einen Methodentext ändert, eine neue Methode hinzufügt oder ein Layout oder eine String-Ressource ändert. Sie können beispielsweise inkrementelle Szenarien wie die folgenden erstellen:
# <root-project>/scenarios.txt
non_abi_change {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to = ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
}
abi_change {
tasks = [":app:assembleDebug"]
apply-abi-change-to = ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
}
layout_change {
tasks = [":app:assembleDebug"]
apply-android-layout-change-to = "app/src/main/res/your_layout_file.xml"
}
string_resource_change {
tasks = [":app:assembleDebug"]
apply-android-resource-value-change-to = "app/src/main/res/values/strings.xml"
}
Wenn Sie gradle-profiler --benchmark --project-dir <root-project>
--scenario-file scenarios.txt ausführen, wird der HTML-Bericht mit den Benchmarking-Daten generiert.
Sie können inkrementelle Szenarien mit anderen Einstellungen kombinieren, z. B. Heap-Größe, Anzahl der Worker oder Gradle-Version:
# <root-project>/scenarios.txt
non_abi_change_4g {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
jvm-args = ["-Xmx4096m"]
}
non_abi_change_4g_8workers {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
jvm-args = ["-Xmx4096m"]
gradle-args = ["--max-workers=8"]
}
non_abi_change_3g_gradle67 {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
jvm-args = ["-Xmx3072m"]
version = ["6.7"]
}
Profil für einen sauberen Build erstellen
Wenn Sie einen sauberen Build vergleichen möchten, können Sie ein Szenario erstellen, das für die Ausführung des Gradle-Profilers verwendet wird:
# <root-project>/scenarios.txt
clean_build {
tasks = [":app:assembleDebug"]
cleanup-tasks = ["clean"]
}
Führen Sie das Szenario mit dem folgenden Befehl aus:
gradle-profiler --benchmark --project-dir <root-project> --scenario-file scenarios.txt
Gradle-Option --profile verwenden
So generieren Sie ein Build-Profil über die Gradle-Befehlszeile und rufen es auf:
Öffnen Sie ein Befehlszeilenterminal im Stammverzeichnis Ihres Projekts.
Führen Sie mit dem folgenden Befehl einen Clean Build aus. Wenn Sie ein Profil für Ihren Build erstellen, sollten Sie zwischen den einzelnen Builds, für die Sie ein Profil erstellen, einen Clean Build ausführen, da Gradle Aufgaben überspringt, wenn sich die Eingaben für eine Aufgabe (z. B. Quellcode) nicht ändern. Daher wird ein zweiter Build ohne Eingabeänderungen immer schneller ausgeführt, da Aufgaben nicht noch einmal ausgeführt werden. Wenn Sie die Aufgabe
cleanzwischen Ihren Builds ausführen, wird der gesamte Build-Prozess profiliert.// On Mac or Linux, run the Gradle wrapper using "./gradlew". gradlew cleanFühren Sie einen Debug-Build einer Ihrer Produktvarianten, z. B. der „dev“-Variante, mit den folgenden Flags aus:
gradlew --profile --offline --rerun-tasks assemble<var>Flavor</var>Debug--profile: Aktiviert die Profilerstellung.--offline: Verhindert, dass Gradle Online-Abhängigkeiten abruft. So wird sichergestellt, dass Verzögerungen, die durch den Versuch von Gradle, Ihre Abhängigkeiten zu aktualisieren, verursacht werden, Ihre Profilerstellungsdaten nicht beeinträchtigen. Sie sollten Ihr Projekt bereits einmal erstellt haben, damit Gradle Ihre Abhängigkeiten bereits heruntergeladen und im Cache gespeichert hat.--rerun-tasks: Erzwingt, dass Gradle alle Aufgaben noch einmal ausführt und alle Aufgabenoptimierungen ignoriert.
Nachdem der Build abgeschlossen ist, rufen Sie im Fenster Projekt das Verzeichnis
project-root/build/reports/profile/auf (siehe Abbildung 1).
Abbildung 1. Projektansicht, die den Speicherort von Profilberichten angibt.
Klicken Sie mit der rechten Maustaste auf die Datei
profile-timestamp.htmlund wählen Sie Im Browser öffnen > Standard aus. Der Bericht sollte in etwa so aussehen wie in Abbildung 2. Sie können jeden Tab im Bericht prüfen, um mehr über Ihren Build zu erfahren. Auf dem Tab Task Execution (Aufgabenausführung) sehen Sie beispielsweise, wie lange Gradle für die Ausführung der einzelnen Build-Aufgaben benötigt hat.
Abbildung 2: Bericht in einem Browser ansehen
Optional: Bevor Sie Änderungen an Ihrem Projekt oder Ihrer Build-Konfiguration vornehmen, wiederholen Sie den Befehl in Schritt 3, lassen Sie aber das Flag
--rerun-tasksweg. Da Gradle versucht, Zeit zu sparen, indem es Aufgaben, deren Eingaben sich nicht geändert haben, nicht noch einmal ausführt (diese werden im Bericht auf dem Tab Task Execution alsUP-TO-DATEangezeigt, wie in Abbildung 3 dargestellt), können Sie feststellen, welche Aufgaben ausgeführt werden, obwohl sie es nicht sollten. Wenn die:app:processDevUniversalDebugManifestbeispielsweise nicht alsUP-TO-DATEgekennzeichnet ist, kann dies darauf hindeuten, dass Ihre Build-Konfiguration das Manifest bei jedem Build dynamisch aktualisiert. Einige Aufgaben müssen jedoch bei jedem Build ausgeführt werden, z. B.:app:checkDevDebugManifest.
Abbildung 3: Ergebnisse der Taskausführung ansehen
Nachdem Sie einen Build-Profilbericht erstellt haben, können Sie nach Optimierungsmöglichkeiten suchen, indem Sie die Informationen auf den einzelnen Tabs des Berichts prüfen. Einige Build-Einstellungen erfordern Tests, da die Vorteile je nach Projekt und Workstation variieren können. Bei Projekten mit einer großen Codebasis kann beispielsweise die Codekomprimierung hilfreich sein, um nicht verwendeten Code zu entfernen und die App-Größe zu reduzieren.
Bei kleineren Projekten kann es jedoch vorteilhafter sein, die Codekomprimierung vollständig zu deaktivieren. Außerdem kann sich die Erhöhung der Gradle-Heap-Größe (mit org.gradle.jvmargs) negativ auf die Leistung von Computern mit wenig Arbeitsspeicher auswirken.
Nachdem Sie eine Änderung an Ihrer Build-Konfiguration vorgenommen haben, können Sie die Ergebnisse Ihrer Änderungen sehen, indem Sie die vorherigen Schritte wiederholen und ein neues Build-Profil generieren. Abbildung 4 zeigt beispielsweise einen Bericht für dieselbe Beispiel-App, nachdem einige der auf dieser Seite beschriebenen grundlegenden Optimierungen angewendet wurden.
Abbildung 4: Neuen Bericht nach der Optimierung der Build-Geschwindigkeit ansehen.