Ręczne tworzenie profili bazowych i pomiar ich skuteczności

Zdecydowanie zalecamy automatyczne generowanie reguł profilu za pomocą biblioteki Macrobenchmark, aby zmniejszyć nakład pracy i zwiększyć ogólną skalowalność. Można jednak ręcznie tworzyć w aplikacji reguły dotyczące profilu i mierzyć ich skuteczność.

Zdefiniuj reguły profilu ręcznie

Reguły profilu możesz zdefiniować ręcznie w aplikacji lub module biblioteki, tworząc plik o nazwie baseline-prof.txt w katalogu src/main. To ten sam folder, który zawiera plik AndroidManifest.xml.

Każdą regułę w pliku podano po jednej w każdym wierszu. Każda reguła reprezentuje wzorzec dopasowywania metod lub klas w aplikacji bądź bibliotece, który wymaga optymalizacji.

Składnia tych reguł jest nadzbiorem zrozumiałego dla człowieka formatu profilu ART (HRF) podczas korzystania z funkcji adb shell profman --dump-classes-and-methods. Składnia jest podobna do składni deskryptorów i podpisów, ale umożliwia użycie symboli wieloznacznych do uproszczenia procesu pisania reguł.

Poniższy przykład przedstawia kilka reguł profilu podstawowego zawartych w bibliotece Jetpack Compose:

HSPLandroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V
HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I
HLandroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V
PLandroidx/compose/runtime/CompositionImpl;->applyChanges()V
HLandroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I
Landroidx/compose/runtime/ComposerImpl;

Składnia reguły

Reguły te mają jedną z dwóch postaci:

[FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE]

Reguła klasy używa tego wzorca:

[CLASS_DESCRIPTOR]

Szczegółowy opis znajdziesz w tej tabeli:

Składnia Opis
FLAGS Reprezentuje co najmniej jeden ze znaków H, S i P wskazujący, czy ta metoda musi być oznaczona jako Hot, Startup czy Post Startup w odniesieniu do typu uruchamiania.

Metoda z flagą H wskazuje, że jest to metoda „gorąca”, co oznacza, że jest wywoływana wiele razy przez cały okres użytkowania aplikacji.

Metoda z flagą S wskazuje, że jest ona wywoływana podczas uruchamiania.

Metoda z flagą P wskazuje, że jest wywoływana po uruchomieniu.

Klasa znajdująca się w tym pliku wskazuje, że jest używana podczas uruchamiania i musi być wstępnie przydzielona na stercie, aby uniknąć kosztów ładowania zajęć. Kompilator ART korzysta z różnych strategii optymalizacji, takich jak kompilacja AOT tych metod i przeprowadzanie optymalizacji układu w wygenerowanym pliku AOT.
CLASS_DESCRIPTOR Deskryptor klasy metody kierowania. Na przykład androidx.compose.runtime.SlotTable ma deskryptor o wartości Landroidx/compose/runtime/SlotTable;. W formacie Dalvik Executable (DEX) następuje ciąg L.
METHOD_SIGNATURE Podpis metody, w tym nazwa, typy parametrów i zwracane typy metody. Na przykład:

// LayoutNode.kt

fun isPlaced():Boolean {
// ...
}

na LayoutNode ma podpis isPlaced()Z.

Wzorce mogą zawierać symbole wieloznaczne, aby jedna reguła obejmowała wiele metod lub klas. Pomoc przy tworzeniu składni reguł w Android Studio znajdziesz we wtyczce Android Baseline Profiles.

Przykładowa reguła z symbolem wieloznacznym może wyglądać mniej więcej tak:

HSPLandroidx/compose/ui/layout/**->**(**)**

Obsługiwane typy w regułach profilu podstawowego

Reguły profilu podstawowego obsługują poniższe typy. Szczegółowe informacje o tych typach znajdziesz w formacie Dalvik Executable (DEX).

Znak Typ Opis
B bajt Podpisany bajt
C znak Znakowy punkt kodowy Unicode zakodowany w UTF-16
D podwójny Wartość zmiennoprzecinkowa podwójnej precyzji
F liczba zmiennoprzecinkowa Wartość zmiennoprzecinkowa o pojedynczej precyzji
I int Liczba całkowita
J długi Długa liczba całkowita
S krótki Podpisany – Short
V nieważność Nieważna
Z Wartość logiczna Prawda czy fałsz?
L (nazwa zajęć) pliku referencyjnego Instancja o nazwie klasy

Biblioteki mogą też definiować reguły, które są pakietowane w artefaktach AAR. Gdy tworzysz plik APK, który ma zawierać te artefakty, reguły są scalane (podobnie jak dzieje się to w przypadku scalania plików manifestu) i kompilowane w kompaktowy binarny profil ART specyficzny dla danego pliku.

ART korzysta z tego profilu, gdy plik APK jest używany na urządzeniach do kompilowania określonego podzbioru aplikacji w czasie instalacji na Androidzie 9 (poziom interfejsu API 28) lub Androidzie 7 (poziom API 24) przy użyciu ProfileInstaller.

Ręczne zbieranie profili bazowych

Możesz ręcznie wygenerować profil podstawowy bez konfigurowania biblioteki Macroporównanie, a także utworzyć w interfejsie automatyzację kluczowych działań użytkowników. Chociaż zalecamy korzystanie z porównań makr, nie zawsze jest to możliwe. Jeśli na przykład używasz systemu kompilacji innego niż Gradle, nie możesz używać wtyczki Gradle profilu podstawowego. W takich przypadkach możesz ręcznie zbierać reguły profilu podstawowego. Jest to znacznie łatwiejsze, jeśli używasz urządzenia lub emulatora z interfejsem API 34 lub nowszym. Chociaż jest to możliwe przy niższych poziomach interfejsów API, wymaga on dostępu do roota i musisz użyć emulatora obsługującego obraz AOSP. Reguły możesz zbierać bezpośrednio, wykonując te czynności:

  1. Zainstaluj wersję aplikacji na urządzeniu testowym. Aby uzyskać dokładny profil, typ kompilacji aplikacji musi być zoptymalizowany pod kątem R8 i nie można go debugować.
  2. Sprawdź, czy profile nie zostały już skompilowane.

    API 34 i nowsze

    adb shell cmd package compile -f -m verify $PACKAGE_NAME
    adb shell pm art clear-app-profiles $PACKAGE_NAME
    

    API 33 i starsze

    adb root
    adb shell cmd package compile --reset $PACKAGE_NAME
    

    Jeśli Twój plik APK jest zależny od biblioteki instalatora profilu Jetpack, biblioteka wczytuje profil przy pierwszym uruchomieniu pliku APK. Może to zakłócić proces generowania profilu, dlatego wyłącz go za pomocą tego polecenia:

    adb shell am broadcast -a androidx.profileinstaller.action.SKIP_FILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver
    

  3. Uruchom aplikację i ręcznie przejdź przez najważniejsze ścieżki użytkowników, w przypadku których chcesz zbierać profile.
  4. Poproś ART o zrzut profili. Jeśli Twój plik APK jest zależny od biblioteki instalatora profilu Jetpack, użyj jej do pobrania profili:

    adb shell am broadcast -a androidx.profileinstaller.action.SAVE_FILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver
    adb shell am force-stop $PACKAGE_NAME
    
    Jeśli nie używasz instalatora profili, zrzuć profile ręcznie w emulatorze, korzystając z tego polecenia:

    adb root
    adb shell killall -s SIGUSR1 $PACKAGE_NAME
    adb shell am force-stop $PACKAGE_NAME
    

  5. Odczekaj co najmniej pięć sekund, aby wygenerować profil.
  6. Przekonwertuj wygenerowane profile binarne na tekst:

    API 34 i nowsze

    adb shell pm dump-profiles --dump-classes-and-methods $PACKAGE_NAME
    

    API 33 i starsze

    Sprawdź, czy został utworzony profil referencyjny czy bieżący. Profil referencyjny znajduje się w tym miejscu:

    /data/misc/profiles/ref/$$PACKAGE_NAME/primary.prof
    

    Bieżący profil znajduje się w tej lokalizacji:

    /data/misc/profiles/cur/0/$PACKAGE_NAME/primary.prof
    

    Określ lokalizację pliku APK:

    adb root
    adb shell pm path $PACKAGE_NAME
    

    Wykonaj konwersję:

    adb root
    adb shell profman --dump-classes-and-methods --profile-file=$PROFILE_PATH --apk=$APK_PATH > /data/misc/profman/$PACKAGE_NAME-primary.prof.txt
    

  7. Użyj narzędzia adb, aby pobrać skopiowany profil z urządzenia:

    adb pull /data/misc/profman/$PACKAGE_NAME-primary.prof.txt PATH_TO_APP_MODULE/src/main/
    

Wygenerowane reguły profilu zostaną pobrane i zainstalowane w module aplikacji. Profil podstawowy będzie uwzględniany przy następnym tworzeniu aplikacji. Aby to sprawdzić, wykonaj czynności opisane w sekcji Problemy z instalacją.

Ręczne pomiary ulepszeń aplikacji

Zdecydowanie zalecamy przeprowadzanie testów porównawczych dotyczących wprowadzania ulepszeń aplikacji. Jeśli jednak chcesz samodzielnie mierzyć ulepszenia, możesz zacząć od pomiaru niezoptymalizowanego uruchomienia aplikacji.

PACKAGE_NAME=com.example.app
# Force Stop App
adb shell am force-stop $PACKAGE_NAME
# Reset compiled state
adb shell cmd package compile --reset $PACKAGE_NAME
# Measure App startup
# This corresponds to `Time to initial display` metric.
adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \
 | grep "TotalTime"

Następnie wczytaj profil podstawowy z innego urządzenia.

# Unzip the Release APK first.
unzip release.apk
# Create a ZIP archive.
# The name should match the name of the APK.
# Copy `baseline.prof{m}` and rename it `primary.prof{m}`.
cp assets/dexopt/baseline.prof primary.prof
cp assets/dexopt/baseline.profm primary.profm
# Create an archive.
zip -r release.dm primary.prof primary.profm
# Confirm that release.dm only contains the two profile files:
unzip -l release.dm
# Archive:  release.dm
#   Length      Date    Time    Name
# ---------  ---------- -----   ----
#      3885  1980-12-31 17:01   primary.prof
#      1024  1980-12-31 17:01   primary.profm
# ---------                     -------
#                               2 files
# Install APK + Profile together.
adb install-multiple release.apk release.dm

Aby sprawdzić, czy podczas instalacji pakiet został zoptymalizowany, uruchom to polecenie:

# Check dexopt state.
adb shell dumpsys package dexopt | grep -A 1 $PACKAGE_NAME

Dane wyjściowe muszą wskazywać, że pakiet jest skompilowany:

[com.example.app]
  path: /data/app/~~YvNxUxuP2e5xA6EGtM5i9A==/com.example.app-zQ0tkJN8tDrEZXTlrDUSBg==/base.apk
  arm64: [status=speed-profile] [reason=install-dm]

Teraz możesz mierzyć wydajność uruchamiania aplikacji tak jak wcześniej, ale bez resetowania stanu skompilowanego. Zadbaj o to, aby nie resetować stanu skompilowanego pakietu.

# Force stop app
adb shell am force-stop $PACKAGE_NAME
# Measure app startup
adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \
 | grep "TotalTime"

Profile podstawowe i profgen

W tej sekcji opisujemy, co robi narzędzie profgen podczas tworzenia kompaktowej wersji binarnej profilu podstawowego.

Interfejs Profgen-cli ułatwia kompilowanie profili ART oraz przeprowadzanie introspekcji i transpilowanie profili ART, dzięki czemu można je instalować na urządzeniach z Androidem niezależnie od docelowej wersji pakietu SDK.

Profgen-cli to interfejs wiersza poleceń, który kompilowa HRF profilu podstawowego do jego skompilowanego formatu. Interfejs wiersza poleceń jest też dostępny w repozytorium cmdline-tools w ramach pakietu SDK na Androida.

Te funkcje są dostępne w gałęzi studio-main:

➜ ../cmdline-tools/latest/bin
apkanalyzer
avdmanager
lint
profgen
retrace
screenshot2
sdkmanager

Twórz kompaktowe profile binarne za pomocą Profgen-cli

Polecenia dostępne w Profgen-cli to bin, validate i dumpProfile. Aby zobaczyć dostępne polecenia, użyj polecenia profgen --help:

profgen --help
Usage: profgen options_list
Subcommands:
    bin - Generate Binary Profile
    validate - Validate Profile
    dumpProfile - Dump a binary profile to a HRF

Options:
    --help, -h -> Usage info

Użyj polecenia bin, aby wygenerować kompaktowy profil binarny. Oto przykładowe wywołanie:

profgen bin ./baseline-prof.txt \
  --apk ./release.apk \
  --map ./obfuscation-map.txt \
  --profile-format v0_1_0_p \
  --output ./baseline.prof \

Aby zobaczyć dostępne opcje, użyj profgen bin options_list:

Usage: profgen bin options_list
Arguments:
    profile -> File path to Human Readable profile { String }
Options:
    --apk, -a -> File path to apk (always required) { String }
    --output, -o -> File path to generated binary profile (always required)
    --map, -m -> File path to name obfuscation map { String }
    --output-meta, -om -> File path to generated metadata output { String }
    --profile-format, -pf [V0_1_0_P] -> The ART profile format version
      { Value should be one of [
         v0_1_5_s, v0_1_0_p, v0_0_9_omr1, v0_0_5_o, v0_0_1_n
        ]
      }
    --help, -h -> Usage info

Pierwszy argument przedstawia ścieżkę do HRF baseline-prof.txt.

Profgen-cli wymaga też ścieżki do kompilacji pakietu APK oraz mapy zaciemniania kodu, która służy do zaciemniania pliku APK w przypadku korzystania z R8 lub ProGuard. Dzięki temu profgen może tłumaczyć symbole źródłowe w HRF na odpowiadające im zaciemnione nazwy podczas tworzenia skompilowanego profilu.

Formaty profili ART nie są zgodne wstecz ani wstecznie, dlatego podaj format profilu, w którym plik profgen tworzy metadane profilu (profm), których w razie potrzeby możesz używać do transkodowania jednego formatu profilu ART na inny.

Formaty profilu i wersje platformy

Podczas wybierania formatu profilu dostępne są następujące opcje:

Format profilu Wersja platformy Poziom interfejsu API
wersja 0_1_5_s Android S+ ponad 31
wersja 0_1_0_p Android P, Q i R 28-30
v0_0_9_omr1 Android O MR1 27
wersja 0_0_5_o Android O 26
wersja 0_0_1_n Android N 24-25

Skopiuj pliki wyjściowe baseline.prof i baseline.profm do folderu assets lub dexopt w pliku APK.

Mapy zaciemniania kodu

Mapę zaciemniania musisz przesłać tylko wtedy, gdy w HRF są używane symbole źródła. Jeśli dane HRF są generowane na podstawie kompilacji wersji, która jest już zaciemniona i mapowanie nie jest konieczne, możesz zignorować tę opcję i skopiować dane wyjściowe do folderu assets lub dexopt.

Tradycyjna instalacja profili bazowych

Profile podstawowe są tradycyjnie dostarczane na urządzenie na jeden z dwóch sposobów.

Używanie właściwości install-multiple z metadanymi DexMetadata

Na urządzeniach z interfejsem API 28 lub nowszym klient Google Play pobiera plik APK i ładunek DexMetadata (DM) dla instalowanej wersji pliku APK. DM zawiera informacje o profilu przekazywane do menedżera pakietów na urządzeniu.

Plik APK i DM są instalowane w ramach pojedynczej sesji instalacji przy użyciu takiego elementu:

adb install-multiple base.apk base.dm

Instalator profilu Jetpack

Na urządzeniach z interfejsem API na poziomie 29 lub nowszym biblioteka JetpackProfileInstaller zapewnia alternatywny mechanizm instalacji profilu spakowanego do aplikacji assetslub dexopt po zainstalowaniu pliku APK na urządzeniu. Narzędzie ProfileInstaller jest wywoływane przez ProfileInstallReceiver lub bezpośrednio przez aplikację.

Biblioteka ProfileInstaller transkoduje profil na podstawie wersji pakietu SDK urządzenia docelowego i kopiuje profil do katalogu cur na urządzeniu (katalogu przejściowego dla konkretnego pakietu dla profili ART na urządzeniu).

Gdy urządzenie jest nieaktywne, profil jest pobierany na urządzeniu w ramach procesu o nazwie bg-dexopt.

Wczytywanie z innego profilu profilu podstawowego

W tej sekcji opisaliśmy, jak zainstalować profil podstawowy dla pliku APK.

Przesyłaj na: androidx.profileinstaller

Na urządzeniach z interfejsem API 24 lub nowszym możesz przesłać polecenie instalacji profilu:

# Broadcast the install profile command - moves binary profile from assets
#     to a location where ART uses it for the next compile.
#     When successful, the following command prints "1":
adb shell am broadcast \
    -a androidx.profileinstaller.action.INSTALL_PROFILE \
    <pkg>/androidx.profileinstaller.ProfileInstallReceiver

# Kill the process
am force-stop <pkg>

# Compile the package based on profile
adb shell cmd package compile -f -m speed-profile <pkg>

Nie ma go w większości plików APK z profilami podstawowymi – czyli w około 77 tys. z 450 tys. aplikacji w Google Play. Można go jednak znaleźć we wszystkich plikach APK korzystających z funkcji Utwórz. Dzieje się tak, ponieważ biblioteki mogą udostępniać profile bez deklarowania zależności od ProfileInstaller. Począwszy od Jetpack, dodawane jest zależność w każdej bibliotece z profilem.

Użyj właściwości install-multiple z profgen lub DexMetaData

Na urządzeniach z interfejsem API 28 lub nowszym możesz załadować profil Baseline Profile bez konieczności używania biblioteki ProfileInstaller w aplikacji.

Aby to zrobić, użyj Profgen-cli:

profgen extractProfile \
        --apk app-release.apk \
        --output-dex-metadata app-release.dm \
        --profile-format V0_1_5_S # Select based on device and the preceding table.

# Install APK and the profile together
adb install-multiple appname-release.apk appname-release.dm

Aby umożliwić dzielenie plików APK, uruchom poprzednie kroki profilowania wyodrębniania raz na plik APK. Podczas instalacji przekaż każdy plik APK i powiązany plik .dm, upewniając się, że nazwy plików APK i .dm są takie same:

adb install-multiple appname-base.apk appname-base.dm \
appname-split1.apk appname-split1.dm

Weryfikacja

Aby sprawdzić, czy profil jest prawidłowo zainstalowany, możesz wykonać czynności opisane w artykule Ręczne pomiary ulepszeń aplikacji.

Zrzuć zawartość profilu binarnego

Aby zbadać zawartość kompaktowej wersji binarnej profilu podstawowego, użyj opcji dumpProfile Profgen-cli:

Usage: profgen dumpProfile options_list
Options:
    --profile, -p -> File path to the binary profile (always required)
    --apk, -a -> File path to apk (always required) { String }
    --map, -m -> File path to name obfuscation map { String }
    --strict, -s [true] -> Strict mode
    --output, -o -> File path for the HRF (always required) { String }
    --help, -h -> Usage info

dumpProfile potrzebuje pliku APK, ponieważ kompaktowa reprezentacja binarna przechowuje tylko przesunięcia plików DEX i dlatego potrzebuje ich do rekonstruowania nazw klas i metod.

Domyślnie włączony jest tryb ścisły, który sprawdza zgodność profilu z plikami DEX w pliku APK. Jeśli spróbujesz debugować profile wygenerowane przez inne narzędzie, mogą pojawić się błędy zgodności, które uniemożliwią przesłanie zrzutu w celu zbadania sprawy. W takich przypadkach możesz wyłączyć tryb rygorystyczny za pomocą polecenia --strict false. W większości przypadków należy jednak pozostawić tryb rygorystyczny.

Mapa zaciemniania kodu jest opcjonalna. Jeśli zostanie udostępniona, pomaga mapować zaciemnione symbole na ich wersje zrozumiałe dla człowieka, co ułatwia ich użycie.