指标是指从基准测试中提取的主要信息类型。这些指标会以 List 的形式传递给 measureRepeated 函数;也就是说,您可以一次性指定多个测量指标。若要运行基准测试,必须至少提供 1 种类型的指标。
以下代码段会捕获 Jetpack Compose 延迟布局界面的帧时间和自定义的轨迹部分指标:
@OptIn(ExperimentalMetricApi::class)
@Test
fun scrollComposeList() {
benchmarkRule.measureRepeated(
// [START_EXCLUDE]
packageName = TARGET_PACKAGE,
metrics = listOf(
FrameTimingMetric(),
// Measure power usage. This is supported on Pixel 6 and later.
PowerMetric(PowerMetric.Type.Power(
mapOf(
PowerCategory.CPU to PowerCategoryDisplayLevel.TOTAL,
PowerCategory.DISPLAY to PowerCategoryDisplayLevel.TOTAL,
PowerCategory.GPU to PowerCategoryDisplayLevel.TOTAL,
PowerCategory.NETWORK to PowerCategoryDisplayLevel.TOTAL,
)
)),
// Measure custom trace sections by name EntryRow (which is added to the EntryRow composable).
// Mode.Sum measures combined duration and also how many times it occurred in the trace.
// This way, you can estimate whether a composable recomposes more than it should.
TraceSectionMetric("EntryRowCustomTrace", TraceSectionMetric.Mode.Sum),
// This trace section takes into account the SQL wildcard character %,
// which can find trace sections without the full name.
// This way, you can measure composables produced by the composition tracing
// and measure how long they took and how many times they recomposed.
// WARNING: This metric only shows results when running with composition tracing, otherwise it won't be visible in the outputs.
TraceSectionMetric("%EntryRow%", TraceSectionMetric.Mode.Sum),
),
// Try switching to different compilation modes to see the effect
// it has on frame timing metrics.
compilationMode = CompilationMode.None(),
startupMode = StartupMode.WARM, // restarts activity each iteration
iterations = DEFAULT_ITERATIONS,
// [END_EXCLUDE]
setupBlock = {
uiAutomator {
// Before starting to measure, navigate to the UI to be measured.
startIntent(Intent("$packageName.COMPOSE_ACTIVITY"))
}
}
) {
uiAutomator {
onElement { isScrollable }.fling(Direction.DOWN)
}
}
}
在以下示例中,EntryRowCustomTrace 表示使用标准 Kotlin trace(sectionName) { ... } 块封装容器在可组合项层内定义的自定义轨迹部分。如需为 TraceSectionMetric 提供数据,您必须使用标准 Jetpack 运行时 trace 块封装应用生产代码库中的目标界面组件:
@Composable
private fun EntryRow(entry: Entry, modifier: Modifier = Modifier) = trace("EntryRowCustomTrace") {
Card(modifier = modifier) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = entry.contents,
modifier = Modifier
.padding(16.dp)
.wrapContentSize()
)
Spacer(modifier = Modifier.weight(1f))
Checkbox(
checked = false,
onCheckedChange = {},
modifier = Modifier.padding(16.dp)
)
}
}
}
基准测试结果会直接输出到 Android Studio 内的 Benchmark 终端标签页,如图 1 所示。如果定义了多个指标,则所有这些指标的计算数据点都会合并到摘要窗口中。
TraceSectionMetric 和 FrameTimingMetric 的合并控制台结果。下文将详细介绍 StartupTimingMetric、FrameTimingMetric、TraceSectionMetric 和 PowerMetric。如需查看可用基准指标的完整列表,请参阅 API 参考文档中的 Metric 的子类。
StartupTimingMetric
StartupTimingMetric 可捕获提供以下值的应用启动时间指标:
timeToInitialDisplayMs:从系统收到启动 intent 到渲染目标屏幕的第一帧所用的时间。timeToFullDisplayMs:从系统收到启动 intent 到应用使用内部平台报告机制报告已完全绘制所用的时间。当跟随在完全绘制信号之后或包含该信号的第一帧完成渲染时,测量即会停止。
StartupTimingMetric 会输出启动迭代的最小值、中位数值和最大值。如需评估启动方面的改进,您应始终重点关注中位数值,因为它们能够最准确地估算典型用户启动时间。
在以 Compose 为先的架构中,请勿尝试手动调用 activity.reportFullyDrawn。请改用 Compose 安全的异步实用程序 ReportDrawn、ReportDrawnWhen 或 ReportDrawnAfter,在屏幕可组合项内自动向 Macrobenchmark 发出信号,表明异步网络数据或复杂的界面状态已完成渲染。
如需详细了解如何分析和优化初始化性能,请参阅应用启动时间。
FrameTimingMetric
FrameTimingMetric 会捕获基准测试历程(例如滚动列表或复杂的界面布局动画)所生成帧的精确时间信息,并输出以下诊断值:
frameOverrunMs:给定帧完全呈现用时与其呈现时限相差的时长。正数表示出现了丢帧和可见的卡顿。负数表示帧完成时间比子系统硬件截止时间快多少。注意:此指标仅适用于 Android 12(API 级别 31)及更高版本。frameDurationCpuMs:帧在 CPU 上主动生成所用的时间,包括主应用界面线程和 ComposeRenderThread。
系统会收集分布在第 50 个、第 90 个、第 95 个和第 99 个百分位的以上测量值:
frameDurationCpuMs P50 3.5, P90 6.0, P95 6.4, P99 11.0
frameOverrunMs P50 -11.6, P90 -7.2, P95 -7.1, P99 -1.2
优化 Jetpack Compose 布局层次结构时,请查看性能最差的帧(P95 和 P99 边界)。如果 frameOverrunMs 在高百分位时飙升为正整数,则表明在滚动动画繁重时,重组会使主线程停滞。
如需深入了解如何识别和解决帧速率缓慢的问题,请参阅 Jetpack Compose 性能。
TraceSectionMetric
TraceSectionMetric 会捕获特定轨迹部分发生的次数和执行所花费的绝对时间。对于时间跟踪,它会输出最小值、中位数和最大值(以毫秒为单位)。目标轨迹部分是通过 trace(sectionName) 函数调用或者 Trace.beginSection(sectionName) 和 Trace.endSection() 之间的较低级别块边界(或其异步变体)来定义。
EntryRowCustomTraceCount min 20.0, median 28.0, max 50.0
EntryRowCustomTraceSumMs min 34.9, median 44.4, max 66.6
默认情况下,该指标仅输出直接从您自己的应用软件包二进制文件中编译的轨迹部分。如需包含源自应用软件包边界之外的进程,请设置属性 targetPackageOnly = false。
在处理 Jetpack Compose 运行时跟踪时,您可以通过启用组合跟踪,在系统跟踪图表中显示各个可组合函数,而无需编写手动跟踪封装容器。
虽然只需向目标应用添加 androidx.compose.runtime:runtime-tracing 依赖项即可进行手动分析器轨迹分析,但在 Macrobenchmark 运行期间以编程方式捕获这些轨迹需要在基准模块内进行额外配置。
如需查看完整的设置说明,请参阅使用 Jetpack Macrobenchmark 捕获跟踪记录。
PowerMetric
PowerMetric 会捕获 Macrobenchmark 运行期间的耗电量或能量变化。每个选定类别可拆分为多个可衡量的硬件组件,而未选择的类别则分组到“未选择”类别中。
硬件要求:这些指标测量的是系统级消耗,而不是每个应用的消耗。因此,数据收集仅限于实体 Google Pixel 6、Pixel 6 Pro 和更新款实体设备。
该指标会针对每个类别输出两项衡量数据:
power<category>Uw:相应类别在测试期间的耗电量(以微瓦为单位)。energy<category>Uws:此类别在测试期间每单位时间传输的总能量(以微瓦秒为单位)。
类别包括以下各项:
CPUDISPLAYGPUGPSMEMORYMACHINE_LEARNINGNETWORKUNCATEGORIZED
对于某些类别(如 CPU),可能很难将其他进程执行的工作与您自己的应用执行的工作区分开来。请移除或限制不必要的应用和账号,最大限度地减少干扰。
powerCategoryCpuUw min 300.2, median 346.1, max 519.6
powerCategoryDisplayUw min 319.8, median 325.8, max 329.7
powerCategoryGpuUw min 18.8, median 23.3, max 36.9
powerCategoryNetworkUw min 97.3, median 123.3, max 681.3
powerTotalUw min 1234.8, median 1316.6, max 2112.4
powerUnselectedUw min 483.3, median 512.6, max 561.7
分析核心子系统
PowerMetric 会捕获所提供的电源类别在测试期间的耗电量或能量变化。您选择的每个类别可拆分为多个可衡量的子组件,未选择的类别则添加到“未选择”指标中。
终端输出会映射到您请求的配置:
powerCategoryCpuUw:CPU 在测试期间的耗电量。powerCategoryGpuUw:GPU 在测试期间的耗电量。powerUnselectedUw:初始化映射中未明确请求的所有可用硬件类别的总耗电量。
为防止在运行期间硬件轨道上出现不稳定的数据峰值,请在开始 Macrobenchmark 循环之前,将屏幕亮度锁定为固定值,保持稳定的设备温度,并关闭竞争性后台进程。
其他资源
查看内容
为你推荐
- 注意:当 JavaScript 处于关闭状态时,系统会显示链接文字
- 创建基准配置文件 {:#creating-profile-rules}
- 编写 Macrobenchmark
- 应用启动分析和优化 {:#app-startup-analysis-optimization}