Use a biblioteca Macrobenchmark para testar casos de uso maiores do
aplicativo, incluindo a inicialização do app e manipulações complexas de IU, como rolar uma
RecyclerView
ou mostrar animações. Se você quiser testar áreas menores
do código, consulte a biblioteca Microbenchmark.
A biblioteca gera resultados comparativos no console do Android Studio e em um arquivo JSON com mais detalhes. Ela também fornece arquivos de rastreamento que podem ser carregados e analisados no Android Studio.
Use a biblioteca Macrobenchmark em um ambiente de integração contínua (CI, na sigla em inglês), conforme descrito em Executar comparações na integração contínua.
Os perfis de referência podem ser gerados com a biblioteca Macrobenchmark. Siga o guia abaixo para configurar a biblioteca e criar um perfil de referência.
Configuração do projeto
Recomendamos usar a Macrobenchmark com a versão mais recente do Android Studio, já que há novos recursos nessa versão do ambiente de desenvolvimento integrado à Macrobenchmark.
Configurar o módulo Macrobenchmark
A biblioteca Macrobenchmark exige um módulo
com.android.test
separado do código do app, responsável por executar os testes que medem o desempenho
dele.
No Android Studio, há um modelo disponível para simplificar a configuração do módulo da biblioteca Macrobenchmark. O modelo de módulo de comparação cria automaticamente um módulo no projeto para medir o app criado por um módulo, incluindo um exemplo de inicialização de comparação.
Para usar o modelo e criar um novo módulo, siga estas etapas:
Clique com o botão direito do mouse no seu projeto ou módulo no painel Project do Android Studio e clique em New > Module.
Selecione Benchmark no painel Templates.
É possível personalizar o aplicativo de destino (o app que vai ser comparado) e também o nome do pacote e do novo módulo da Macrobenchmark.
Clique em Finish.
Configurar o aplicativo
Para avaliar um app, que é chamado de destino da biblioteca Macrobenchmark, ele precisa
ser profileable
para ler informações detalhadas sobre o rastreamento sem
afetar a performance. O assistente de módulo adiciona a tag <profileable>
automaticamente ao arquivo AndroidManifest.xml
do app.
Configure o app comparado para que fique o mais próximo possível da versão de lançamento
(ou de produção). Defina-o como não depurável e, de preferência, com a minificação ativada, que
melhora o desempenho. Normalmente, isso é feito criando uma cópia da variante
da versão, que tem o mesmo desempenho, mas é assinada localmente com chaves de depuração.
Como alternativa, use initWith
para instruir o Gradle a fazer isso por você:
Groovy
buildTypes { val release = getByName("release") { isMinifyEnabled = true isShrinkResources = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } create("benchmark") { initWith(release) signingConfig = signingConfigs.getByName("debug") proguardFiles("benchmark-rules.pro") } }
Kotlin
buildTypes { getByName("release") { isMinifyEnabled = true isShrinkResources = true proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt")) } create("benchmark") { initWith(getByName("release")) signingConfig = signingConfigs.getByName("debug") } }
Sincronize com o Gradle, abra o painel Build Variants à esquerda e selecione a variante de comparação do app e do módulo da Macrobenchmark. Isso vai garantir que a comparação crie e teste a variante correta do app:
(Opcional) Configurar aplicativos com vários módulos
Caso seu app tenha mais de um módulo do Gradle, confira se os scripts
de build sabem qual variante vai ser compilada. Sem isso, o buildType
benchmark
recém-adicionado faz com que o build falhe e mostra esta mensagem
de erro:
> Could not resolve project :shared.
Required by:
project :app
> No matching variant of project :shared was found.
...
Para corrigir o problema, adicione a propriedade matchingFallbacks
no buildType
benchmark
dos seus módulos :macrobenchmark
e :app
. Os outros
módulos do Gradle podem ter a mesma configuração anterior.
Groovy
benchmark { initWith buildTypes.release signingConfig signingConfigs.debug matchingFallbacks = ['release'] }
Kotlin
create("benchmark") { initWith(getByName("release")) signingConfig = signingConfigs.getByName("debug") matchingFallbacks += listOf('release') }
Ao selecionar as variantes de build no seu projeto, escolha benchmark
para os módulos :app
e :macrobenchmark
e release
para qualquer outro módulo no
app, como mostrado na imagem abaixo:
Para ver mais informações, consulte o gerenciamento de dependências com reconhecimento de variantes.
(Opcional) Configurar variações de produtos
Se você tem diversas variações de produto definidas no app, é necessário configurar o módulo
:macrobenchmark
para que ele saiba qual variação vai ser criada
e comparada. Sem essa configuração, você pode receber um erro de build semelhante ao que acontece com
vários módulos Gradle:
Could not determine the dependencies of task ':macrobenchmark:connectedBenchmarkAndroidTest'.
> Could not determine the dependencies of null.
> Could not resolve all task dependencies for configuration ':macrobenchmark:benchmarkTestedApks'.
> Could not resolve project :app.
Required by:
project :macrobenchmark
> The consumer was configured to find a runtime of a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'benchmark', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.3.0'. However we cannot choose between the following variants of project :app:
- demoBenchmarkRuntimeElements
- productionBenchmarkRuntimeElements
All of them match the consumer attributes:
...
Neste guia, usamos as duas variações de produto no módulo :app
,
demo
e production
, como você pode conferir neste snippet:
Groovy
flavorDimensions 'environment' productFlavors { demo { dimension 'environment' // ... } production { dimension 'environment' // ... } }
Kotlin
flavorDimensions += "environment" productFlavors { create("demo") { dimension = "environment" // ... } create("production") { dimension = "environment" // ... } }
Há duas maneiras de configurar a comparação com diversas variações de produto:
Usar missingDimensionStrategy
Especificar missingDimensionStrategy
no defaultConfig
do módulo
:macrobenchmark
instrui o sistema de compilação a substituir a dimensão
de variações. Caso as dimensões não sejam encontradas no módulo, você precisa especificar
quais vão ser usadas. No exemplo a seguir, a variação production
é usada
como a dimensão padrão.
Groovy
defaultConfig { missingDimensionStrategy "environment", "production" }
Kotlin
defaultConfig { missingDimensionStrategy("environment", "production") }
Dessa forma, o módulo :macrobenchmark
só pode criar e comparar a
variação de produto especificada, o que é útil quando você sabe que apenas uma delas
tem a configuração adequada para comparação.
Definir variações de produtos no módulo :macrobenchmark
Para criar e comparar outras variações de produto, elas precisam
ser definidas no módulo :macrobenchmark
. Especifique-as de maneira semelhante ao
módulo :app
, mas atribua productFlavors
a apenas uma dimension
.
Nenhuma outra configuração é necessária.
Groovy
flavorDimensions 'environment' productFlavors { demo { dimension 'environment' } production { dimension 'environment' } }
Kotlin
flavorDimensions += "environment" productFlavors { create("demo") { dimension = "environment" } create("production") { dimension = "environment" } }
Depois de definir e sincronizar o projeto, escolha a variante de build desejada no painel Build Variants:
Para saber mais, consulte Resolver erros de build relacionados à correspondência de variantes.
Criar uma classe de Macrobenchmark
O teste de comparação é fornecido pela API de regra MacrobenchmarkRule
do JUnit4 na biblioteca Macrobenchmark. Ele contém um método measureRepeated
que permite especificar várias condições de execução e comparar o aplicativo de destino.
É necessário especificar pelo menos o packageName
do aplicativo de destino, quais
metrics
você quer medir e quantas iterations
a comparação precisa
executar.
Kotlin
@LargeTest @RunWith(AndroidJUnit4::class) class SampleStartupBenchmark { @get:Rule val benchmarkRule = MacrobenchmarkRule() @Test fun startup() = benchmarkRule.measureRepeated( packageName = TARGET_PACKAGE, metrics = listOf(StartupTimingMetric()), iterations = DEFAULT_ITERATIONS, setupBlock = { // Press home button before each run to ensure the starting activity isn't visible. pressHome() } ) { // starts default launch activity startActivityAndWait() } }
Java
@LargeTest @RunWith(AndroidJUnit4.class) public class SampleStartupBenchmark { @Rule public MacrobenchmarkRule benchmarkRule = new MacrobenchmarkRule(); @Test public void startup() { benchmarkRule.measureRepeated( /* packageName */ TARGET_PACKAGE, /* metrics */ Arrays.asList(new StartupTimingMetric()), /* iterations */ 5, /* measureBlock */ scope -> { // starts default launch activity scope.startActivityAndWait(); return Unit.INSTANCE; } ); } }
Para ver todas as opções de personalização da comparação, consulte a seção Personalizar as comparações.
Executar a comparação
Faça o teste no Android Studio para medir o desempenho do app
no dispositivo. É possível executar as comparações da mesma forma que você executa qualquer outro
@Test
usando a ação de gutter ao lado da classe ou do método de teste, conforme mostrado na
imagem abaixo.
Também é possível fazer todas as comparações em um módulo do Gradle na linha de comando usando o comando connectedCheck:
./gradlew :macrobenchmark:connectedCheck
Ou para executar um único teste:
./gradlew :macrobenchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.macrobenchmark.startup.SampleStartupBenchmark#startup
Consulte a seção Comparações na CI para ver informações sobre como fazer e monitorar comparações na integração contínua.
Resultados da comparação
Após a execução da comparação, as métricas são exibidas diretamente no Android Studio e também são geradas para uso da CI em um arquivo JSON. Cada iteração medida captura um rastreamento do sistema separado. É possível abrir esses rastreamentos de resultados clicando em um dos links no painel Test Results, conforme mostrado na imagem abaixo.
Quando o rastreamento é carregado, o Android Studio pede que você selecione o processo a ser analisado. A seleção é pré-preenchida com o processo do app de destino:
Após o arquivo de trace ser carregado, o Studio mostra os resultados na ferramenta CPU Profiler:
Os relatórios JSON e todos os rastros de criação de perfil também são copiados automaticamente do dispositivo para o host. Eles são gravados na máquina host em:
project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/
Acessar arquivos de rastreamento manualmente
Para usar a ferramenta Perfetto para analisar um arquivo de rastreamento, outras etapas precisam ser seguidas. O Perfetto possibilita inspecionar todos os processos que ocorrem em todo o dispositivo durante o rastreamento, enquanto o CPU Profiler do Android Studio limita a inspeção a um único processo.
Se você invocar os testes no Android Studio ou usar a linha de comando do Gradle, os arquivos de rastreamento vão ser copiados automaticamente do dispositivo para o host. Eles são gravados na máquina host em:
project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/TrivialStartupBenchmark_startup[mode=COLD]_iter002.perfetto-trace
Quando o arquivo de rastreamento for criado no sistema host, você vai poder abri-lo no Android Studio no menu em File > Open. A tela da ferramenta do criador de perfil mostrada na seção anterior vai aparecer.
Erros de configuração
Se o app estiver configurado incorretamente (por exemplo, se for depurável ou não estiver relacionado à criação de perfil), a Macrobenchmark
vai retornar um erro, em vez de relatar uma medição incorreta ou incompleta.
É possível suprimir esses erros usando o argumento
androidx.benchmark.suppressErrors
.
Erros também são gerados ao tentar medir o desempenho em um emulador ou em um dispositivo com bateria fraca, porque isso pode comprometer a disponibilidade de núcleos e a velocidade de processamento.
Personalizar as comparações
A função measureRepeated
aceita vários parâmetros que têm influência sobre
as métricas que a biblioteca coleta, como o aplicativo é iniciado e
compilado ou quantas iterações a comparação vai executar.
Capturar as métricas
As métricas são o principal tipo de informação extraída das comparações.
As opções disponíveis são StartupTimingMetric
, FrameTimingMetric
e
TraceSectionMetric
. Para ver mais informações sobre eles, consulte a página
Capturar as métricas.
Melhorar os dados de rastreamento com eventos personalizados
Pode ser útil instrumentar o aplicativo com eventos de rastreamento personalizados, que são mostrados com o restante do relatório de rastreamento e podem ajudar a apontar problemas específicos do app. Para saber mais sobre como criar eventos de rastreamento personalizados, consulte o guia Definir eventos personalizados.
CompilationMode
As comparações da Macrobenchmark podem especificar uma classe CompilationMode, que define quanto do app precisa ser pré-compilado do bytecode DEX (o formato de bytecode dentro de um APK) para código de máquina (semelhante à linguagem C++ pré-compilada).
Por padrão, as comparações da biblioteca Macrobenchmark são executadas com o CompilationMode.DEFAULT
, que
instala um perfil de referência (se disponível) no Android 7 (nível 24 da API) e
versões mais recentes. Se você estiver usando o Android 6 (nível 23 da API) ou uma versão anterior, o modo de compilação
compila o APK completamente como o comportamento padrão do sistema.
Você pode instalar um perfil de referência se o aplicativo de destino tiver um
perfil de referência e usar a biblioteca ProfileInstaller
.
No Android 7 e versões mais recentes, é possível personalizar o CompilationMode
para afetar a quantidade de pré-compilação no dispositivo e imitar diferentes níveis de
compilação antecipada (AOT, na sigla em inglês) ou armazenamento em cache JIT. Consulte
CompilationMode.Full
, CompilationMode.Partial
e CompilationMode.None
.
Essa funcionalidade é criada com base em comandos de compilação do ART. Cada comparação limpa os dados de perfil antes de começar para garantir a não interferência entre elas.
StartupMode
Para inicializar uma atividade, é possível transmitir um modo de inicialização predefinido (um de
COLD
, WARM
ou HOT
). Esse parâmetro muda a forma como a atividade
é iniciada e o estado do processo no início do teste.
Para saber mais sobre os tipos de inicialização, consulte a documentação sobre inicialização do Android vitals.
Exemplos
Um projeto de exemplo está disponível como parte do repositório android/performance-samples (link em inglês) no GitHub.
Enviar feedback
Para informar problemas ou enviar solicitações de novos recursos para a Jetpack MacroBenchmark, consulte o Issue Tracker público.