要了解如何通过对应用程序代码添加更改来使用 Microbenchmark 库,请参阅 快速入门 部分。要了解如何完成对代码库进行更复杂更改的完整设置,请参阅 完整项目设置 部分。
快速入门
本节介绍如何在不将代码移动到模块的情况下尝试基准测试并运行一次性测量。为了获得准确的性能结果,这些步骤涉及禁用应用程序中的调试,因此请将此操作保存在本地工作副本中,而不要将更改提交到源代码控制系统。
要执行一次性基准测试,请执行以下操作
将库添加到模块的
build.gradle
或build.gradle.kts
文件中Kotlin
dependencies { implementation("androidx.benchmark:benchmark-junit4:1.2.4") }
Groovy
dependencies { implementation 'androidx.benchmark:benchmark-junit4:1.2.4' }
使用
implementation
依赖项而不是androidTestImplementation
依赖项。如果使用androidTestImplementation
,基准测试将无法运行,因为库 清单 未合并到应用程序清单中。更新
debug
构建类型,使其不可调试Kotlin
android { ... buildTypes { debug { isDebuggable = false } } }
Groovy
android { ... buildTypes { debug { debuggable false } } }
将
testInstrumentationRunner
更改为AndroidBenchmarkRunner
Kotlin
android { ... defaultConfig { testInstrumentationRunner = "androidx.benchmark.junit4.AndroidBenchmarkRunner" } }
Groovy
android { ... defaultConfig { testInstrumentationRunner "androidx.benchmark.junit4.AndroidBenchmarkRunner" } }
在
androidTest
目录中的测试文件中添加BenchmarkRule
的实例,以添加您的基准测试。有关编写基准测试的更多信息,请参阅 创建微基准测试类。以下代码片段演示了如何将基准测试添加到工具测试中
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() { BenchmarkRuleKt.measureRepeated( (Function1<BenchmarkRule.Scope, Unit>) scope -> doSomeWork() ); } } }
要了解如何编写基准测试,请跳到 创建微基准测试类。
完整项目设置
要设置定期基准测试而不是一次性基准测试,请将基准测试隔离到它们自己的模块中。这有助于确保它们的配置(例如,将 debuggable
设置为 false
)与常规测试分开。
由于 Microbenchmark 直接运行您的代码,因此将要基准测试的代码放在单独的 Gradle 模块中,并设置对该模块的依赖项,如 figure 1 所示。
若要添加新的 Gradle 模块,您可以使用 Android Studio 中的模块向导。向导会创建一个为基准测试预配置的模块,其中添加了基准测试目录,并将 debuggable
设置为 false
。
在 Android Studio 的“项目”面板中右键单击您的项目或模块,然后单击“新建 > 模块”。
在“模板”窗格中选择“基准测试”。
选择“Microbenchmark”作为基准测试模块类型。
为模块名称键入“microbenchmark”。
单击“完成”。
创建模块后,修改其 build.gradle
或 build.gradle.kts
文件,并将 androidTestImplementation
添加到包含要基准测试代码的模块。
Kotlin
dependencies { // The module name might be different. androidTestImplementation(project(":benchmarkable")) }
Groovy
dependencies { // The module name might be different. androidTestImplementation project(':benchmarkable') }
创建 Microbenchmark 类
基准测试是标准的 Instrumentation 测试。若要创建基准测试,请使用库提供的 BenchmarkRule
类。若要基准测试活动,请使用 ActivityScenario
或 ActivityScenarioRule
。若要基准测试 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() { // Use random with the same seed, so that it generates the same data every // run. Random random = new Random(0); // Create the array once and 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
一样运行您的基准测试,使用测试类或方法旁边的代码段操作,如图 3 所示。
或者,从命令行运行 connectedCheck
来运行指定 Gradle 模块中的所有测试。
./gradlew benchmark:connectedCheck
或单个测试
./gradlew benchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.benchmark.SampleBenchmark#benchmarkSomeWork
基准测试结果
Microbenchmark 运行成功后,指标会直接显示在 Android Studio 中,并且完整基准测试报告(包括其他指标和设备信息)以 JSON 格式提供。
JSON 报告和任何性能分析跟踪也会自动从设备复制到主机。这些文件在主机的以下位置写入
project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/
默认情况下,JSON 报告会写入设备上的测试 APK 的外部共享媒体文件夹,该文件夹通常位于 /storage/emulated/0/Android/media/**app_id**/**app_id**-benchmarkData.json
。
配置错误
库会检测以下条件,以确保您的项目和环境已为发布版本的准确性能做好准备。
- 将
debuggable
设置为false
。 - 正在使用物理设备(不支持模拟器)。
- 如果设备已植根,则时钟已锁定。
- 设备上的电池电量充足,至少为 25%。
如果上述任何检查失败,基准测试会报告错误,以防止不准确的测量结果。
若要将特定错误类型抑制为警告,并防止它们停止基准测试,请将错误类型以逗号分隔的列表形式传递给 Instrumentation 参数 androidx.benchmark.suppressErrors
。
您可以从您的 Gradle 脚本中设置此项,如以下示例所示
Kotlin
android { defaultConfig { … testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE,LOW-BATTERY" } }
Groovy
android { defaultConfig { … testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE,LOW-BATTERY" } }
您也可以从命令行抑制错误
$ ./gradlew :benchmark:connectedCheck -P andoidtestInstrumentationRunnerArguments.androidx.benchmark.supperssErrors=DEBUGGABLE,LOW-BATTERY
抑制错误可以让基准测试在配置不正确的状态下运行,并且基准测试的输出会故意通过在测试名称前面加上错误来重命名。例如,如果在先前代码片段中抑制的情况下运行可调试基准测试,测试名称会以 DEBUGGABLE_
开头。
为您推荐
- 注意:当 JavaScript 关闭时,链接文本会显示。
- 编写 Macrobenchmark
- 在没有 Gradle 的情况下构建 Microbenchmarks
- 创建基线配置文件 {:#creating-profile-rules}