撰寫 Microbenchmark

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

透過新增變更至應用程式程式碼,即可快速開始使用 Microbenchmark 程式庫。如要正確設定專案,請按照需要更複雜變更程式碼集的完整設定一節操作。

快速入門

本節提供試用基準化和一次性測量的快速導覽,您無須將程式碼移入模組。為了獲得準確的效能結果,以下步驟包含停用應用程式的偵錯功能,因此您應在本機作業副本中保留此功能,而不需要變更來源控制系統。

如要快速執行一次性基準化,請執行下列步驟:

  1. 將程式庫新增至模組的 build.gradle 檔案:

    project_root/module_dir/build.gradle

    Groovy

    dependencies {
        androidTestImplementation 'androidx.benchmark:benchmark-junit4:1.1.0-beta03'
    }
    

    Kotlin

    dependencies {
        androidTestImplementation("androidx.benchmark:benchmark-junit4:1.1.0-beta03")
    }
    
  2. 如要停用測試資訊清單中的偵錯功能,請更新 <application> 元素,暫時強制停用偵錯功能:

    project_root/module_dir/src/androidTest/AndroidManifest.xml

    <!-- Important: disable debuggable for accurate performance results -->
    <application
        android:debuggable="false"
        tools:ignore="HardcodedDebugMode"
        tools:replace="android:debuggable"/>
    
  3. 如要新增基準,請在 androidTest 目錄中的測試檔案中新增 BenchmarkRule 例項。如要進一步瞭解編寫基準的資訊,請參閱建立 Microbenchmark 類別

    下列程式碼片段說明如何在 JUnit 測試中新增基準:

    Kotlin

    @RunWith(AndroidJUnit4::class)
    class SampleBenchmark {
        @get:Rule
        val benchmarkRule = BenchmarkRule()
    
        @Test
        fun benchmarkSomeWork() {
            benchmarkRule.measureRepeated {
                doSomeWork()
            }
        }
    }
    

    Java

    @RunWith(AndroidJUnit4.class)
    class SampleBenchmark {
        @Rule
        public BenchmarkRule benchmarkRule = new BenchmarkRule();
    
        @Test
        public void benchmarkSomeWork() {
            final BenchmarkState state = benchmarkRule.getState();
            while (state.keepRunning()) {
                doSomeWork();
            }
        }
    }
    

如要瞭解如何編寫基準,請略過至建立 Microbenchmark 類別 section.

完整專案設定

如要設定一般基準化,而非一次性基準化,請將基準隔離到各自的模組中。這可確保其設定 (例如將 debuggable 設為 false) 與一般測試各自獨立。

由於 Microbenchmark 直接執行您的程式碼,因此您必須將要做為基準的程式碼放入獨立的 Gradle 模組,並設定對模組的依附元件,如下圖所示。

包含 :app、:microbenchmark 和 :benchmarkable Gradle 模組的應用程式結構,讓 Microbenchmark 能夠成為 :benchmarkable 模組中的基準程式碼。

如要新增 Gradle 模組,您可以使用 Android Studio 中的模組精靈。此精靈會建立為基準預先設定的模組,並新增基準目錄,同時將 debuggable 設為 false

Bumblebee (或更新版本)

  1. 在 Android Studio 的「Project」(專案)面板中的專案或模組,按一下滑鼠右鍵您,然後按一下「Add」(新增) >「Module」(模組)
  2. 在「Templates」(範本) 窗格中選取「Benchmark」(基準)
  3. 選取 Microbenchmark 做為基準模組類型。
  4. 輸入模組名稱的 Microbenchmark。
  5. 按一下「Finish」(完成)
  6. 設定新的程式庫模組

Arctic Fox

  1. 在 Android Studio 的「Project」(專案)面板中的專案或模組,按一下滑鼠右鍵您,然後按一下「Add」(新增) >「Module」(模組)
  2. 在「Templates」(範本) 窗格中選取「Benchmark」(基準)
  3. 輸入模組名稱的 Microbenchmark。
  4. 按一下「Finish」(完成)
  5. 設定新的程式庫模組

建立模組後,請變更其 build.gradle 檔案,並將 testImplementation 新增至含有基準程式碼的模組:

Groovy

dependencies {
    // Note, that the module name may be different
    androidTestImplementation project(':benchmarkable')
}

Kotlin

dependencies {
    // Note, that the module name may be different
    androidTestImplementation(project(":benchmarkable"))
}

建立 Microbenchmark 類別

基準屬於標準檢測設備測試。如要建立基準,請使用程式庫提供的 BenchmarkRule 類別。如要基準化活動,請使用 ActivityTestRuleActivityScenarioRule。如要基準化 UI 程式碼,請使用 @UiThreadTest

下列程式碼代表範本基準:

Kotlin

@RunWith(AndroidJUnit4::class)
class SampleBenchmark {
    @get:Rule
    val benchmarkRule = BenchmarkRule()

    @Test
    fun benchmarkSomeWork() {
        benchmarkRule.measureRepeated {
            doSomeWork()
        }
    }
}
    

Java

@RunWith(AndroidJUnit4.class)
class SampleBenchmark {
    @Rule
    public BenchmarkRule benchmarkRule = new BenchmarkRule();

    @Test
    public void benchmarkSomeWork() {
        final BenchmarkState state = benchmarkRule.getState();
        while (state.keepRunning()) {
            doSomeWork();
        }
    }
}
    

停用設定時間

您可以停用不想透過 runWithTimingDisabled{} 區塊測量的程式碼區段時間。這些區段通常代表每次基準疊代時需要執行的部分程式碼。

Kotlin

// using random with the same seed, so that it generates the same data every run
private val random = Random(0)

// create the array once and just copy it in benchmarks
private val unsorted = IntArray(10_000) { random.nextInt() }

@Test
fun benchmark_quickSort() {
    // ...
    benchmarkRule.measureRepeated {
        // copy the array with timing disabled to measure only the algorithm itself
        listToSort = runWithTimingDisabled { unsorted.copyOf() }

        // sort the array in place and measure how long it takes
        SortingAlgorithms.quickSort(listToSort)
    }

    // assert only once not to add overhead to the benchmarks
    assertTrue(listToSort.isSorted)
}
    

Java

private final int[] unsorted = new int[10000];

public SampleBenchmark() {
    // using random with the same seed, so that it generates the same data every run
    Random random = new Random(0);

    // create the array once and just copy it in benchmarks
    Arrays.setAll(unsorted, (index) -> random.nextInt());
}

@Test
public void benchmark_quickSort() {
    final BenchmarkState state = benchmarkRule.getState();

    int[] listToSort = new int[0];

    while (state.keepRunning()) {
        
        // copy the array with timing disabled to measure only the algorithm itself
        state.pauseTiming();
        listToSort = Arrays.copyOf(unsorted, 10000);
        state.resumeTiming();
        
        // sort the array in place and measure how long it takes
        SortingAlgorithms.quickSort(listToSort);
    }

    // assert only once not to add overhead to the benchmarks
    assertTrue(SortingAlgorithmsKt.isSorted(listToSort));
}
    

請盡量減少在 measureRepeated 區塊內和 runWithTimingDisabled 內部執行的作業量。measureRepeated 區塊會多次執行,且會影響執行基準所需的總時間。如果需要驗證某些基準測試結果,您可以聲明最後一個結果,而不是在每次基準疊代時執行。

執行基準測試

在 Android Studio 中,使用測試類別或方法旁的溝槽動作執行任何 @Test 的基準測試,如下圖所示。

使用測試類別旁的溝槽動作執行 Microbenchmark 測試

或者,從指令列執行 connectedCheck,以從指定的 Gradle 模組執行所有測試:

./gradlew benchmark:connectedCheck

或單一測試:

./gradlew benchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.benchmark.SampleBenchmark#benchmarkSomeWork

基準測試結果

Microbenchmark 順利執行後,就能直接在 Android Studio 中顯示指標,以及提供其他指標和裝置資訊的完整基準報表,而裝置資訊則以 JSON 格式提供。androidx.benchmark Gradle 外掛程式根據預設為啟用 JSON 輸出。

Microbenchmark 結果

根據預設,JSON 報表會寫入測試 APK 的外部共用媒體資料夾中的裝置端,通常位於 /storage/emulated/0/Android/media/app_id/app_id-benchmarkData.json

此外,JSON 報表也會自動從裝置複製到主機。這些寫入主體機器的內容如下:

project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/app_id-benchmarkData.json

設定錯誤

程式庫會偵測下列條件,確保您的專案和環境都設定妥當,以釋出準確效能:

  • 可進行偵錯設定為 false
  • 正在使用的實體裝置 (不支援模擬器)。
  • 已啟用 Root 權限的裝置時鐘會遭到鎖定。
  • 裝置具備足夠電池電量 (至少 25%)。

如果以上任何檢查失敗,基準都會回報錯誤,避免進行不正確的測量。

如要略過警告的特定錯誤類型,並避免警告中止基準測試,請透過以半形逗號分隔的清單將錯誤類型傳遞至檢測引數 androidx.benchmark.suppressErrors

您可以透過您的 Gradle 指令碼設定,如下所示:

Groovy

android {
    defaultConfig {
       …
      testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE,LOW-BATTERY"
    }
}

Kotlin

android {
    defaultConfig {
       …
      testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE,LOW-BATTERY"
    }
}

封鎖錯誤時,基準就能以錯誤設定的狀態執行,且基準的輸出內容則會透過含錯誤的預先測試名稱刻意重新命名。例如,在上述程式碼片段中,執行封鎖的可進行偵錯基準將在 DEBUGGABLE_ 前面加上測試名稱。