您可以在持续集成 (CI) 中运行基准测试,以跟踪性能随时间的变化,并在应用发布之前识别性能下降或改进。此页面提供有关在 CI 中进行基准测试的基本信息。
在开始在 CI 中进行基准测试之前,请考虑捕获和评估结果与常规测试有何不同。
模糊结果
虽然基准测试是检测测试,但结果不仅仅是通过或失败。基准测试会为其运行所在的给定设备提供时间测量结果。随着时间的推移绘制结果图表,您可以监控变化并观察测量系统中的噪声。
使用真实设备
在物理 Android 设备上运行基准测试。虽然它们可以在模拟器上运行,但这强烈不建议这样做,因为它不能代表真实的用户信息,而是提供与主机操作系统和硬件功能相关的数字。请考虑使用真实设备或允许您在真实设备上运行测试的服务,例如 Firebase Test Lab。
运行基准测试
将基准测试作为 CI 管道的一部分运行可能与从 Android Studio 本地运行有所不同。在本地,您通常使用一个 Gradle connectedCheck
任务运行 Android 集成测试。此任务会自动构建您的 APK 和测试 APK,并在连接到 CI 服务器的设备上运行测试。在 CI 中运行时,此流程通常需要分成不同的阶段。
构建
对于 Microbenchmark 库,运行 Gradle 任务 assemble[VariantName]AndroidTest
,这将创建包含您的应用程序代码和被测代码的测试 APK。
或者,Macrobenchmark 库要求您分别构建目标 APK 和测试 APK。因此,运行 :app:assemble[VariantName]
和 :macrobenchmark:assemble[VariantName]
Gradle 任务。
安装和运行
这些步骤通常无需运行 Gradle 任务即可完成。请注意,根据您是否使用允许您在真实设备上运行测试的服务,它们可能会被抽象化。
对于安装,请使用 adb install
命令并指定测试 APK 或目标 APK。
运行 adb shell am
instrument 命令以运行所有基准测试
adb shell am instrument -w com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner
使用 Macrobenchmark 库时,请使用常规的 androidx.test.runner.AndroidJUnitRunner
作为 Instrumentation Runner。
您可以使用 -e
参数传递与 Gradle 配置中相同的 Instrumentation 参数。有关所有 Instrumentation 参数选项,请参阅 微基准测试 Instrumentation 参数 或 为 Macrobenchmark 添加 Instrumentation 参数。
例如,您可以设置 dryRunMode
参数,以便在拉取请求验证过程中运行微基准测试。启用此标志后,微基准测试仅运行单循环,验证其运行是否正确,但不会花费太长时间执行。
adb shell am instrument -w -e "androidx.benchmark.dryRunMode.enable" "true" com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner
有关如何从命令行运行 Instrumentation 测试的更多信息,请参阅 使用 ADB 运行测试。
锁定时钟
Microbenchmark Gradle 插件提供命令 ./gradlew lockClocks
用于锁定已 root 设备的 CPU 时钟。如果您有权访问已 root 的设备(例如“userdebug”版本),这对于确保稳定性非常有用。您可以使用 lockClocks.sh
shell 脚本复制此操作,该脚本位于 库的源代码 中。
您可以直接从 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
如果您直接在主机上运行 shell 脚本,它会将这些命令分派到已连接的设备。
有关锁定 CPU 时钟为何有帮助的更多信息,请参阅如何 获得一致的基准测试结果。
收集结果
基准测试库在每次基准测试运行后,会将测量结果(以 JSON 格式)以及性能分析跟踪输出到 Android 设备上的目录中。Macrobenchmark 库会输出多个 Perfetto 跟踪文件:每个 MacrobenchmarkRule.measureRepeated
循环的每个已测量迭代一个。Microbenchmark 然而,只为每个 BenchmarkRule.measureRepeated
的所有迭代创建一个跟踪文件。性能分析 跟踪文件也会输出到同一目录。
保存和查找文件
如果您使用 Gradle 运行基准测试,这些文件将自动复制到主机计算机的输出目录下的 build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/
。
如果直接使用 adb
命令运行,则需要手动提取文件。默认情况下,报告保存在被测应用外部存储的媒体目录中。为方便起见,库会将文件的路径打印到 Logcat。请注意,输出文件夹可能因运行基准测试的 Android 版本而异。
Benchmark: writing results to /storage/emulated/0/Android/media/com.example.macrobenchmark/com.example.macrobenchmark-benchmarkData.json
您还可以使用 Instrumentation 参数 additionalTestOutputDir
配置基准测试报告在设备上的保存位置。您的应用必须可以写入此文件夹。
adb shell am instrument -w -e additionalTestOutputDir /sdcard/Download/ com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner
在 Android 10(API 级别 29)及更高版本上,您的应用测试默认情况下在存储沙箱中运行,这会阻止您的应用访问应用特定目录之外的文件。要能够保存到全局目录(例如 /sdcard/Download
),请传递以下 Instrumentation 参数
-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
}
]
}
其他资源
- 有关如何检测性能回归的指导,请参阅 在 CI 中使用基准测试来对抗回归。
- 要了解如何使用 Firebase Test Lab 设置 Github Actions,请参阅 为 CI 设置 Jetpack Macrobenchmarks
推荐内容
- 注意:当 JavaScript 关闭时显示链接文本
- SQLite 性能最佳实践
- 创建和测量无需 Macrobenchmark 的基线配置文件
- 卡住的部分唤醒锁