As métricas são o principal tipo de informação extraída das comparações. Elas
são transmitidas para a função measureRepeated como um List, permitindo
especificar várias métricas medidas de uma só vez. Pelo menos um tipo de métrica é
necessário para que a comparação seja executada.
O snippet de código abaixo captura as métricas de marcação do tempo para a renderização do frame e as da seção de rastros personalizados para uma interface de layout lento do 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)
}
}
}
No exemplo a seguir, EntryRowCustomTrace representa uma seção de rastreamento personalizada
definida dentro das camadas de itens combináveis usando o wrapper de bloco
trace(sectionName) { ... } padrão do Kotlin. Para fornecer dados para
TraceSectionMetric, encapsule os componentes de UI de destino na base de código de produção do
aplicativo com o wrapper de bloco trace
padrão do Jetpack Runtime:
@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)
)
}
}
}
Os resultados da comparação são gerados diretamente na guia do terminal Benchmark no Android Studio, conforme mostrado na Figura 1. Se várias métricas forem definidas, todos os pontos de dados calculados serão combinados na janela de resumo.
TraceSectionMetric e FrameTimingMetric para um layout moderno do Compose.StartupTimingMetric, FrameTimingMetric, TraceSectionMetric e
PowerMetric são abordados em detalhes abaixo. Para uma lista completa das métricas de comparativo de mercado disponíveis, consulte as subclasses de Metric na referência da API.
StartupTimingMetric
A StartupTimingMetric captura métricas de tempo de inicialização do app com os
seguintes valores:
timeToInitialDisplayMs: tempo total entre o momento em que o sistema recebe uma intent de inicialização e a renderização do primeiro frame da tela de destino.timeToFullDisplayMs: tempo total entre o momento em que o sistema recebe uma intent de inicialização e o momento em que o app é totalmente renderizado usando os mecanismos internos de relatórios da plataforma. A medição é interrompida quando a renderização do primeiro frame após (ou que contém) o sinal totalmente renderizado é concluída.
A StartupTimingMetric gera os valores mínimos, medianos e máximos das
iterações de inicialização. Para avaliar a melhoria da inicialização, concentre-se sempre nos valores medianos, porque eles oferecem a melhor estimativa dos tempos normais de inicialização do usuário.
Em uma arquitetura Compose-first, não tente invocar
activity.reportFullyDrawn manualmente. Em vez disso, use os utilitários assíncronos
seguros para Compose ReportDrawn, ReportDrawnWhen ou ReportDrawnAfter
nos combináveis de tela para sinalizar automaticamente ao Macrobenchmark quando
os dados de rede assíncronos ou os estados complexos da interface terminarem de renderizar.
Para mais informações sobre como analisar e otimizar o desempenho da inicialização, consulte Tempo de inicialização do app.
FrameTimingMetric
A FrameTimingMetric captura informações precisas de marcação de tempo de frames
produzidos por uma jornada de comparativo, como rolar uma lista ou uma animação
de layout de interface complexa, e gera os seguintes valores de diagnóstico:
frameOverrunMs: por quanto tempo um frame específico perdeu o prazo. Números positivos indicam uma queda de frame acompanhada de instabilidade ou travamento perceptíveis. Números negativos indicam a velocidade de renderização de um frame em relação ao prazo do hardware do subsistema. Observação: essa métrica está disponível apenas no Android 12 (nível 31 da API) e versões mais recentes.frameDurationCpuMs: o tempo que o frame passou sendo produzido ativamente na CPU na linha de execução de interface do aplicativo principal e noRenderThreaddo Compose.
Essas medidas são coletadas em uma distribuição de percentis 50, 90, 95 e 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
Ao otimizar as hierarquias de layout do Jetpack Compose, analise os frames com pior desempenho (os limites P95 e P99). Se frameOverrunMs aumentar para números inteiros positivos nos percentis altos, isso indica que as recomposições estão travando a linha de execução principal durante animações de rolagem pesadas.
Para insights mais detalhados sobre como identificar e resolver frames lentos, consulte Performance do Jetpack Compose.
TraceSectionMetric
TraceSectionMetric captura o número de vezes que uma seção de trace específica
ocorre e o tempo absoluto necessário para a execução. Para o rastreamento de tempo,
ela gera os tempos mínimo, mediano e máximo em milissegundos. A seção de rastreamento de destino é definida pela chamada de função trace(sectionName) ou pelos limites de bloco de nível inferior entre Trace.beginSection(sectionName) e Trace.endSection() ou suas variantes assíncronas.
EntryRowCustomTraceCount min 20.0, median 28.0, max 50.0
EntryRowCustomTraceSumMs min 34.9, median 44.4, max 66.6
Por padrão, a métrica só gera seções de rastreamento compiladas diretamente dos binários do pacote de aplicativos. Para incluir processos originados fora
do limite do pacote do app, defina a propriedade targetPackageOnly = false.
Ao trabalhar com o rastreamento de tempo de execução do Jetpack Compose, é possível mostrar funções combináveis individuais nos gráficos de rastreamento do sistema sem escrever wrappers de rastreamento manuais. Para isso, ative o rastreamento de composição.
Embora adicionar a dependência androidx.compose.runtime:runtime-tracing ao
aplicativo de destino seja suficiente para rastreamentos manuais do criador de perfil, capturar esses
rastreamentos de maneira programática em uma execução de Macrobenchmark exige mais
configurações no módulo de comparativo de mercado.
Para instruções completas de configuração, consulte Capturar rastros com a Macrobenchmark do Jetpack.
PowerMetric
PowerMetric captura a mudança de energia durante a execução do
Macrobenchmark. Cada categoria selecionada é dividida em componentes de hardware mensuráveis, enquanto as categorias não selecionadas são agrupadas em um bucket "não selecionado".
Requisito de hardware: essas métricas medem o consumo em todo o sistema, e não os cálculos por app. Por isso, a coleta de dados é limitada aos dispositivos físicos Google Pixel 6, Pixel 6 Pro e mais recentes.
A métrica gera duas medições por categoria:
power<category>Uw: quantidade de energia consumida durante o teste da categoria (medida em microwatts).energy<category>Uws: a quantidade total de energia transferida por unidade de tempo durante o teste da categoria (medida em microwatt-segundos).
As categorias incluem:
CPUDISPLAYGPUGPSMEMORYMACHINE_LEARNINGNETWORKUNCATEGORIZED
Com algumas categorias, como CPU, pode ser difícil separar o trabalho feito por
outros processos do trabalho feito pelo seu app. Para minimizar a interferência,
remova ou restrinja contas e apps desnecessários.
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
Analisar subsistemas principais
A PowerMetric captura a mudança de energia durante o teste para as categorias de energia fornecidas. Cada categoria selecionada é dividida em subcomponentes mensuráveis, e as categorias não selecionadas são adicionadas à métrica "não selecionada".
O terminal gera um mapa para a configuração solicitada:
powerCategoryCpuUw: a quantidade de energia consumida pela CPU durante o teste.powerCategoryGpuUw: a quantidade de energia consumida pela GPU durante o teste.powerUnselectedUw: a energia agregada consumida por todas as categorias de hardware disponíveis que não foram solicitadas explicitamente no mapa de inicialização.
Para evitar picos de dados irregulares nos trilhos de hardware durante uma execução, bloqueie o brilho da tela em um valor fixo, mantenha uma temperatura estável do dispositivo e feche os processos em segundo plano concorrentes antes de iniciar o loop do Macrobenchmark.
Outros recursos
Visualiza conteúdo
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Criar perfis de referência {:#creating-profile-rules}
- Como criar uma comparação da Macrobenchmark
- Otimização e análise de inicialização do app {:#app-startup-analysis-optimization}