Profila la tua build

I progetti più grandi o quelli che implementano molta logica di build personalizzata richiedono un'analisi più approfondita del processo di compilazione per individuare i colli di bottiglia. Puoi farlo profilando il tempo impiegato da Gradle per eseguire ogni fase il ciclo di vita e ogni attività di build. Ad esempio, se il tuo profilo build mostra che Gradle passa troppo tempo a configurare il progetto, suggerire che è necessario sposta la logica di build personalizzata dalla fase di configurazione. Inoltre, se l'attività mergeDevDebugResources utilizza una grande quantità del tempo di compilazione, potrebbe indicare che devi convertire le tue immagini in WebP o disabilita il crunching dei file PNG.

Se utilizzi Android Studio 4.0 o versioni successive: il modo migliore per esaminare il rendimento delle build problemi consiste nell'usare l'Analizzatore build.

Inoltre, sono disponibili due opzioni per la profilazione della build al di fuori Android Studio:

  1. Lo strumento gradle-profiler autonomo, uno per un'analisi approfondita della tua build.

  2. L'opzione Gradle --profile, un pratico strumento disponibile dalla riga di comando di Gradle.

Utilizzo dello strumento autonomo gradle-profiler

Per trovare la configurazione del progetto che fornisca la migliore velocità di compilazione, dovresti usare Gradle profiler, uno strumento per raccogliere informazioni di profilazione e benchmarking per le build Gradle. Profiler Gradle consente di creare scenari di build ed eseguirli volte, prevenendo un'elevata varianza tra i risultati e garantendo la riproducibilità dei risultati.

Modalità benchmarking dovrebbe essere usato per raccogliere informazioni su build pulite e incrementali, mentre la modalità di profilazione può essere utilizzato per raccogliere informazioni più granulari sulle esecuzioni, inclusa la CPU snapshot.

Alcune configurazioni di configurazione del progetto per il benchmarking includono:

  • Versioni plug-in
  • Versioni Gradle
  • Impostazioni JVM (dimensioni heap, dimensioni permanenti, garbage collection e così via)
  • Numero di worker Gradle (org.gradle.workers.max)
  • Opzioni per plug-in per ottimizzare ulteriormente il rendimento

Per iniziare

  • Installa gradle-profiler seguendo queste istruzioni
  • Corsa: gradle-profiler --benchmark --project-dir <root-project> :app:assembleDebug

Questo comando rappresenterà una build completamente aggiornata perché --benchmark esegue un'attività più volte senza cambiare progetto. Quindi genera un report HTML nella directory profile-out/ che mostra e i tempi di compilazione.

Esistono altri scenari che potrebbero essere più utili per l'analisi comparativa:

  • Modifiche al codice nel corpo di un metodo in una classe in cui svolgi la maggior parte del lavoro.
  • Modifiche all'API in un modulo utilizzato nel tuo progetto. Sebbene meno rispetto alle modifiche apportate al tuo codice, questo ha un impatto maggiore ed è utile per misurarlo.
  • Modifiche al layout per simulare l'iterazione del lavoro dell'interfaccia utente.
  • Modifiche alle stringhe per simulare la gestione di lavori di traduzione.
  • Pulisci le build per simulare modifiche alla build stessa (ad es. Android Gradle aggiornamento del plug-in, aggiornamento di Gradle o modifiche al codice di build sotto buildSrc).

Per eseguire un'analisi comparativa di questi casi d'uso, potete creare uno scenario utilizzata per guidare l'esecuzione di gradle-profiler e che applica in modo appropriato modifiche alle tue fonti. Puoi esaminare alcuni degli scenari comuni riportati di seguito.

Profilazione di impostazioni di memoria/CPU diverse

Per confrontare diverse impostazioni di memoria e CPU, puoi creare più scenari che utilizzano valori diversi per org.gradle.jvmargs. Per Ad esempio, puoi creare scenari:

# <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"]
}

gradle-profiler --benchmark --project-dir <root-project> --scenario-file scenarios.txt in esecuzione esegue tre scenari e potrai confrontare il tempo :app:assembleDebug richiede per ciascuna di queste configurazioni.

Profilazione di diverse versioni del plug-in Gradle

Per scoprire l'impatto della modifica della versione del plug-in Gradle tempi di creazione, crea uno scenario per l'analisi comparativa. Ciò richiede preparazione per rendere la versione del plug-in iniettabile dallo scenario. Cambia il file build.gradle principale:

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

Ora puoi specificare i plug-in Android per Gradle e Kotlin Gradle del file di scenari e chiedi allo scenario di aggiungere un nuovo metodo i file sorgente:

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

Profilazione di una build incrementale

La maggior parte delle build è incrementale, il che rende questa una delle più importanti scenari da profilare. Profiler Gradle offre un ampio supporto Profilare build incrementali. È in grado di applicare automaticamente modifiche a un file di origine modificando corpo del metodo, aggiungere un nuovo metodo o modificare un layout o una risorsa stringa. Per Ad esempio, puoi creare scenari incrementali come questo:

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

gradle-profiler --benchmark --project-dir &lt;root-project> --scenario-file scenarios.txt in esecuzione genera il report HTML con i dati di benchmarking.

Puoi combinare scenari incrementali con altre impostazioni, come la dimensione heap, numero di worker o versione Gradle:

# <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"]
}

Profilazione di una build pulita

Per eseguire il benchmarking di una build pulita, potete creare uno scenario che sarà utilizzato per guidare l'esecuzione di gradle-profiler:

# <root-project>/scenarios.txt
clean_build {
    tasks = [":app:assembleDebug"]
    cleanup-tasks = ["clean"]
}

Per eseguire questo scenario, utilizza il comando seguente:

gradle-profiler --benchmark --project-dir <root-project> --scenario-file scenarios.txt

Usa l'opzione Gradle --profile

Per generare e visualizzare un profilo di build dalla riga di comando Gradle, esegui segui questi passaggi:

  1. Apri un terminale a riga di comando nella directory principale del progetto.
  2. Esegui una build pulita inserendo questo comando. Durante il profilo devi eseguire una build pulita tra una build e l'altra perché Gradle salta le attività quando gli input in un'attività (come il codice sorgente) non modifica. Di conseguenza, una seconda build senza modifiche agli input viene sempre eseguita più velocemente non vengano eseguite nuovamente. Quindi, eseguendo l'attività clean tra le build ti permettono di profilare l'intero processo di compilazione.
    // On Mac or Linux, run the Gradle wrapper using "./gradlew".
    gradlew clean
    
  3. Eseguire una build di debug di una delle versioni di un prodotto, ad esempio "dev" sapore, con i seguenti flag:
    gradlew --profile --offline --rerun-tasks assembleFlavorDebug
    
    • --profile: attiva la profilazione.
    • --offline: disattiva il recupero online da parte di Gradle delle dipendenze. Questo assicura che eventuali ritardi causati da Gradle di aggiornare le dipendenze non interferiscono con sulla profilazione dei dati. Dovresti aver già creato il progetto una volta per che Gradle abbia già scaricato e memorizzato nella cache le dipendenze.
    • --rerun-tasks: forza Gradle a eseguire nuovamente tutte le attività e a ignorare le ottimizzazioni delle attività.
  4. Figura 1. Vista del progetto che indica la località report sul profilo.

    Una volta completata la build, utilizza la finestra Progetto per accedere alla Directory project-root/build/reports/profile/ (come mostrata nella figura 1).

  5. Fai clic con il tasto destro del mouse sul file profile-timestamp.html e seleziona Apri nel browser > Predefinita. Il report dovrebbe essere simile a questo come mostrato nella figura 2. Puoi esaminare ogni scheda del report per scoprire di più come la scheda Task Execution, che mostra il tempo impiegato da Gradle per eseguire ogni attività di build.

    Figura 2. Visualizzazione di un report in un browser.

  6. Facoltativo:prima di apportare modifiche al progetto o alla build ripeti il comando nel passaggio 3, ma ometti Flag --rerun-tasks. Poiché Gradle cerca di risparmiare tempo rieseguire attività i cui input non sono cambiati (queste sono indicate come UP-TO-DATE nella scheda Esecuzione attività del report, come mostrato nella figura 3), puoi identificare quali attività stanno eseguendo un lavoro quando non dovrebbe esserlo. Ad esempio, se :app:processDevUniversalDebugManifest non è contrassegnato come UP-TO-DATE, potrebbe suggerire che la configurazione della build sia aggiornare in modo dinamico il manifest a ogni build. Tuttavia, alcune attività devono vengono eseguiti durante ogni build, ad esempio :app:checkDevDebugManifest.

    Figura 3. Visualizzazione dei risultati dell'esecuzione dell'attività.

Ora che disponi di un report sul profilo di compilazione, puoi iniziare a cercare opportunità di ottimizzazione esaminando le informazioni in ogni scheda report. Alcune impostazioni della build richiedono una sperimentazione perché i vantaggi possono e differiscono tra progetti e workstation. Ad esempio, i progetti con un il codebase può trarre vantaggio dalla riduzione del codice per rimuovere il codice inutilizzato e ridurre le dimensioni dell'app. Tuttavia, i valori più piccoli i progetti possono trarre vantaggio dalla disattivazione completa della riduzione del codice. Inoltre, aumentando la dimensione dell'heap Gradle (utilizzando org.gradle.jvmargs) potrebbe influire negativamente sulle prestazioni delle macchine con memoria ridotta.

Dopo aver apportato una modifica alla configurazione della build, osserva i risultati le modifiche ripetendo i passaggi precedenti e generando un nuovo profilo di build. Ad esempio, la figura 4 mostra un report per la stessa app di esempio dopo l'applicazione alcune delle ottimizzazioni di base descritte in questa pagina.

Figura 4. Visualizzare un nuovo report dopo l'ottimizzazione della build la velocità.