在持續整合中執行基準測試

你可以在持續整合 (CI) 中執行基準測試,以追蹤應用程式的效能變化,並在應用程式尚未發布前找出效能迴歸問題 (或改善)。本頁面提供有關 CI 基準化的基本資訊。

在開始 CI 基準化前,請先思考如何擷取和評估與一般測試不同的結果。

模糊結果

儘管基準測試屬於檢測設備測試,但結果不代表通過/失敗。基準測試為指定執行的裝置提供時序量測。 您可利用一段時間的繪製結果監控測量系統中的變化並觀察雜訊。

使用實際裝置

基準測量應在實體 Android 裝置上執行。儘管可以在模擬器上執行,但強烈建議不要採用此方式,因為這無法反映實際的使用者體驗,而是提供與主機作業系統和硬體功能相關的數字。建議您使用真實裝置或服務,在真實的裝置上執行測試,例如 Firebase Test Lab

執行基準測試

做為 CI 管道一部分執行的基準測試可能與在 Android Studio 本機執行的基準測試不同。在本機,您通常會執行含有一項 Gradle connectedCheck 工作的 Android 整合測試。這項工作會自動建立 APK 並進行測試,並在目前已連結的裝置上執行測試。在 CI 中執行時,這個流程通常需要分成不同的階段。

建構

如為 Microbenchmark 程式庫,請執行 Gradle 工作 assemble[VariantName]AndroidTest,這會建立含應用程式程式碼和已測試程式碼的測試 APK。

此外,Macrobenchmark 程式庫必須分別建立目標 APK 和測試 APK。因此,請執行 :app:assemble[VariantName]:macrobenchmark:assemble[VariantName] Gradle 工作。

安裝及執行

這些步驟通常不需要執行 Gradle 工作就能完成。請注意,系統可以擷取這些 Gradle 工作,視您使用的服務是否能在實際裝置上執行測試而定。

如要安裝,請使用 adb install 指令並指定測試 APK (或目標 APK)。

執行 adb shell am 檢測指令,以執行所有基準測試。

adb shell am instrument -w com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner

請注意,使用 Macrobenchmark 程式庫時,請使用一般的 androidx.test.runner.AndroidJUnitRunner 做為檢測執行器。

您可使用 -e 引數來傳遞和 Gradle 設定中相同的檢測引數。如需所有檢測引數選項資訊,請查看微基準測試巨集基準測試頁面。

例如,您可以設定 dryRunMode 引數來執行微基準測試,作為 提取要求驗證流程中的一部分。啟用此旗標後,微基準測試就只會在單一迴圈中執行,藉此驗證執行是否正確,但執行時間不得過長。

adb shell am instrument -w -e "androidx.benchmark.dryRunMode.enable" "true" com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner

如要進一步瞭解如何透過指令列執行檢測設備測試,請參閱使用 ADB 執行測試

鎖定時鐘

Microbenchmark Gradle 外掛程式提供 ./gradlew lockClocks 指令來鎖定已解鎖裝置的 CPU 時鐘。在存取已解鎖裝置時 (例如「userdebug」建構作業) 這對確保穩定性而言相當實用。您可以使用程式庫來源中的 lockClocks.sh 殼層指令碼複製此項目。

您可以直接透過 Linux 或 Mac 主機執行指令碼,也可以使用少數 ADB 指令推送至裝置:

adb push path/lockClocks.sh /data/local/tmp/lockClocks.sh
adb shell /data/local/tmp/lockClocks.sh
adb shell rm /data/local/tmp/lockClocks.sh

如果您直接在主機上執行殼層指令碼,系統會將這些指令分派到已連結的裝置。

如要進一步瞭解鎖定 CPU 時鐘的重要性,請參閱如何取得一致基準一文。

收集結果

基準化程式庫會在 JSON 中輸出測量結果,並在每次執行基準測試後,將剖析追蹤記錄轉送至 Android 裝置上的目錄。巨集基準測試程式庫會輸出多個 Perfetto 追蹤檔案:每個 MacrobenchmarkRule.measureRepeated 迴圈的測量疊代次數各為一個。不過,微基準測試只會為各 BenchmarkRule.measureRepeated 的所有疊代建立一個追蹤檔。剖析追蹤檔也會輸出至相同目錄。

儲存並找到檔案

如果您使用 Gradle 執行基準測試,這些檔案會自動複製到主機裝置。如果使用 adb 指令直接執行,則必須手動提取。根據預設,這些報表皆直接儲存在裝置上,即受測試應用程式外部儲存裝置的媒體目錄中。為了方便起見,程式庫會將檔案的路徑列印至 Logcat。請注意,輸出資料夾可能會因執行基準測試的 Android 版本而有所不同。

Benchmark: writing results to /storage/emulated/0/Android/media/com.example.macrobenchmark/com.example.macrobenchmark-benchmarkData.json

您也可以使用檢測引數 additionalTestOutputDir 來設定要將基準測試報表儲存在裝置上的位置。此資料夾必須可供應用程式寫入。

adb shell am instrument -w -e additionalTestOutputDir /sdcard/Download/ com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner

在 Android 10 (API 級別 29) 以上版本中,應用程式測試根據預設會在儲存空間沙箱中執行,並導致應用程式無法存取應用程式專屬目錄以外的檔案。如要儲存至部分全域目錄 (例如 /sdcard/Download),可傳遞下列檢測引數:

-e no-isolated-storage true

您也必須在基準測試資訊清單中明確允許放行舊版儲存空間選項:

<application android:requestLegacyExternalStorage="true" ... >

詳情請參閱暫時退出限定範圍儲存空間

擷取檔案

如要取得從裝置產生的檔案,您可以使用 adb pull 指令,將指定檔案提取至主機上的目前目錄。

adb pull /storage/emulated/0/Android/media/com.example.macrobenchmark/com.example.macrobenchmark-benchmarkData.json

如要從指定資料夾擷取所有 benchmarkData,請查看下列程式碼片段:

# The following command pulls all files ending in -benchmarkData.json from the directory
# hierarchy starting at the root /storage/emulated/0/Android.
adb shell find /sdcard/Download -name "*-benchmarkData.json" | tr -d '\r' | xargs -n1 adb pull

請注意,追蹤檔 (.trace.perfetto-trace) 皆儲存在與 benchmarkData.json 相同的資料夾中,因此您可以透過相同的方式收集這些檔案。

基準資料範例

基準資料庫會產生 JSON 檔案,其中包含執行基準測試裝置及其執行實際基準測試的資訊。下列程式碼片段代表產生的 JSON 檔案。

{
    "context": {
        "build": {
            "brand": "google",
            "device": "blueline",
            "fingerprint": "google/blueline/blueline:12/SP1A.210812.015/7679548:user/release-keys",
            "model": "Pixel 3",
            "version": {
                "sdk": 31
            }
        },
        "cpuCoreCount": 8,
        "cpuLocked": false,
        "cpuMaxFreqHz": 2803200000,
        "memTotalBytes": 3753299968,
        "sustainedPerformanceModeEnabled": false
    },
    "benchmarks": [
        {
            "name": "startup",
            "params": {},
            "className": "com.example.macrobenchmark.startup.SampleStartupBenchmark",
            "totalRunTimeNs": 4975598256,
            "metrics": {
                "timeToInitialDisplayMs": {
                    "minimum": 347.881076,
                    "maximum": 347.881076,
                    "median": 347.881076,
                    "runs": [
                        347.881076
                    ]
                }
            },
            "sampledMetrics": {},
            "warmupIterations": 0,
            "repeatIterations": 3,
            "thermalThrottleSleepSeconds": 0
        }
    ]
}

其他資源