Debugowanie profili podstawowych

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:

Dodaj niestandardową konfigurację uruchamiania, aby utworzyć profile podstawowe w Now w Androidzie
Rysunek 1. Dodaj niestandardową konfigurację uruchamiania, aby utworzyć punkt odniesienia Profile w Google Now na Androidzie.
.

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:

Sprawdź profil Baseline za pomocą przeglądarki plików APK w Android Studio
Rysunek 2. Sprawdź profil Baseline za pomocą przeglądarki plików APK w Android Studio.

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. jest RESULT_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
ProfileVerifieris 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 doPackageManager.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.