手動建立及評估基準設定檔

我們強烈建議使用 Jetpack Macrobenchmark 程式庫自動產生設定檔規則,因為這樣可以減少人力作業並提高一般擴充性。不過,您可以在應用程式中手動建立及評估設定檔規則。

手動定義設定檔規則

您可以透過在 src/main 目錄中建立名為 baseline-prof.txt 的檔案,手動定義應用程式或程式庫模組中的設定檔規則。這就是存放 AndroidManifest.xml 檔案的同一個資料夾。

在這個檔案中,每一行會指定一個規則。每個規則都代表一種模式,用來比對應用程式/程式庫中需要最佳化的方法或類別。

使用 adb shell profman --dump-classes-and-methods 時,這些規則的語法是一個人類可讀的 ART 設定檔格式 (HRF) 超集。語法和描述元及特徵標記的語法類似,但允許使用萬用字元來簡化規則編寫程序。

下列範例列出 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;

您可以嘗試修改這個範例 Compiler Explorer 專案中的設定檔規則。請注意,編譯器探索器只支援人類可讀的 ART 設定檔格式 (HRF),因此不支援萬用字元。

規則語法

這些規則能以兩種模式之一來指定方法或類別:

[FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE]

類別規則使用以下模式:

[CLASS_DESCRIPTOR]

請參閱下表的詳細說明:

語法 說明
FLAGS 代表 HSP 的一或多個字元,點出此方法必須標記為 HotStartupPost Startup,與啟動類型相關。

具有 H 標記表示這是個「熱門」方法;意即在應用程式生命週期間,系統會多次呼叫這個方法。

具有 S 標記表示系統會在應用程式啟動時,呼叫這個方法。

具有 P 標記表示系統會在應用程式啟動後,呼叫這個方法。

在這個檔案中可以看到的類別,代表會在程式啟動時使用。必須在堆積中預先分配好,才能避免無謂的類別載入作業。ART 編譯器採用多種最佳化策略:例如上述的 AOT 編譯方法,及在已產生的 AOT 檔案內,就版面配置進行最佳化處理。
CLASS_DESCRIPTOR 指定方法類別的描述元。舉例來說,androidx.compose.runtime.SlotTable 的描述元是 Landroidx/compose/runtime/SlotTable;。系統會依據 Dalvik Executable (DEX) 格式在開頭加上 L 字。
METHOD_SIGNATURE 方法的特徵標記,包括名稱、參數類型和傳回類型。舉例來說,LayoutNode 上的

// LayoutNode.kt

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

帶有 isPlaced()Z 特徵標記。

這些模式可納入萬用字元,這樣一條規則就能涵蓋多種方法或類別。如果使用 Android Studio 的規則語法編寫時,需要引導或協助,請參考 Android 基準設定檔外掛程式。

萬用字元規則的範例如下:

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

基準設定檔規則的支援類型

基準設定檔規則支援下列類型。如要進一步瞭解這些類型,請參考 Dalvik Executable (DEX) 格式

字元 類型 說明
B byte 有符號的位元組
C char 以 UTF-16 編碼的萬國碼字元碼點
D double 雙精度浮點值
F float 單精度浮點值
I int 整數
J long 長整數
S short 有符號的短整數
V void 無效
Z 布林值 true 或 false
L (類別名稱) 參照 類別名稱的例子

此外,程式庫也可以規範放在 AAR 構件中的規則。當您建構 APK 以納入這些構件時,系統會將規則合併在一起 (類似於資訊清單的合併方式),並編譯為 APK 專用的精簡二進位 ART 設定檔。

當裝置搭載 Android 9 (API 級別 28),並在安裝期間使用 APK 預先編譯特定的應用程式子集,ART 就會使用這個設定檔。若裝置搭載 Android 7 (API 級別 24) 並使用 ProfileInstaller,ART 也會使用這個設定檔。

手動收集基準設定檔

您可以手動產生基準設定檔,而無須設定 Macrobenchmark 程式庫,並為關鍵使用者旅程建立 UI 自動化動作。雖然我們建議使用 Macrobenchmark,但不一定適用於所有情況。舉例來說,如果您使用非 Gradle 建構系統,就無法使用基準設定檔 Gradle 外掛程式。在這種情況下,您可以手動收集基準設定檔規則。如果您使用搭載 API 34 以上版本的裝置或模擬器,這項操作就會變得簡單許多。雖然在較低的 API 級別中仍可執行此操作,但需要 Root 存取權,且您必須使用執行 AOSP 映像檔的模擬器。您可以按照下列步驟直接收集規則:

  1. 在測試裝置上安裝應用程式的發布版本。應用程式建構類型必須經過 R8 最佳化,且無法進行偵錯,才能取得準確的設定檔。
  2. 請確認設定檔尚未編譯。

    API 34 以上版本

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

    API 33 以下

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

    如果 APK 依附於 Jetpack Profile Installer 程式庫,該程式庫會在首次啟動 APK 時啟動設定檔。這可能會干擾設定檔產生程序,因此請使用下列指令停用這項功能:

    adb shell am broadcast -a androidx.profileinstaller.action.SKIP_FILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver
  3. 執行應用程式,並手動瀏覽要收集設定檔的關鍵使用者旅程。
  4. 請 ART 轉儲設定檔。如果您的 APK 依附於 Jetpack Profile Installer 程式庫,請使用該程式庫傾印設定檔:

    adb shell am broadcast -a androidx.profileinstaller.action.SAVE_FILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver
    adb shell am force-stop $PACKAGE_NAME
    如果您沒有使用設定檔安裝工具,請使用下列指令在模擬器上手動轉儲設定檔:

    adb root
    adb shell killall -s SIGUSR1 $PACKAGE_NAME
    adb shell am force-stop $PACKAGE_NAME
  5. 等待至少五秒,讓設定檔產生作業完成。
  6. 將產生的二進位設定檔轉換為文字:

    API 34 以上版本

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

    API 33 以下

    判斷是否已建立參考設定檔或目前設定檔。參考設定檔位於以下位置:

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

    目前的設定檔位於以下位置:

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

    判斷 APK 的位置:

    adb root
    adb shell pm path $PACKAGE_NAME

    執行轉換:

    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. 使用 adb 從裝置擷取已傾印的設定檔:

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

這會擷取產生的設定檔規則,並將其安裝到應用程式模組。下次建構應用程式時,系統就會納入基準設定檔。如要確認這項資訊,請按照「安裝問題」一節中的步驟操作。

手動評估應用程式改善情形

強烈建議您透過基準測試評估應用程式改善情形。不過,如要手動評估改善程度,您可以先評估未經最佳化的應用程式啟動效能,當做參考。

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"

接著,側載基準設定檔。

# 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

為確認套件在安裝時是否已完成最佳化,請執行下列指令:

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

輸出結果必須顯示套件已完成編譯:

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

現在可以像之前一樣評估應用程式啟動效能,但不會重設已編譯的狀態。請確保不會重設套件的已編譯狀態。

# 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"

基準設定檔和 Profgen

本節說明「Profgen」工具在為基準設定檔建構精簡二進位檔版本時執行的動作。

Profgen-cli 可協助您編譯設定檔、自我檢查,以及轉譯 ART 設定檔,無論目標 SDK 版本為何,都能在 Android 裝置上安裝設定檔。

Profgen-cli 是 CLI,可將基準設定檔的 HRF 編譯為其本身的編譯格式。CLI 也會做為 Android SDK 的一部分傳送至 cmdline-tools 存放區。

studio-main 分支版本提供以下功能:

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

使用 Profgen-cli 建構密集二進位設定檔

Profgen-cli 可用的指令為 binvalidatedumpProfile。如要查看可用的指令,請使用 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

使用 bin 指令產生精簡二進位設定檔。以下是叫用範例:

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

如要查看可用的選項,請使用 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

第一個引數代表 baseline-prof.txt HRF 的路徑。

Profgen-cli 也需要 APK 的發布子版本路徑,以及在使用 R8 或 Proguard 時,用於將 APK 模糊處理的模糊處理對應。這樣一來,profgen 就能在建構已編譯的設定檔時,將 HRF 中的來源符號轉譯成對應的模糊化名稱。

ART 設定檔格式沒有前瞻相容或回溯相容的性質,因此請提供設定檔格式,讓 profgen 封裝設定檔中繼資料 (profm),方便您視需要將 ART 設定檔轉碼為另一種格式。

設定檔格式和平台版本

選擇設定檔格式時,可用的選項如下:

設定檔格式 平台版本 API 級別
v0_1_5_s Android S+ 31 以上
v0_1_0_p Android P、Q 和 R 28 到 30
v0_0_9_omr1 Android O MR1 27
v0_0_5_o Android O 26
v0_0_1_n Android N 24 到 25

baseline.profbaseline.profm 輸出檔案複製到 APK 中的 assetsdexopt 資料夾。

模糊處理對應

只有在 HRF 使用來源符號時,才需要提供模糊處理對應。如果 HRF 是由經過模糊處理的發布子版本產生,且不一定需要對應,可以忽略該選項,並將輸出內容複製到 assetsdexopt 資料夾。

以傳統方式安裝基準設定檔

一般而言,有兩種方法可將基準設定檔傳送到裝置。

install-multiple 與 DexMetadata 搭配使用

在搭載 API 28 以上版本的裝置上,Play 用戶端會下載所安裝 APK 版本的 APK 和 DexMetadata (DM) 酬載。該 DM 包含傳遞至裝置上套件管理工具的設定檔資訊。

APK 和 DM 會在單次安裝工作階段中,採用以下形式安裝:

adb install-multiple base.apk base.dm

Jetpack ProfileInstaller

在搭載 API 級別 29 以上版本的裝置上,Jetpack ProfileInstaller 程式庫提供了另一種機制,可在 APK 安裝到裝置上後,「安裝」封裝至 assetsdexopt 中的設定檔。ProfileInstaller 是由 ProfileInstallReceiver 或應用程式直接叫用。

ProfileInstaller 程式庫會根據目標裝置的 SDK 版本對設定檔進行轉碼,並將設定檔複製到裝置上的 cur 目錄 (裝置上 ART 設定檔的套件專屬暫存目錄)。

一旦裝置處於閒置狀態,裝置上名為 bg-dexopt 的程序就會編譯設定檔。

側載基準設定檔

本節說明如何在具備 APK 的情況下安裝基準設定檔。

使用 androidx.profileinstaller 播送

在搭載 API 24 以上版本的裝置上,您可以播送指令來安裝設定檔:

# 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>

大多數包含基準設定檔的 APK 中都沒有 ProfileInstaller (Play 中有約 45 萬個應用程式,其中約 7.7 萬個應用程式有 ProfileInstaller),但其實每個使用 Compose 的 APK 中都有 ProfileInstaller。這是因為程式庫可提供設定檔,而不必宣告 ProfileInstaller 的依附元件。從 Jetpack 開始,每個有設定檔的程式庫都會新增依附元件。

install-multiple 與 Profgen 或 DexMetaData 搭配使用

在搭載 API 28 以上版本的裝置上,您不必在應用程式中安裝 ProfileInstaller 程式庫,就可以在應用程式中側載基準設定檔。

方法是使用 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

如要支援 APK 分割功能,請分別為每個 APK 執行一次上述的擷取設定檔步驟。安裝時請傳遞每個 APK 和相關聯的 .dm 檔案,確保 APK 和 .dm 名稱相符:

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

驗證

如要驗證是否已正確安裝設定檔,請按照「手動評估應用程式改善情形」中的步驟操作。

傾印二進位設定檔的內容

如果想要自我檢查基準設定檔的精簡二進位檔版本內容,請使用 Profgen-cli dumpProfile 選項:

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 需要 APK,因為精簡二進位檔表示法只會儲存 DEX 偏移,因此需要重新建構類別和方法名稱。

根據預設,系統會啟用嚴格模式,對 APK 中 DEX 檔案進行設定檔相容性檢查。如果您嘗試對其他工具產生的設定檔進行偵錯,可能會發生相容性錯誤,導致您無法傾印檔案以供調查。在這種情況下,您可以使用 --strict false 停用嚴格模式。但在大部分情況下,應保持啟用嚴格模式。

您可以選用模糊處理對應,此模式可將模糊處理的符號重新對應到人類可讀的版本,以便使用。