Questo documento illustra le best practice per diagnosticare i problemi e garantire i profili di riferimento funzionano correttamente per offrire i maggiori benefici.
Problemi con la build
Se hai copiato l'esempio dei profili di riferimento nella sezione Ora in Android di esempio, potresti riscontrare errori nei test durante l'attività Profilo di riferimento che indica che i test non possono essere eseguiti su un emulatore:
./gradlew assembleDemoRelease
Starting a Gradle Daemon (subsequent builds will be faster)
Calculating task graph as no configuration cache is available for tasks: assembleDemoRelease
Type-safe project accessors is an incubating feature.
> Task :benchmarks:pixel6Api33DemoNonMinifiedReleaseAndroidTest
Starting 14 tests on pixel6Api33
com.google.samples.apps.nowinandroid.foryou.ScrollForYouFeedBenchmark > scrollFeedCompilationNone[pixel6Api33] FAILED
java.lang.AssertionError: ERRORS (not suppressed): EMULATOR
WARNINGS (suppressed):
...
Gli errori si verificano perché Now in Android utilizza un dispositivo gestito da Gradle Generazione del profilo di riferimento. Gli errori sono previsti, perché in genere non devono eseguire benchmark delle prestazioni su un emulatore. Tuttavia, poiché non quando generi profili di riferimento, puoi eseguire Raccolta di profili di riferimento sugli emulatori per praticità. Per utilizzare la base di riferimento I profili con un emulatore, eseguono la build e l'installazione dal dalla riga di comando e imposta un argomento per abilitare le regole dei profili di riferimento:
installDemoRelease -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile
In alternativa, puoi creare una configurazione di esecuzione personalizzata in Android Studio per abilita i profili di riferimento sugli emulatori selezionando Esegui > Modifica configurazioni:
di Gemini Advanced.Problemi di installazione
Verifica che l'APK o l'AAB che stai creando provenga da una variante di build che include
Profili di riferimento. Il modo più semplice per verificare è aprire l'APK in
Android Studio selezionando Crea > Analizza l'APK, aprendo lo
APK e cercando il profilo nell'app /assets/dexopt/baseline.prof
file:
I profili di riferimento devono essere compilati sul dispositivo che esegue l'app. Per entrambi
le installazioni di app store e le app installate con
PackageInstaller
, la compilazione sul dispositivo avviene all'interno dell'app
durante il processo di installazione. Tuttavia, quando l'app viene trasferita tramite sideload da Android Studio, oppure
utilizzando gli strumenti a riga di comando, la libreria Jetpack ProfileInstaller
accoderà i profili per la compilazione durante
processo di ottimizzazione DEX in background. In questi casi, se vuoi assicurarti
I profili di riferimento sono in uso, potrebbe essere necessario
forza la compilazione dei profili di riferimento. ProfileVerifier
consente
si esegue una query sullo stato dell'installazione e della compilazione del profilo, come mostrato
nell'esempio seguente:
Kotlin
private const val TAG = "MainActivity" class MainActivity : ComponentActivity() { ... override fun onResume() { super.onResume() lifecycleScope.launch { logCompilationStatus() } } private suspend fun logCompilationStatus() { withContext(Dispatchers.IO) { val status = ProfileVerifier.getCompilationStatusAsync().await() when (status.profileInstallResultCode) { RESULT_CODE_NO_PROFILE -> Log.d(TAG, "ProfileInstaller: Baseline Profile not found") RESULT_CODE_COMPILED_WITH_PROFILE -> Log.d(TAG, "ProfileInstaller: Compiled with profile") RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION -> Log.d(TAG, "ProfileInstaller: Enqueued for compilation") RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING -> Log.d(TAG, "ProfileInstaller: App was installed through Play store") RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST -> Log.d(TAG, "ProfileInstaller: PackageName not found") RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ -> Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read") RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE -> Log.d(TAG, "ProfileInstaller: Can't write cache file") RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION -> Log.d(TAG, "ProfileInstaller: Enqueued for compilation") else -> Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued") } } }
Java
public class MainActivity extends ComponentActivity { private static final String TAG = "MainActivity"; @Override protected void onResume() { super.onResume(); logCompilationStatus(); } private void logCompilationStatus() { ListeningExecutorService service = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor()); ListenableFuture<ProfileVerifier.CompilationStatus> future = ProfileVerifier.getCompilationStatusAsync(); Futures.addCallback(future, new FutureCallback<>() { @Override public void onSuccess(CompilationStatus result) { int resultCode = result.getProfileInstallResultCode(); if (resultCode == RESULT_CODE_NO_PROFILE) { Log.d(TAG, "ProfileInstaller: Baseline Profile not found"); } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE) { Log.d(TAG, "ProfileInstaller: Compiled with profile"); } else if (resultCode == RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION) { Log.d(TAG, "ProfileInstaller: Enqueued for compilation"); } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING) { Log.d(TAG, "ProfileInstaller: App was installed through Play store"); } else if (resultCode == RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST) { Log.d(TAG, "ProfileInstaller: PackageName not found"); } else if (resultCode == RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ) { Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read"); } else if (resultCode == RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE) { Log.d(TAG, "ProfileInstaller: Can't write cache file"); } else if (resultCode == RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION) { Log.d(TAG, "ProfileInstaller: Enqueued for compilation"); } else { Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued"); } } @Override public void onFailure(Throwable t) { Log.d(TAG, "ProfileInstaller: Error getting installation status: " + t.getMessage()); } }, service); } }
I seguenti codici risultato forniscono suggerimenti per la causa di alcuni problemi:
RESULT_CODE_COMPILED_WITH_PROFILE
- Il profilo viene installato, compilato e viene utilizzato ogni volta che l'app viene eseguita. Questo è il risultato che vuoi vedere.
RESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
- Nessun profilo trovato nell'APK o nell'AAB in esecuzione. Assicurati di utilizzare un creare una variante che include i profili di riferimento se viene visualizzato questo errore e l'APK contiene un profilo.
RESULT_CODE_NO_PROFILE
- Durante l'installazione dell'app tramite l'app non è stato installato alcun profilo per questa app
negozio o gestore di pacchetti. Il motivo principale di questo codice di errore è che il profilo
non è stato eseguito perché
ProfileInstallerInitializer
è stato disattivato. Tieni presente che quando viene segnalato questo errore, nella sezione APK dell'app. Quando non viene trovato un profilo incorporato, viene restituito il codice di errore èRESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
. RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
- Nell'APK o nell'AAB è stato trovato un profilo che è in coda per essere compilato. Quando
profilo installato da
ProfileInstaller
, è in coda per la compilazione la prossima volta che l'ottimizzazione DEX in background viene eseguita dal sistema. Il profilo non è attivo fino al completamento della compilazione. Non tentare di confrontare la tua base di riferimento Profili fino al completamento della compilazione. Potresti dover forza la compilazione dei profili di riferimento. Questo errore non si verifica quando L'app viene installata dallo store o dal gestore di pacchetti sui dispositivi Android 9 (API 28) e versioni successive, perché la compilazione eseguite durante l'installazione. RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING
- È installato un profilo non corrispondente, che è stato compilato con l'app.
Questo è il risultato dell'installazione tramite Google Play Store o gestore di pacchetti.
Tieni presente che questo risultato è diverso da
RESULT_CODE_COMPILED_WITH_PROFILE
perché il profilo non corrispondente compilerà solo i metodi che sono ancora condivisi tra il profilo e l'app. Il profilo è effettivamente più piccolo di previsto e verranno compilati meno metodi di quelli inclusi nella base di riferimento Profilo. RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE
ProfileVerifier
non può scrivere il file della cache dei risultati della verifica. Questo può si verificano a causa di problemi con le autorizzazioni della cartella dell'app o se spazio libero su disco sul dispositivo non sufficiente.RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION
- ProfileVerifier
is running on an unsupported API version of Android. ProfileVerifier
supporta solo Android 9 (livello API 28) e versioni successive. RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST
- Quando esegui una query sul tag, viene generato il valore
PackageManager.NameNotFoundException
PackageManager
per il pacchetto dell'app. Questo dovrebbe accadere di rado. Prova disinstallando l'app e reinstallando tutto. RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ
- Esiste un file della cache dei risultati di verifica precedente, ma non può essere letto. Questo si verificano di rado. Prova a disinstallare e reinstallare l'app.
Utilizzare ProfileVerifier in produzione
In produzione, puoi utilizzare ProfileVerifier
insieme a
librerie di report di analisi dei dati, come Google Analytics for Firebase, per
generare eventi di analisi che indichino lo stato del profilo. Ad esempio, questo
avvisa rapidamente se viene rilasciata una nuova versione dell'app che non contiene
Profili di riferimento.
Forza la compilazione dei profili di riferimento
Se lo stato di compilazione dei tuoi profili di riferimento è
RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
, puoi forzare immediatamente
utilizzando adb
:
adb shell cmd package compile -r bg-dexopt PACKAGE_NAME
Controlla lo stato di compilazione senza ProfileVerifier
Se non utilizzi ProfileVerifier
, puoi controllare lo stato di compilazione utilizzando
adb
, anche se non offre informazioni approfondite come ProfileVerifier
:
adb shell dumpsys package dexopt | grep -A 2 PACKAGE_NAME
L'utilizzo di adb
produce un risultato simile al seguente:
[com.google.samples.apps.nowinandroid.demo]
path: /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/base.apk
arm64: [status=speed-profile] [reason=bg-dexopt] [primary-abi]
[location is /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/oat/arm64/base.odex]
Il valore dello stato indica lo stato di compilazione del profilo ed è uno dei i seguenti valori:
Stato compilazione | Significato |
---|---|
speed‑profile |
Un profilo compilato esiste ed è in uso. |
verify |
Non esiste alcun profilo compilato. |
Lo stato verify
non significa che l'APK o l'AAB non contiene un profilo,
perché può essere messo in coda per la compilazione con la successiva ottimizzazione DEX in background
dell'attività.
Il valore del motivo indica che cosa attiva la compilazione del profilo uno dei seguenti valori:
Motivo | Significato |
---|---|
install‑dm
|
Un profilo di riferimento è stato compilato manualmente o da Google Riproduci quando l'app è installata. |
bg‑dexopt
|
È stato compilato un profilo mentre il dispositivo era inattivo. Potrebbe essere un profilo di riferimento o un raccolto durante l'utilizzo dell'app. |
cmdline
|
La compilazione è stata attivata utilizzando adb. Potrebbe essere un profilo di riferimento o un raccolto durante l'utilizzo dell'app. |
Problemi di prestazioni
Questa sezione illustra alcune best practice per una corretta definizione e benchmarking i tuoi profili di riferimento per trarne il massimo vantaggio.
Confronta correttamente le metriche di avvio
I tuoi profili di riferimento saranno più efficaci se le metriche iniziali sono ben definito. Le due metriche principali sono il tempo di visualizzazione iniziale (TTID) e tempo di attesa per la visualizzazione completa (TTFD).
Il TTID si verifica quando l'app recupera il primo frame. È importante che i tempi siano brevi il più possibile perché la visualizzazione di qualcosa mostra all'utente che l'app è in esecuzione. Puoi anche mostrare un indicatore di avanzamento indeterminato per mostrare che l'app sta adattabile.
Il TTFD indica quando è possibile interagire con l'app. È importante tenere il più breve possibile per evitare frustrazioni degli utenti. Se segnali correttamente TTFD, si sta dicendo al sistema che il codice che viene eseguito sul percorso verso il TTFD nell'avvio dell'app. È più probabile che il sistema inserisca questo codice nel profilo di conseguenza.
Mantieni sia TTID che TTFD il più possibile per rendere la tua app reattiva.
Il sistema è in grado di rilevare il TTID, visualizzarlo in Logcat e segnalarlo come parte
di benchmark per le startup. Tuttavia, il sistema non è in grado di determinare il TTFD e
responsabilità dell'app di segnalare quando raggiunge una fase interattiva completamente disegnata
stato. A questo scopo, chiama il numero reportFullyDrawn()
oppure
ReportDrawn
se utilizzi Jetpack Compose. Se disponi di più
attività in background che devono essere completate prima che l'app venga considerata completa
disegnata, puoi utilizzare FullyDrawnReporter
, come descritto in Migliorare
la precisione della tempistica di avvio.
Profili libreria e profili personalizzati
Quando si esegue il benchmarking dell'impatto dei profili, può essere difficile separare i vantaggi dei profili della tua app provenienti dai profili forniti dalle librerie, ad esempio Librerie Jetpack. Quando crei l'APK, il plug-in Android Gradle aggiunge i profili nelle dipendenze della libreria, nonché il tuo profilo personalizzato. Va bene per ottimizzare le prestazioni complessive ed è consigliato per le build di release. Tuttavia, rende difficile misurare l'aumento delle prestazioni che si ottiene del tuo profilo personalizzato.
Un modo rapido per visualizzare manualmente l'ottimizzazione aggiuntiva fornita dal profilo consiste nel rimuoverlo ed eseguire i benchmark. Poi sostituiscilo ed esegui di nuovo i benchmark. Confrontando i due, vedrai le ottimizzazioni fornite dalla solo i profili della biblioteca e i profili della biblioteca più il tuo profilo personalizzato.
Un modo automatizzabile per confrontare i profili è creare una nuova variante di build che
contiene solo i profili della libreria e non il tuo profilo personalizzato. Confronta
benchmark di questa variante per la variante di release che contiene sia il valore
i profili delle biblioteche e i tuoi profili personalizzati. L'esempio seguente mostra come
per configurare la variante che includa solo i profili della raccolta. Aggiungere una nuova variante
denominato releaseWithoutCustomProfile
nel modulo consumer del tuo profilo,
in genere il modulo della tua app:
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile(project(":baselineprofile")) } baselineProfile { variants { create("release") { from(project(":baselineprofile")) } } }
Alla moda
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile ':baselineprofile"' } baselineProfile { variants { release { from(project(":baselineprofile")) } } }
L'esempio di codice precedente rimuove la dipendenza baselineProfile
da tutti
e applica selettivamente solo la variante release
. Potrebbe sembrare
non è chiaro che i profili
della libreria vengono ancora aggiunti quando
la dipendenza dal modulo producer profilo viene rimossa. Tuttavia, questo modulo è
responsabile solo della generazione del profilo personalizzato. Android Gradle
è ancora in esecuzione per tutte le varianti ed è responsabile dell'inclusione
profili delle biblioteche.
Devi anche aggiungere la nuova variante al modulo del generatore del profilo. In questo
Ad esempio, il modulo producer è denominato :baselineprofile
.
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") {} ... } ... }
Alla moda
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile {} ... } ... }
Quando esegui il benchmark da Android Studio, seleziona una
releaseWithoutCustomProfile
variante per misurare il rendimento solo con la raccolta
profili oppure seleziona una variante release
per misurare il rendimento con la raccolta
e profili personalizzati.
Evita l'avvio di app associate all'I/O
Se l'app esegue molte chiamate I/O o chiamate di rete durante l'avvio, può influire negativamente sia sul tempo di avvio dell'app sia sulla precisione dell'avvio il benchmarking. Queste chiamate ad alta intensità possono richiedere tempi indeterminati che possono variare nel tempo e anche tra iterazioni dello stesso benchmark. I/O sono generalmente migliori delle chiamate di rete, perché quest'ultimo può in base a fattori esterni al dispositivo e al dispositivo stesso. Evita chiamate di rete durante l'avvio. Se è inevitabile usare l'uno o l'altro, usa I/O.
È consigliabile fare in modo che l'architettura dell'app supporti l'avvio dell'app senza rete o Chiamate I/O, anche se da usare solo per il benchmarking delle startup. Questo aiuta a garantire la più bassa variabilità possibile tra le diverse iterazioni dei benchmark.
Se la tua app utilizza Hilt, puoi fornire file di I/O falsi implementazioni durante il benchmarking in Microbenchmark e Hilt.
Includi tutti i percorsi importanti degli utenti
È importante comprendere accuratamente tutti i percorsi importanti degli utenti nel tuo Generazione del profilo di riferimento. Gli eventuali percorsi dell'utente non coperti non saranno migliorati dai profili di riferimento. I profili di riferimento più efficaci includono tutte percorsi utente iniziali comuni, nonché utenti in-app sensibili alle prestazioni come lo scorrimento degli elenchi.