Las métricas son el tipo principal de información que se extrae de tus comparativas. Se
pasan a la measureRepeated función como una List, lo que te
permite especificar varias métricas medidas a la vez. Se requiere al menos un tipo de métrica para que se ejecute la comparativa.
En el siguiente fragmento de código, se capturan las latencias de fotogramas y las métricas personalizadas de la sección de registro para una interfaz de diseño diferido de 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)
}
}
}
En el siguiente ejemplo, EntryRowCustomTrace representa una sección de registro personalizada definida dentro de las capas de elementos componibles con el wrapper de bloque trace(sectionName) { ... } estándar de Kotlin. Para proporcionar datos para TraceSectionMetric, debes incluir los componentes de IU de destino dentro de la base de código de producción de tu aplicación con el wrapper de bloque trace estándar del tiempo de ejecución de Jetpack:
@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)
)
}
}
}
Los resultados de comparativas se muestran directamente en la pestaña de la terminal Benchmark dentro de Android Studio, como se muestra en la Figura 1. Si se definen varias métricas, todos sus puntos de datos calculados se combinan en la ventana de resumen.
TraceSectionMetric y FrameTimingMetric para un diseño moderno de Compose.StartupTimingMetric, FrameTimingMetric, TraceSectionMetric y PowerMetric se explican en detalle a continuación. Para obtener una lista completa de las métricas de comparativas disponibles, consulta las subclases de Metric en la referencia de la API.
StartupTimingMetric
StartupTimingMetric captura las métricas de tiempo de inicio de la app con los siguientes valores:
timeToInitialDisplayMs: Es la cantidad de tiempo desde que el sistema recibe un intent de inicio hasta que renderiza el primer fotograma de la pantalla de destino.timeToFullDisplayMs: Es la cantidad de tiempo que transcurre desde que el sistema recibe un intent de inicio hasta que la app informa que se visualiza por completo con los mecanismos internos de informes de la plataforma. La medición se detiene cuando se completa la renderización del primer fotograma después de la señal de visualización completa (o que lo contiene).
StartupTimingMetric genera los valores mínimos, medios y máximos de las iteraciones de inicio. Para evaluar la mejora del inicio, enfócate siempre en los valores medios, ya que proporcionan la mejor estimación de los tiempos de inicio típicos del usuario.
En una arquitectura de Compose primero, no intentes invocar activity.reportFullyDrawn de forma manual. En su lugar, usa las utilidades asíncronas seguras para Compose
ReportDrawn, ReportDrawnWhen o ReportDrawnAfter
dentro de tus elementos componibles de pantalla para indicarle automáticamente a Macrobenchmark cuándo
terminaron de renderizarse tus datos de red asíncronos o los estados complejos de la IU.
Para obtener más información sobre el análisis y la optimización del rendimiento de la inicialización, consulta Tiempo de inicio de la app.
FrameTimingMetric
FrameTimingMetric captura información precisa de latencia de los fotogramas que produce un recorrido de comparativa, como el desplazamiento de una lista o una animación de diseño de la IU compleja, y genera los siguientes valores de diagnóstico:
frameOverrunMs: Es la cantidad de tiempo por el que un fotograma determinado no pudo cumplir su plazo. Los números positivos indican un fotograma descartado acompañado de un bloqueo o salto visible. Los números negativos indican cuánto más rápido se completó un fotograma en relación con el plazo de hardware del subsistema. Nota: Esta métrica solo está disponible en Android 12 (nivel de API 31) y versiones posteriores.frameDurationCpuMs: Es la cantidad de tiempo que el fotograma pasó produciéndose de forma activa en la CPU, tanto en el subproceso de IU de la aplicación principal como enRenderThreadde Compose.
Estas mediciones se recopilan en la distribución: percentil 50, 90, 95 y 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
Cuando optimices las jerarquías de diseño de Jetpack Compose, observa los fotogramas con el peor rendimiento (los límites P95 y P99). Si frameOverrunMs aumenta a números enteros positivos en los percentiles altos, indica que las recomposiciones están deteniendo el subproceso principal durante las animaciones de desplazamiento intensas.
Para obtener información más detallada sobre cómo identificar y resolver fotogramas lentos, consulta Jetpack Compose Performance.
TraceSectionMetric
TraceSectionMetric captura la cantidad de veces que se produce una sección de registro específica y la cantidad absoluta de tiempo que tarda en ejecutarse. Para el seguimiento del tiempo, muestra el tiempo mínimo, el máximo y la mediana en milisegundos. La sección de registro de destino
se define mediante una llamada a función trace(sectionName)
o los límites de bloque de nivel inferior entre
Trace.beginSection(sectionName) y Trace.endSection() o sus
variantes asíncronas.
EntryRowCustomTraceCount min 20.0, median 28.0, max 50.0
EntryRowCustomTraceSumMs min 34.9, median 44.4, max 66.6
De forma predeterminada, la métrica solo muestra las secciones de registro compiladas directamente desde los objetos binarios del paquete de tu aplicación. Para incluir procesos que se originan fuera del límite del paquete de tu app, establece la propiedad targetPackageOnly = false.
Cuando trabajes en el registro del tiempo de ejecución de Jetpack Compose, puedes mostrar funciones componibles individuales en los gráficos de registro del sistema sin escribir wrappers de registro manuales habilitando el registro de composición.
Si bien agregar la dependencia androidx.compose.runtime:runtime-tracing a tu aplicación de destino es suficiente para los registros de generador de perfiles manuales, capturar estos registros de forma programática dentro de una ejecución de Macrobenchmark requiere una configuración adicional dentro de tu módulo de comparativa.
Para obtener instrucciones de configuración completas, consulta Cómo capturar un registro con Jetpack Macrobenchmark.
PowerMetric
PowerMetric captura el cambio en la alimentación o la energía durante la ejecución de Macrobenchmark. Cada categoría seleccionada se divide en sus componentes de hardware medibles, mientras que las categorías sin seleccionar se agrupan en un bucket "sin seleccionar".
Requisito de hardware: Estas métricas miden el consumo en todo el sistema en lugar de los cálculos por app. Por lo tanto, la recopilación de datos se limita a los dispositivos físicos Google Pixel 6, Pixel 6 Pro y dispositivos físicos más nuevos.
La métrica genera dos mediciones por categoría:
power<category>Uw: La cantidad de energía consumida durante la prueba en esta categoría (medida en microvatios).energy<category>Uws: la cantidad total de energía transferida por unidad de tiempo durante la prueba en esta categoría (medida en microvatios-segundos).
Entre las categorías, se incluyen las siguientes:
CPUDISPLAYGPUGPSMEMORYMACHINE_LEARNINGNETWORKUNCATEGORIZED
Con algunas categorías, como CPU, puede ser difícil separar el trabajo que realizan otros procesos del que realiza tu propia app. Para minimizar la interferencia, quita o restringe apps y cuentas innecesarias.
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
Análisis de subsistemas principales
PowerMetric captura el cambio en la alimentación o la energía durante la prueba para las categorías de energía proporcionadas. Cada categoría seleccionada se divide en sus subcomponentes medibles, y las categorías sin seleccionar se agregan a la métrica "sin seleccionar".
La terminal genera un mapa de la configuración que solicitas:
powerCategoryCpuUw: La cantidad de energía consumida por la CPU durante la prueba.powerCategoryGpuUw: La cantidad de energía consumida por la GPU durante la prueba.powerUnselectedUw: La energía agregada consumida por todas las categorías de hardware disponibles que no se solicitaron de forma explícita en tu mapa de inicialización.
Para evitar picos de datos erráticos en los rieles de hardware durante una ejecución, bloquea el brillo de la pantalla en un valor fijo, mantén una temperatura estable del dispositivo y cierra los procesos en segundo plano que compiten antes de iniciar el bucle de Macrobenchmark.
Recursos adicionales
Contenido de Views
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Cómo crear perfiles de Baseline {:#creating-profile-rules}
- Cómo escribir una macrocomparativa
- Optimización y análisis de inicio de la app {:#app-startup-analysis-optimization}