val benchmarkRule = BenchmarkRule()
fun simpleScroll() {
benchmarkRule.measureRepeated {
// 滚动 RecyclerView 至某个条目
recyclerView.scrollBy(0, recyclerView.getLastChild().height)
}
}
示例工程: android/performance-samples
JUnit Rule API
https://developer.android.google.cn/reference/kotlin/androidx/benchmark/junit4/BenchmarkRule.html
基准测试 vs 正确性测试
一个工程里就算有数千个正确性测试,也可以轻易通过信息折叠显示在数据面板上。下面就是我们在 Jetpack 中的测试信息:
这里没有什么特别的内容,但是在减少视觉负荷方面使用了两个常见技巧。首先,这里以包和类的维度折叠了包含数千条测试信息的列表;然后,默认情况下隐藏了结果全部正确的包。就这样,数十个库里接近两万个测试结果,就被囊括到了寥寥几行文字之中。正确性测试的面板很好地控制了所展示的数据规模。
但是基准测试又如何呢?基准测试不会简单地输出通过/不通过,每个测试的结果都是一个标量,这意味着我们没法简单地将通过的结果折叠起来。我们可以看一看数据图表,也许可以对数据的模式有个直观的了解,毕竟通常情况下,基准测试的数量要远少于正确性测试...
但是您却只能看到一大堆可见噪声。就算测试结果从数千减少到数百个,直接看图表对于数据的分析依然不会有任何帮助。基准测试中保持原有性能结果的数据与测试回归的数据所占据的可视区域相同,所以我们需要把未出现测试回归的数据过滤掉 (这样测试回归的数据才能凸显出来)。
简单的回归检测方法
虽然我们一直尝试在基准测试中产生稳定且一致的结果,但是曲线的变化仍然会很大,这主要取决于工作量的大小和所运行的设备。比如说,相比于其他 CPU 工作量基准测试数据,我们发现填充视图的测试结果非常不稳定。而将阈值设置为百分之一并不能在每个测试中获得理想的结果,但是我们也不希望把设定阈值的 (或者基线) 的负担施加在基准测试的作者身上,因为这个工作不但繁琐,而且随着分析规模的增加,其扩展性也相对较差。
△ RecyclerView、Ads-identifier 以及 Room 的一次基准测试中出现的所有峰值——我们不希望将其作为回归模型报告出来
综上所述,我们不能仅通过第 N 次和 N - 1 次 Build 结果就定位一个测试回归问题——我们需要更多上下文信息来辅助决策。
分步拟合,一个可扩展的解决方案
△ 上下文可以揭示出性能退化幅度较大的位置可能只是基准化分析结果反复无常的变化而已
测试回归
https://ci.android.com/builds/branches/aosp-androidx-master-dev/grid?head=5783944&tail=5783944
后续相关的修正
https://ci.android.com/builds/branches/aosp-androidx-master-dev/grid?head=5787972&tail=5787972
宽度 (WIDTH) — 要涵盖多少个代码提交的结果
增加宽度值会降低不一致性,但是也会导致在结果变动较为频繁时难以发现测试回归——我们当前使用的宽度值是 5。阈值用于整体的敏感性控制——我们当前用的是 25。降低阈值可以看到捕捉更多的测试回归,但是也可能导致更多的误报。
如果想在您自己的 CI 中进行配置,需要:
编写一些基准测试
在真机的 CI 中运行它们, 最好有持续的性能支持
从 JSON 中收集输出指标
当一个结果准备完毕时,检查一下当宽度为两倍时的结果
预提交
对于可能中断提交补丁工作流的预提交测试,您需要对所使用的回归检测有更高的可信度。
由于单次运行基准测试并不能给我们自己带来足够的信心,所以上面的分步拟合算法是必须的。同样,我们可以通过获取更多数据来增加这方面的信心——只需要不加修改地多次运行,来检测补丁是否引入了测试回归即可。
对于每次修改代码然后进行的多次基准测试,都会增加一定的资源消耗,如果您可以接受,那么预提交就能够很好地发挥作用。
结论
Jetpack Benchmark 提供了一种从 Android 设备外获取准确性能指标的简便方法。结合上面的逐步拟合算法,您可以解决不稳定的问题,从而可以在性能问题影响到用户前发现它们的测试回归问题——就像我们在 Jetpack CI 中做的一样。
在基准测试中捕获关键的滚动界面
为与第三方库交互的关键位置和高 CPU 消耗的任务添加性能测试
要像对待测试回归问题一样对待改进——它们值得深究
延伸阅读
《在 CI 中使用 Benchmarks》
https://v.youku.com/v_show/id_XNDQxNDMwOTk1Ng==.html
我们使用 Skia Perf 应用来跟踪 AndroidX 库的性能,基准测试结果可以在 androidx-perf.skia.org 找到。由于它现在在我们的 CI 中运行,您可以看到此处描述的逐步拟合算法的实际来源。如果您想了解更多信息,Joe Gregorio 撰写的另一篇有关他们更高级的 K-means 聚类检测算法的博文,解释了 Skia 项目开发的特定问题和解决方案,这些问题和解决方案是专门为整合多种配置 (不同的操作系统和操作系统版本,CPU/GPU 芯片/驱动程序变体,编译器等) 设计的。
Skia Perf 应用
https://skia.org/dev/testing/skiaperf
androidx-perf.skia.org
https://androidx-perf.skia.org/e/
实际来源
https://github.com/google/skia-buildbot/blob/master/perf/go/stepfit/stepfit.go
K-means 聚类检测算法的博文
https://bitworking.org/news/2014/11/detecting-benchmark-regressions/
推荐阅读