1. Prima di iniziare
Questo codelab mostra come generare profili di riferimento per ottimizzare il rendimento dell'applicazione e come verificare i vantaggi in termini di rendimento dell'utilizzo dei profili di riferimento.
Che cosa ti serve
- Android Studio Hedgehog (2023.1.1) o versioni successive
- Plug-in Android Gradle 8.0 o versioni successive
- Nozioni di base su Jetpack Macrobenchmark
- Un dispositivo Android fisico con Android 7 (livello API 24) o versioni successive
In questo lab proverai a:
- Configura il progetto in modo che utilizzi i generatori di profili di riferimento.
- Genera profili di riferimento per ottimizzare le prestazioni di avvio e scorrimento dell'app.
- Verifica i miglioramenti del rendimento con la libreria Jetpack Macrobenchmark.
Obiettivi didattici
- Profili di riferimento e come possono migliorare le prestazioni dell'app.
- Come generare i profili di baseline.
- Miglioramento del rendimento dei profili di riferimento.
2. Preparazione
Per iniziare, clona il repository GitHub dalla riga di comando utilizzando questo comando:
$ git clone https://github.com/android/codelab-android-performance.git
In alternativa, puoi scaricare due file ZIP:
Aprire il progetto in Android Studio
- Nella finestra di benvenuto di Android Studio, seleziona
Apri un progetto esistente.
- Seleziona la cartella
[Download Location]/codelab-android-performance/baseline-profiles
. Assicurati di selezionare la directorybaseline-profiles
. - Quando Android Studio importa il progetto, assicurati di poter eseguire il modulo
app
per compilare l'applicazione di esempio con cui lavorerai in un secondo momento.
L'app di esempio
In questo codelab, lavorerai con l'applicazione di esempio JetSnack. Si tratta di un'app virtuale per ordinare snack che utilizza Jetpack Compose.
Per misurare il rendimento dell'applicazione, devi comprendere la struttura dell'interfaccia utente e il comportamento dell'app, in modo da poter accedere agli elementi dell'interfaccia utente dai benchmark. Esegui l'app e acquisisci familiarità con le schermate di base ordinando snack. Non è necessario conoscere i dettagli dell'architettura dell'app.
3. Che cosa sono i profili di riferimento
I profili di riferimento migliorano la velocità di esecuzione del codice di circa il 30% rispetto al primo avvio evitando i passaggi di compilazione just-in-time (JIT) per i percorsi di codice inclusi. Se invii un profilo di riferimento in un'app o una libreria, Android Runtime (ART) può ottimizzare i percorsi di codice inclusi tramite la compilazione AOT (Ahead of Time), offrendo miglioramenti delle prestazioni per ogni nuovo utente e a ogni aggiornamento dell'app. Questa ottimizzazione basata su profilo (PGO) consente alle app di ottimizzare l'avvio, ridurre i problemi di interazione e migliorare le prestazioni complessive del runtime per gli utenti finali fin dal primo avvio.
Con un profilo di riferimento, tutte le interazioni degli utenti, come l'avvio dell'app, il passaggio da una schermata all'altra o lo scorrimento dei contenuti, sono più fluide fin dalla prima esecuzione. L'aumento della velocità e della reattività di un'app porta a un aumento degli utenti attivi giornalieri e a un tasso di visite di ritorno medio più elevato.
I profili di riferimento aiutano a guidare l'ottimizzazione oltre l'avvio dell'app fornendo interazioni utente comuni che migliorano il tempo di esecuzione dell'app dal primo lancio. La compilazione AOT guidata non si basa sui dispositivi degli utenti e può essere eseguita una volta per release su una macchina di sviluppo anziché su un dispositivo mobile. Se pubblichi le release con un profilo di riferimento, le ottimizzazioni delle app diventano disponibili molto più rapidamente rispetto all'utilizzo dei soli profili cloud.
Quando non viene utilizzato un profilo di riferimento, tutto il codice dell'app viene compilato JIT in memoria dopo essere stato interpretato o in un file odex in background quando il dispositivo è inattivo. Gli utenti potrebbero quindi avere un'esperienza non ottimale quando eseguono un'app dopo averla installata o aggiornata per la prima volta prima che i nuovi percorsi siano ottimizzati.
4. Configurare il modulo Generatore di profili di riferimento
Puoi generare profili di riferimento con una classe di test di misurazione che richiede l'aggiunta di un nuovo modulo Gradle al progetto. Il modo più semplice per aggiungerlo al progetto è utilizzare la procedura guidata per i moduli di Android Studio fornita con Android Studio Hedgehog o versioni successive.
Apri la finestra della procedura guidata per la creazione del nuovo modulo facendo clic con il tasto destro del mouse sul progetto o sul modulo nel riquadro Progetto e selezionando Nuovo > Modulo.
Dalla finestra aperta, seleziona Baseline Profile Builder dal riquadro Modelli.
Oltre ai soliti parametri come nome del modulo, nome del pacchetto, lingua o lingua di configurazione della build, esistono due input insolitamente per un nuovo modulo: Applicazione di destinazione e Utilizza dispositivo gestito Gradle.
Applicazione di destinazione è il modulo dell'app utilizzato per generare i profili di riferimento. Se il tuo progetto contiene più di un modulo dell'app, seleziona quello per cui vuoi eseguire i generatori.
La casella di controllo Utilizza dispositivo gestito da Gradle imposta il modulo in modo da eseguire i generatori di profili di riferimento su emulatori Android gestiti automaticamente. Puoi scoprire di più sui dispositivi gestiti da Gradle in Eseguire il scaling dei test con i dispositivi gestiti da Gradle. Se deselezioni questa opzione, i generatori utilizzeranno qualsiasi dispositivo connesso.
Dopo aver definito tutti i dettagli del nuovo modulo, fai clic su Fine per procedere con la creazione.
Modifiche apportate dalla procedura guidata del modulo
La procedura guidata del modulo apporta diverse modifiche al progetto.
Aggiunge un modulo Gradle denominato baselineprofile
o il nome selezionato nella procedura guidata.
Questo modulo utilizza il plug-in com.android.test
, che indica a Gradle di non includerlo nella tua applicazione, in modo che possa contenere solo codice o benchmark di test. Viene applicato anche il plug-in androidx.baselineprofile
, che consente di automatizzare la generazione dei profili di riferimento.
La procedura guidata apporta inoltre modifiche al modulo dell'applicazione di destinazione selezionato. Nello specifico, applica il plug-in androidx.baselineprofile
, aggiunge la dipendenza androidx.profileinstaller
e la dipendenza baselineProfile
al modulo build.gradle(.kts)
appena creato:
plugins {
id("androidx.baselineprofile")
}
dependencies {
// ...
implementation("androidx.profileinstaller:profileinstaller:1.3.0")
"baselineProfile"(project(mapOf("path" to ":baselineprofile")))
}
L'aggiunta della dipendenza androidx.profileinstaller
ti consente di svolgere le seguenti operazioni:
- Verifica localmente i miglioramenti del rendimento dei profili di riferimento generati.
- Usa i profili di base su Android 7 (livello API 24) e Android 8 (livello API 26), che non supportano i profili Cloud.
- Utilizzare i profili di riferimento sui dispositivi che non dispongono di Google Play Services.
La dipendenza baselineProfile(project(":baselineprofile"))
consente a Gradle di sapere da quale modulo deve prendere i profili di riferimento generati.
Ora che hai impostato il progetto, scrivi una classe di generatore di profili di riferimento.
5. Scrivi un generatore del profilo di riferimento
In genere, generi profili di riferimento per i percorsi utente tipici della tua app.
La procedura guidata del modulo crea una classe di test BaselineProfileGenerator
di base in grado di generare il profilo di riferimento per l'avvio dell'app e ha il seguente aspetto:
@RunWith(AndroidJUnit4::class)
@LargeTest
class BaselineProfileGenerator {
@get:Rule
val rule = BaselineProfileRule()
@Test
fun generate() {
rule.collect("com.example.baselineprofiles_codelab") {
// This block defines the app's critical user journey. This is where you
// optimize for app startup. You can also navigate and scroll
// through your most important UI.
// Start default activity for your app.
pressHome()
startActivityAndWait()
// TODO Write more interactions to optimize advanced journeys of your app.
// For example:
// 1. Wait until the content is asynchronously loaded.
// 2. Scroll the feed content.
// 3. Navigate to detail screen.
// Check UiAutomator documentation for more information about how to interact with the app.
// https://d.android.com/training/testing/other-components/ui-automator
}
}
}
Questa classe utilizza una regola di test BaselineProfileRule
e contiene un metodo di test per la generazione del profilo. Il punto di ingresso per generare il profilo è la funzione collect()
. Richiede solo due parametri:
packageName
: il pacchetto della tua app.profileBlock
: l'ultimo parametro lambda.
Nella funzione lambda profileBlock
, specifichi le interazioni che coprono i percorsi utente tipici della tua app. La libreria esegue profileBlock
più volte, raccoglie le classi e le funzioni chiamate e genera il profilo di riferimento sul dispositivo con il codice da ottimizzare.
Per impostazione predefinita, la classe del generatore creata contiene interazioni per avviare il Activity
predefinito e attende che venga visualizzato il primo frame dell'app utilizzando il metodo startActivityAndWait()
.
Espandere il generatore con percorsi personalizzati
Puoi vedere che la classe generata include anche alcuni TODO
per scrivere più interazioni al fine di ottimizzare i percorsi avanzati della tua app. Questa operazione è consigliata per ottimizzare il rendimento oltre l'avvio dell'app.
Nella nostra app di esempio, puoi identificare questi percorsi nel seguente modo:
- Avvia l'applicazione. Questo campo è già parzialmente coperto dalla classe generata.
- Attendi che i contenuti vengano caricati in modo asincrono.
- Scorri l'elenco degli snack.
- Vai ai dettagli dello snack.
Modifica il generatore in modo che contenga le funzioni delineate che coprono i percorsi tipici nel seguente snippet:
// ...
rule.collect("com.example.baselineprofiles_codelab") {
// This block defines the app's critical user journey. This is where you
// optimize for app startup. You can also navigate and scroll
// through your most important UI.
// Start default activity for your app.
pressHome()
startActivityAndWait()
// TODO Write more interactions to optimize advanced journeys of your app.
// For example:
// 1. Wait until the content is asynchronously loaded.
waitForAsyncContent()
// 2. Scroll the feed content.
scrollSnackListJourney()
// 3. Navigate to detail screen.
goToSnackDetailJourney()
// Check UiAutomator documentation for more information about how to interact with the app.
// https://d.android.com/training/testing/other-components/ui-automator
}
// ...
Ora scrivi le interazioni per ogni percorso menzionato. Puoi scriverla come funzione di estensione di MacrobenchmarkScope
in modo da avere accesso ai parametri e alle funzioni che fornisce. Scrivendo in questo modo, puoi riutilizzare le interazioni con i benchmark per verificare i miglioramenti del rendimento.
Attendi i contenuti asincroni
Molte app presentano una sorta di caricamento asincrono all'avvio, noto anche come stato completamente visualizzato, che indica al sistema quando i contenuti vengono caricati e visualizzati e l'utente può interagire con essi. Attendi lo stato nel generatore (waitForAsyncContent
) con queste interazioni:
- Trova l'elenco degli snack del feed.
- Attendi che alcuni elementi dell'elenco siano visibili sullo schermo.
fun MacrobenchmarkScope.waitForAsyncContent() {
device.wait(Until.hasObject(By.res("snack_list")), 5_000)
val contentList = device.findObject(By.res("snack_list"))
// Wait until a snack collection item within the list is rendered.
contentList.wait(Until.hasObject(By.res("snack_collection")), 5_000)
}
Percorso elenco a scorrimento
Per il percorso con l'elenco di snack a scorrimento (scrollSnackListJourney
), puoi seguire queste interazioni:
- Trova l'elemento dell'interfaccia utente dell'elenco di snack.
- Imposta i margini dei gesti per non attivare la navigazione nel sistema.
- Scorri l'elenco e attendi che l'interfaccia utente si risolva.
fun MacrobenchmarkScope.scrollSnackListJourney() {
val snackList = device.findObject(By.res("snack_list"))
// Set gesture margin to avoid triggering gesture navigation.
snackList.setGestureMargin(device.displayWidth / 5)
snackList.fling(Direction.DOWN)
device.waitForIdle()
}
Vai al percorso dettagliato
L'ultimo viaggio (goToSnackDetailJourney
) implementa queste interazioni:
- Trova l'elenco degli snack e tutti gli snack con cui puoi lavorare.
- Seleziona un elemento dall'elenco.
- Fai clic sull'elemento e attendi il caricamento della schermata dei dettagli. Puoi sfruttare il fatto che l'elenco degli snack non sarà più visibile sullo schermo.
fun MacrobenchmarkScope.goToSnackDetailJourney() {
val snackList = device.findObject(By.res("snack_list"))
val snacks = snackList.findObjects(By.res("snack_item"))
// Select snack from the list based on running iteration.
val index = (iteration ?: 0) % snacks.size
snacks[index].click()
// Wait until the screen is gone = the detail is shown.
device.wait(Until.gone(By.res("snack_list")), 5_000)
}
Dopo aver definito tutte le interazioni necessarie affinché il generatore del profilo di riferimento sia pronto per l'esecuzione, devi definire il dispositivo su cui viene eseguito.
6. Prepara un dispositivo su cui eseguire il generatore
Per generare profili di riferimento, ti consigliamo di utilizzare un emulatore come un dispositivo gestito da Gradle o un dispositivo con Android 13 (API 33) o versioni successive.
Per rendere il processo riproducibile e automatizzare la generazione dei profili di riferimento, puoi utilizzare i dispositivi gestiti Gradle. I dispositivi gestiti da Gradle ti consentono di eseguire test su un emulatore Android senza doverli avviare e smontare manualmente. Scopri di più sui dispositivi gestiti da Gradle in Eseguire il scaling dei test con i dispositivi gestiti da Gradle.
Per definire un dispositivo gestito Gradle, aggiungi la relativa definizione al file build.gradle.kts
del modulo :baselineprofile
, come mostrato nello snippet seguente:
android {
// ...
testOptions.managedDevices.devices {
create<ManagedVirtualDevice>("pixel6Api31") {
device = "Pixel 6"
apiLevel = 31
systemImageSource = "aosp"
}
}
}
In questo caso, utilizziamo Android 11 (livello API 31) e l'immagine di sistema aosp
è in grado di accedere con accesso root.
Successivamente, configura il plug-in Gradle del profilo di riferimento in modo che utilizzi il dispositivo gestito da Gradle definito. A tale scopo, aggiungi il nome del dispositivo alla proprietà managedDevices
e disattiva useConnectedDevices
come mostrato nel seguente snippet:
android {
// ...
}
baselineProfile {
managedDevices += "pixel6Api31"
useConnectedDevices = false
}
dependencies {
// ...
}
A questo punto, genera il profilo di riferimento.
7. Genera il profilo di riferimento
Una volta che il dispositivo è pronto, puoi creare il profilo di riferimento. Il plug-in Gradle Baseline Profile crea attività Gradle per automatizzare l'intero processo di esecuzione della classe di test del generatore e di applicazione dei profili di riferimento generati nella tua app.
La nuova procedura guidata per i moduli ha creato la configurazione di esecuzione per poter eseguire rapidamente l'attività Gradle con tutti i parametri necessari per l'esecuzione senza dover passare dal terminale ad Android Studio
Per eseguirlo, individua la configurazione di esecuzione Generate Baseline Profile
e fai clic sul pulsante Esegui .
L'attività avvia l'immagine dell'emulatore definita in precedenza. Esegui le interazioni della classe di test BaselineProfileGenerator
più volte, poi rimuovi l'emulatore e fornisci l'output ad Android Studio.
Una volta completato il generatore, il plug-in Gradle inserisce automaticamente il baseline-prof.txt
generato nell'applicazione di destinazione (modulo :app
) nella cartella src/release/generated/baselineProfile/
.
(Facoltativo) Esegui il generatore dalla riga di comando
In alternativa, puoi eseguire il generatore dalla riga di comando. Puoi utilizzare l'attività creata dal dispositivo gestito Gradle: :app:generateBaselineProfile
. Questo comando esegue tutti i test nel progetto definito dalla dipendenza baselineProfile(project(:baselineProfile))
. Poiché il modulo contiene anche benchmark per la verifica successiva degli incrementi delle prestazioni, questi test non vanno a buon fine con un avviso che sconsiglia di eseguire benchmark su un emulatore.
android .testInstrumentationRunnerArguments .androidx.benchmark.enabledRules=BaselineProfile
Per questo motivo, puoi filtrare tutti i generatori dei profili di riferimento con il seguente argomento runner di strumentazione e tutti i benchmark vengono ignorati:
L'intero comando è il seguente:
./gradlew :app:generateBaselineProfile -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile
Distribuire l'app con i profili di riferimento
Dopo aver generato e copiato il profilo di base nel codice sorgente della tua app, crea la versione di produzione dell'app come fai normalmente. Non devi fare altro per distribuire i profili di base ai tuoi utenti. Vengono scelti dal plug-in Android Gradle durante la compilazione e inclusi nell'AAB o nell'APK. Poi carica la build su Google Play.
Quando gli utenti installano l'app o la aggiornano dalla versione precedente, viene installato anche il profilo di riferimento, con un miglioramento del rendimento fin dalla prima esecuzione dell'app.
Il passaggio successivo mostra come verificare di quanto migliorano le prestazioni dell'app con i profili di riferimento.
8. (Facoltativo) Personalizzare la generazione dei profili di riferimento
Il plug-in Gradle Baseline Profiles include opzioni per personalizzare il modo in cui vengono generati i profili in base alle tue esigenze specifiche. Puoi modificare il comportamento con il blocco di configurazione baselineProfile { }
negli script di compilazione.
Il blocco di configurazione all'interno del modulo :baselineprofile
influisce su come eseguire i generatori con la possibilità di aggiungere managedDevices
e decidere se useConnectedDevices
o dispositivi gestiti da Gradle.
Il blocco di configurazione all'interno del modulo target :app
stabilisce dove vengono salvati i profili o come vengono generati. Puoi modificare i seguenti parametri:
automaticGenerationDuringBuild
: se questa opzione è abilitata, puoi generare il profilo di base durante la creazione della build della release di produzione. Questo è utile quando esegui la compilazione in CI prima di rilasciare l'app.saveInSrc
: specifica se i profili di riferimento generati sono archiviati nella cartellasrc/
. In alternativa, puoi accedere al file dalla cartella di compilazione:baselineprofile
.baselineProfileOutputDir
: definisce dove memorizzare i profili di baseline generati.mergeIntoMain
: per impostazione predefinita, i profili di riferimento vengono generati per variante della build (versione di prodotto e tipo di build). Se vuoi unire tutti i profili insrc/main
, puoi farlo attivando questo flag.filter
: puoi filtrare le classi o i metodi da includere o escludere dai profili di riferimento generati. Questa opzione può essere utile per gli sviluppatori di librerie che vogliono includere solo il codice della libreria.
9. Verificare i miglioramenti delle prestazioni all'avvio
Dopo aver generato il profilo di riferimento e averlo aggiunto all'app, verifica che abbia l'effetto desiderato sul rendimento dell'app.
La procedura guidata per la creazione del nuovo modulo crea una classe di benchmark denominata StartupBenchmarks
. Contiene un benchmark per misurare il tempo di avvio dell'app e lo confronta con il tempo di avvio quando l'app utilizza i profili di riferimento.
La classe ha il seguente aspetto:
@RunWith(AndroidJUnit4::class)
@LargeTest
class StartupBenchmarks {
@get:Rule
val rule = MacrobenchmarkRule()
@Test
fun startupCompilationNone() =
benchmark(CompilationMode.None())
@Test
fun startupCompilationBaselineProfiles() =
benchmark(CompilationMode.Partial(BaselineProfileMode.Require))
private fun benchmark(compilationMode: CompilationMode) {
rule.measureRepeated(
packageName = "com.example.baselineprofiles_codelab",
metrics = listOf(StartupTimingMetric()),
compilationMode = compilationMode,
startupMode = StartupMode.COLD,
iterations = 10,
setupBlock = {
pressHome()
},
measureBlock = {
startActivityAndWait()
// TODO Add interactions to wait for when your app is fully drawn.
// The app is fully drawn when Activity.reportFullyDrawn is called.
// For Jetpack Compose, you can use ReportDrawn, ReportDrawnWhen and ReportDrawnAfter
// from the AndroidX Activity library.
// Check the UiAutomator documentation for more information on how to
// interact with the app.
// https://d.android.com/training/testing/other-components/ui-automator
}
)
}
}
Usa MacrobenchmarkRule
in grado di eseguire benchmark per la tua app e raccogliere metriche sul rendimento. Il punto di ingresso per la scrittura di un benchmark è la funzione measureRepeated
della regola.
Richiede diversi parametri:
packageName:
l'applicazione da misurare.metrics
: il tipo di informazioni che vuoi misurare durante il benchmark.iterations
: il numero di ripetizioni del benchmark.startupMode
: la modalità di avvio dell'applicazione all'inizio del benchmark.setupBlock
: le interazioni con la tua app che devono avvenire prima della misurazione.measureBlock
: interazioni con la tua app da misurare durante il benchmark.
La classe di test contiene anche due test: startupCompilationeNone()
e startupCompilationBaselineProfiles()
, che chiamano la funzione benchmark()
con compilationMode
diversi.
CompilationMode
Il parametro CompilationMode
definisce la modalità di precompilazione dell'applicazione in codice macchina. Offre le seguenti opzioni:
DEFAULT
: precompila parzialmente l'app utilizzando i profili di riferimento, se disponibili. Viene utilizzato se non viene applicato alcun parametrocompilationMode
.None()
: reimposta lo stato di compilazione dell'app e non la precompila. La compilazione Just-in-time (JIT) è comunque attivata durante l'esecuzione dell'app.Partial()
: precompila l'app con i profili di riferimento o le esecuzioni di riscaldamento o con entrambi.Full()
: precompila l'intero codice dell'applicazione. Questa è l'unica opzione disponibile su Android 6 (API 23) e versioni precedenti.
Se vuoi iniziare a ottimizzare il rendimento dell'applicazione, puoi scegliere la modalità di compilazione DEFAULT
, perché il rendimento è simile a quello dell'app installata da Google Play. Se vuoi confrontare i vantaggi in termini di rendimento forniti dai profili di riferimento, puoi farlo confrontando i risultati della modalità di compilazione None
e Partial
.
Modificare il benchmark in modo da attendere i contenuti
I benchmark sono scritti in modo simile ai generatori dei profili di riferimento scrivendo le interazioni con la tua app. Per impostazione predefinita, i benchmark creati attendono solo il rendering del primo frame, in modo simile al BaselineProfileGenerator
, quindi ti consigliamo di migliorarlo in modo da attendere i contenuti asincroni.
Puoi farlo riutilizzando le funzioni di estensione che scrivi per il generatore. Poiché questo benchmark acquisisce i tempi di avvio, utilizzando StartupTimingMetric()
, ti consigliamo di attendere solo i contenuti asincroni qui e poi di scrivere un benchmark separato per gli altri percorsi dell'utente definiti nel generatore.
// ...
measureBlock = {
startActivityAndWait()
// The app is fully drawn when Activity.reportFullyDrawn is called.
// For Jetpack Compose, you can use ReportDrawn, ReportDrawnWhen and ReportDrawnAfter
// from the AndroidX Activity library.
waitForAsyncContent() // <------- Added to wait for async content.
// Check the UiAutomator documentation for more information on how to
// interact with the app.
// https://d.android.com/training/testing/other-components/ui-automator
}
Eseguire i benchmark
Puoi eseguire i benchmark nello stesso modo in cui esegui i test con strumenti. Puoi eseguire la funzione di test o l'intero corso con l'icona della canalina accanto.
Assicurati di aver selezionato un dispositivo fisico, perché l'esecuzione di benchmark sull'emulatore Android non va a buon fine in fase di esecuzione con un avviso che indica che il benchmark può fornire risultati errati. Anche se tecnicamente puoi eseguirlo su un emulatore, stai misurando il rendimento della macchina host. Se il carico è elevato, i benchmark funzionano più lentamente e in modo inverso.
Una volta eseguito il benchmark, l'app viene ricostruita ed esegue i benchmark. I benchmark avviano, arrestano e persino reinstallano l'app più volte in base al iterations
che definisci.
Una volta completati i benchmark, puoi vedere i tempi nell'output di Android Studio, come mostrato nello screenshot seguente:
Dallo screenshot, puoi vedere che il tempo di avvio dell'app è diverso per ogni CompilationMode
. I valori mediani sono riportati nella tabella seguente:
tempoToInizialeDisplay [ms] | timeToFullDisplay [ms] | |
Nessuno | 202,2 | 818,8 |
BaselineProfiles | 193,7 | 637,9 |
Miglioramento | 4% | 28% |
La differenza tra le modalità di compilazione per timeToFullDisplay
è di 180 ms,che rappresenta un miglioramento di circa il 28% grazie al semplice profilo di riferimento. CompilationNone
ha un rendimento peggiore perché il dispositivo deve eseguire la maggior parte della compilazione JIT durante l'avvio dell'app. CompilationBaselineProfiles
ha un rendimento migliore perché la compilazione parziale con i profili di base AOT compila il codice che l'utente ha maggiori probabilità di utilizzare e lascia il codice non critico non precompilato, in modo che non debba essere caricato immediatamente.
10. (Facoltativo) Verificare il miglioramento delle prestazioni dello scorrimento
Come nel passaggio precedente, puoi misurare e verificare il rendimento dello scorrimento. Per prima cosa, crea una classe di test ScrollBenchmarks
con la regola di benchmark e due metodi di test che utilizzano diverse modalità di compilazione:
@LargeTest
@RunWith(AndroidJUnit4::class)
class ScrollBenchmarks {
@get:Rule
val rule = MacrobenchmarkRule()
@Test
fun scrollCompilationNone() = scroll(CompilationMode.None())
@Test
fun scrollCompilationBaselineProfiles() = scroll(CompilationMode.Partial())
private fun scroll(compilationMode: CompilationMode) {
// TODO implement
}
}
All'interno del metodo scroll
, utilizza la funzione measureRepeated
con i parametri richiesti. Per il parametro metrics
, utilizza FrameTimingMetric
, che misura il tempo necessario per generare i frame dell'interfaccia utente:
private fun scroll(compilationMode: CompilationMode) {
rule.measureRepeated(
packageName = "com.example.baselineprofiles_codelab",
metrics = listOf(FrameTimingMetric()),
compilationMode = compilationMode,
startupMode = StartupMode.WARM,
iterations = 10,
setupBlock = {
// TODO implement
},
measureBlock = {
// TODO implement
}
)
}
Questa volta, devi suddividere maggiormente le interazioni tra setupBlock
e measureBlock
per misurare solo le durate dei frame durante il primo layout e lo scorrimento dei contenuti. Pertanto, inserisci le funzioni che avviano la schermata predefinita in setupBlock
e le funzioni di estensione già create waitForAsyncContent()
e scrollSnackListJourney()
in measureBlock
:
private fun scroll(compilationMode: CompilationMode) {
rule.measureRepeated(
packageName = "com.example.baselineprofiles_codelab",
metrics = listOf(FrameTimingMetric()),
compilationMode = compilationMode,
startupMode = StartupMode.WARM,
iterations = 10,
setupBlock = {
pressHome()
startActivityAndWait()
},
measureBlock = {
waitForAsyncContent()
scrollSnackListJourney()
}
)
}
Quando il benchmark è pronto, puoi eseguirlo come prima per ottenere i risultati, come illustrato nello screenshot seguente:
FrameTimingMetric
restituisce la durata dei frame in millisecondi (frameDurationCpuMs
) nel 50°, 90°, 95° e 99° percentile. Su Android 12 (livello API 31) e versioni successive, viene restituito anche il tempo di superamento del limite massimo consentito dai frame (frameOverrunMs
). Il valore può essere negativo, il che significa che è rimasto altro tempo per produrre il frame.
Dai risultati, puoi vedere che CompilationBaselineProfiles
ha in media una durata frame inferiore di 2 ms, il che potrebbe non essere evidente per gli utenti. Tuttavia, per gli altri percentili i risultati sono più evidenti. Per il P99, la differenza è di 43,5 ms, ovvero più di 3 frame saltati su un dispositivo che funziona a 90 FPS. Ad esempio, per Pixel 6 il tempo massimo per il rendering di un frame è di 1000 ms/90 f/s = circa 11 ms.
11. Complimenti
Congratulazioni, hai completato questo codelab e hai migliorato il rendimento della tua app con i profili di riferimento.
Altre risorse
Consulta le seguenti risorse aggiuntive:
- Esaminare il rendimento delle app con Macrobenchmark: un codelab che approfondisce il benchmarking.
- Samples di rendimento: repository contenente Macrobenchmark e altri campioni di rendimento.
- Ora nell'app di esempio Android: un'applicazione reale che utilizza il benchmarking e i profili di riferimento per migliorare le prestazioni.