Ten dokument przedstawia sprawdzone metody diagnozowania problemów i zapewnia Twoje profile podstawowe działają poprawnie, aby zapewnić Ci jak największe korzyści.
Problemy z tworzeniem
Jeśli skopiujesz przykładowy profil podstawowy z narzędzia Now in Android przykładowej aplikacji, podczas wykonywania zadania Profil podstawowy mogą wystąpić błędy testowe stwierdza, że testów nie można przeprowadzać w emulatorze:
./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):
...
Błędy te występują, ponieważ funkcja Now na Androidzie używa urządzenia zarządzanego przez Gradle przez Generowanie profilu podstawowego. Błędy są nieuniknione, ponieważ zwykle nie uruchamiaj testów porównawczych wydajności za pomocą emulatora. Skoro jednak nie jesteś zbieraniu danych o wydajności podczas generowania profili podstawowych można Dla wygody zbieranie danych w ramach profilu podstawowego w emulatorach. Aby użyć punktu odniesienia Profile za pomocą emulatora kompilują i instalują wiersza poleceń i ustaw argument włączający reguły profili podstawowych:
installDemoRelease -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile
Możesz też utworzyć w Android Studio niestandardową konfigurację uruchamiania, włącz profile podstawowe w emulatorach, wybierając Uruchom > Edytuj konfiguracje:
.Problemy przy instalacji
Sprawdź, czy pakiet APK lub pakiet aplikacji na Androida pochodzi z wariantu kompilacji, który zawiera
Profile Baseline. Najłatwiej to sprawdzić, otwierając plik APK w
Android Studio, wybierając Kompilacja > Przeanalizuj plik APK, otwierając
APK i szukam profilu w /assets/dexopt/baseline.prof
.
plik:
Profile podstawowe muszą zostać skompilowane na urządzeniu, na którym działa aplikacja. Zarówno dla
instalacje aplikacji ze sklepu z aplikacjami oraz aplikacje zainstalowane za pomocą
PackageInstaller
, kompilacja na urządzeniu odbywa się w ramach aplikacji.
proces instalacji. Jeśli jednak aplikacja zostanie pobrana z innego źródła z Android Studio lub
za pomocą narzędzi wiersza poleceń, biblioteka Jetpack ProfileInstaller
jest
odpowiedzialny za umieszczenie profili w kolejce na potrzeby kompilacji
procesu optymalizacji plików DEX w tle. W takim przypadku, aby mieć pewność, że
Używasz profili podstawowych. Może być konieczne
wymusza kompilację profili podstawowych. ProfileVerifier
pozwala
zadanego przez Ciebie zapytania o stan instalacji i kompilacji profilu, jak widać w argumencie
następujący przykład:
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); } }
Poniższe kody wyników zawierają wskazówki dotyczące przyczyny niektórych problemów:
RESULT_CODE_COMPILED_WITH_PROFILE
- Profil zostaje zainstalowany, skompilowany i używany podczas uruchamiania aplikacji. Ten to wynik, który chcesz uzyskać.
RESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
- W uruchamianym pliku APK lub AAB nie znaleziono profilu. Upewnij się, że używasz tagu wariant kompilacji, który zawiera profile bazowe, jeśli widzisz ten błąd. plik APK zawiera profil.
RESULT_CODE_NO_PROFILE
- Podczas instalowania aplikacji za pomocą aplikacji nie zainstalowano profilu tej aplikacji
sklepu lub menedżera pakietów. Głównym powodem występowania tego kodu błędu jest to, że profil
instalator nie uruchomił się z powodu wyłączenia
ProfileInstallerInitializer
. Po zgłoszeniu tego błędu nadal znaleziono osadzony profil w APK aplikacji. Jeśli umieszczony profil nie zostanie znaleziony, wyświetli się kod błędu. jestRESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
. RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
- Profil znajduje się w pakiecie APK lub AAB i został dodany do kolejki kompilacji. Gdy
jest instalowany przez pakiet
ProfileInstaller
, jest w kolejce do kompilacji przy następnym uruchomieniu przez system optymalizacji plików DEX w tle. Ten profil nie jest aktywny, dopóki kompilacja się nie zakończy. Nie należy podejmować prób porównawczych punktów odniesienia Profile do momentu ukończenia kompilacji. Może być konieczne wymusza kompilację profili podstawowych. Ten błąd nie występuje, gdy jest zainstalowana ze sklepu z aplikacjami lub menedżera pakietów na urządzeniach z Androida 9 (API 28) i nowszych, ponieważ kompilacja podczas instalacji. RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING
- Zainstalowany zostanie niepasujący profil i aplikacja zostanie z nim skompilowana.
To wynik instalacji ze Sklepu Google Play lub menedżera pakietów.
Zwróć uwagę, że ten wynik różni się od wyniku
RESULT_CODE_COMPILED_WITH_PROFILE
, ponieważ niepasujący profil skompiluje tylko metody, które są nadal udostępniane. między profilem a aplikacją. Profil jest efektywnie mniejszy niż i skompilowanych zostanie mniej metod niż te uwzględnione w podstawowym Profil. RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE
ProfileVerifier
nie może zapisać pliku pamięci podręcznej wyników weryfikacji. Może to spowodować gdy występuje problem z uprawnieniami folderu aplikacji lub nie ma wystarczającej ilości wolnego miejsca na dysku urządzenia.RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION
- ProfileVerifier
is running on an unsupported API version of Android. ProfileVerifier
obsługuje tylko Androida 9 (poziom interfejsu API 28) i nowsze. RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST
- Podczas wysyłania zapytania do
PackageManager.NameNotFoundException
PackageManager
dla pakietu aplikacji. Takie sytuacje są rzadkością. Wypróbuj odinstalowanie aplikacji i ponowne zainstalowanie wszystkiego. RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ
- Istnieje poprzedni plik pamięci podręcznej wyników weryfikacji, ale nie można go odczytać. Ten co powinno zdarzać się bardzo rzadko. Odinstaluj aplikację, a potem zainstaluj wszystko jeszcze raz.
Używanie ProfileVerifier w środowisku produkcyjnym
W wersji produkcyjnej możesz używać ProfileVerifier
w połączeniu z:
bibliotek do raportowania danych analitycznych, np. Google Analytics dla Firebase,
generować zdarzenia analityczne wskazujące stan profilu. Na przykład to
powiadamia szybko, jeśli zostanie udostępniona nowa wersja aplikacji, która nie zawiera
Profile Baseline.
Wymuś kompilację profili podstawowych
Jeśli stan kompilacji profili podstawowych to
RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
, możesz wymusić natychmiastowe
kompilacja za pomocą narzędzia adb
:
adb shell cmd package compile -r bg-dexopt PACKAGE_NAME
Sprawdzanie stanu kompilacji bez narzędzia ProfileVerifier
Jeśli nie używasz ProfileVerifier
, możesz sprawdzić stan kompilacji za pomocą polecenia
adb
, choć nie daje to tak szczegółowych statystyk jak ProfileVerifier
:
adb shell dumpsys package dexopt | grep -A 2 PACKAGE_NAME
Użycie właściwości adb
daje efekt podobny do tego:
[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]
Wartość stanu wskazuje stan kompilacji profilu i jest jednym z następujące wartości:
Stan kompilacji | Znaczenie |
---|---|
speed‑profile |
Skompilowany profil istnieje i jest używany. |
verify |
Brak skompilowanego profilu. |
Stan verify
nie oznacza, że plik APK lub pakiet aplikacji na Androida nie zawiera profilu.
ponieważ może on zostać umieszczony w kolejce do kompilacji przez następną optymalizację DEX w tle.
zadanie.
Wartość przyczyny wskazuje, co powoduje kompilację profilu i jest jedną z tych wartości:
Przyczyna | Znaczenie |
---|---|
install‑dm
|
Profil podstawowy został skompilowany ręcznie lub przez Google Odtwarzaj po zainstalowaniu aplikacji. |
bg‑dexopt
|
Profil został skompilowany, gdy urządzenie było bezczynne. Może to być profil podstawowy lub zbierane podczas korzystania z aplikacji. |
cmdline
|
Kompilacja została aktywowana za pomocą narzędzia adb. Może to być profil podstawowy lub zbierane podczas korzystania z aplikacji. |
problemy z wydajnością,
W tej sekcji przedstawiamy kilka sprawdzonych metod prawidłowego definiowania i przeprowadzania testów porównawczych. aby uzyskać z nich jak najwięcej korzyści.
Prawidłowa analiza danych porównawczych dotyczących startu
Profile podstawowe będą działać lepiej, jeśli wskaźniki startowe będą dobrze zdefiniowany. Dwa najważniejsze wskaźniki to czas do początkowego wyświetlenia (TTID) oraz czas do pełnego wyświetlenia (TTFD).
TTID to czas, w którym aplikacja pobiera pierwszą klatkę. Ważne, aby te informacje były krótkie bo wyświetlenie czegoś pokazuje użytkownikowi, że aplikacja jest uruchomiona. Możesz nawet wyświetlać nieokreślony wskaźnik postępu, responsywnych.
TTFD to czas, w którym można faktycznie wchodzić w interakcję z aplikacją. Ważne jest, aby zachować jak najkrótsze, aby uniknąć frustracji użytkownika. Jeśli prawidłowo sygnalizujesz TTFD. Informujesz system, że kod uruchamiany w drodze do TTFD jest podczas uruchamiania aplikacji. System z większym prawdopodobieństwem umieści ten kod w profilu dzięki temu.
Aby aplikacja działała elastycznie, postaraj się, aby identyfikatory TTID i TTFD były jak najniższe.
System może wykryć TTID, wyświetlić go w Logcat i zgłosić jako część
analiz porównawczych dla startupów. System nie jest jednak w stanie określić trybu TTFD i
ma obowiązek zgłosić aplikację, gdy osiągnie
stanu. Aby to zrobić, zadzwoń pod numer reportFullyDrawn()
lub
ReportDrawn
, jeśli korzystasz z Jetpack Compose. Jeśli masz kilka
zadania w tle, które muszą zostać wykonane, aby aplikacja została uznana za w pełni
możesz użyć narzędzia FullyDrawnReporter
zgodnie z opisem w sekcji Ulepszanie
dokładności czasu uruchamiania.
Profile biblioteki i profile niestandardowe
W analizach wpływu profili trudno jest rozdzielić z profili aplikacji pochodzących z profili udostępnianych przez biblioteki, np. Biblioteki Jetpacka. Gdy tworzysz pakiet APK, wtyczka Androida do obsługi Gradle dodaje profile w zależnościach bibliotek oraz profil niestandardowy. Tak jest dobrze do optymalizacji ogólnej wydajności i jest zalecany w przypadku kompilacji wersji. Trudno jest jednak zmierzyć, o ile zwiększa się skuteczność ze swojego profilu niestandardowego.
Szybki sposób ręcznego sprawdzenia dodatkowej optymalizacji zapewnianej przez niestandardowy jest usunięcie profilu i testowanie porównawczych. Następnie wymień ją i uruchom analiz porównawczych. Porównanie obu tych parametrów pozwoli określić optymalizacje zapewniane przez same profile biblioteki, profile biblioteki i profil niestandardowy.
Automatyzacyjny sposób porównywania profili to utworzenie nowego wariantu kompilacji, który
zawiera tylko profile biblioteki, a nie Twój profil niestandardowy. Porównaj
testów porównawczych tego wariantu z wersją zawierającą zarówno
profili bibliotek i profili niestandardowych. Ten przykład pokazuje,
aby skonfigurować wariant, który obejmuje tylko profile z biblioteki. Dodaj nowy wariant
o nazwie releaseWithoutCustomProfile
do modułu konsumenta profilu, który jest
zwykle moduł aplikacji:
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")) } } }
Odlotowe
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile ':baselineprofile"' } baselineProfile { variants { release { from(project(":baselineprofile")) } } }
Poprzedni przykładowy kod usuwa zależność baselineProfile
ze wszystkich
wariantów i stosuje go selektywnie tylko do wariantu release
. Może się wydawać,
wbrew intuicyjności jest to, że profile biblioteki są wciąż dodawane podczas
zależność od modułu producenta profilu zostanie usunięta. Ten moduł
odpowiada jedynie za wygenerowanie Twojego profilu niestandardowego. Gradle Androida
wtyczka wciąż działa we wszystkich wariantach i odpowiada za uwzględnienie
profili bibliotek.
Musisz też dodać nowy wariant do modułu generatora profili. W tym
Na przykład moduł producenta nazywa się :baselineprofile
.
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") {} ... } ... }
Odlotowe
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile {} ... } ... }
Przeprowadzając test porównawczy w Android Studio, wybierz
releaseWithoutCustomProfile
wariant do pomiaru skuteczności tylko za pomocą biblioteki
profili lub wybierz wariant release
, aby zmierzyć wydajność za pomocą biblioteki
i profili niestandardowych.
Unikaj uruchamiania aplikacji korzystających z operacji wejścia-wyjścia
Jeśli podczas uruchamiania aplikacja wykonuje wiele połączeń wejścia-wyjścia lub połączeń sieciowych, może to negatywnie wpłynąć zarówno na czas uruchamiania aplikacji, jak i na dokładność jej uruchamiania analiz porównawczych. Takie rozmowy mogą zajmować nieokreśloną ilość czasu które mogą się zmieniać w czasie, a nawet w różnych powtórzeniach tego samego testu. I/O są zwykle lepsze niż wywołania sieciowe, ponieważ mogą być na które mają wpływ czynniki zewnętrzne i same urządzenie. Unikaj połączeń sieciowych podczas uruchamiania. Jeśli użycie jednego lub drugiego rozwiązania jest nie do uniknięcia, używaj wejścia/wyjścia.
Zalecamy ustawienie architektury aplikacji tak, aby obsługiwała uruchamianie aplikacji bez użycia sieci lub wywołań wejścia-wyjścia, nawet jeśli ma być używana tylko podczas testowania porównawczych startupów. Pomaga to zapewnić, najniższą możliwą rozbieżność między różnymi iteracjami testu porównawczego.
Jeśli Twoja aplikacja używa Hilt, możesz podać fałszywe dane I/O wdrożeniach w przypadku testów porównawczych w mikroporównaniach i Hilt.
Obejmują wszystkie ważne ścieżki użytkownika
Ważne jest, aby dokładnie uwzględnić wszystkie ważne ścieżki użytkowników w Generowanie profilu podstawowego. Żadne ścieżki użytkowników, które nie zostały uwzględnione, nie zostaną uwzględnione dzięki profilom bazowym. Najskuteczniejsze profile podstawowe obejmują wszystkie typowe ścieżki użytkownika początkowego, a także użytkownicy aplikacji, którym zależy na wydajności. takich jak przewijanie listy.