Projetos maiores ou aqueles que implementam uma grande quantidade de lógica de compilação personalizada podem exigir
que você examine mais detalhadamente o processo de compilação para encontrar gargalos.
Você pode fazer isso analisando quanto tempo leva para o Gradle executar cada fase do
ciclo de vida e cada tarefa de build. Por exemplo, se o perfil de build mostrar
que o Gradle está gastando muito tempo configurando o projeto, ele pode sugerir
que você remova a lógica de build personalizada da fase de configuração.
Além disso, se a tarefa mergeDevDebugResources consome uma grande parte do tempo de build, isso pode indicar que você precisa converter suas imagens em WebP ou desativar a análise de PNG.
Se você está usando o Android Studio 4.0 ou versão mais recente, a melhor maneira de investigar problemas de desempenho de build é usar o Build Analyzer.
Além disso, há duas opções para analisar o build fora do Android Studio:
A ferramenta independente
gradle-profiler, uma ferramenta robusta para análise profunda do seu build.A opção
--profiledo Gradle, uma ferramenta conveniente disponível na linha de comando do Gradle.
Como usar a ferramenta gradle-profiler autônoma
Para encontrar a configuração de projeto com a melhor velocidade de build, você pode usar o Gradle profiler, uma ferramenta para coleta de informações sobre criação de perfis e comparações para builds do Gradle. O Gradle Profiler permite criar cenários de build e executá-los várias vezes, evitando uma grande variação entre os resultados e garantindo a reprodutibilidade deles.
O modo de comparação deve ser usado para coletar informações sobre builds limpos e incrementais, enquanto o modo de criação de perfil pode ser usado para coletar informações mais detalhadas sobre as execuções, incluindo snapshots de CPU.
Algumas das configuração de projeto para comparação incluem:
- Versões do plug-in
- Versões do Gradle
- Configurações de JVM (tamanho da alocação heap, tamanho de permgen, coleta de lixo etc.)
- Número de workers do Gradle (
org.gradle.workers.max) - Opções por plug-in para otimizar ainda mais o desempenho
Primeiros passos
- Instale o gradle-profiler seguindo estas instruções
- Execute:
gradle-profiler --benchmark --project-dir <root-project> :app:assembleDebug
Isso vai comparar um build totalmente atualizado, porque o --benchmark executa a
tarefa múltiplas vezes sem mudar o projeto entre elas. Depois, é gerado
um relatório HTML sob o diretório profile-out/, mostrando os
tempos de compilação.
Há outros cenários que podem ser mais úteis para comparar:
- Mudanças de código no corpo de um método em uma classe em que você faz a maior parte do trabalho.
- Mudanças de API em um módulo usado em todo o projeto. Embora seja menos frequente que as alterações do código, isso tem um impacto maior e é útil para avaliações.
- Edições de layout para simular a iteração no trabalho da IU.
- Edições de string para simular o trabalho com translação.
- Limpe os builds para simular mudanças no próprio build (por exemplo, atualização do Plug-in do Android para Gradle, atualização do Gradle ou edições no seu próprio código de build em
buildSrc).
Para comparar esses casos de uso, crie um cenário que será
usado para impulsionar a execução do gradle-profiler e que aplica as mudanças
adequadas às suas fontes. As seções a seguir descrevem alguns cenários comuns.
Como criar perfis com diferentes configurações de memória/CPU
Para comparar diferentes configurações de CPU e memória, é possível criar
vários cenários que usam valores diferentes para org.gradle.jvmargs. Por
exemplo, você pode criar cenários:
# <root-project>/scenarios.txt
clean_build_2gb_4workers {
tasks = [":app:assembleDebug"]
gradle-args = ["--max-workers=4"]
jvm-args = ["-Xmx2048m"]
cleanup-tasks = ["clean"]
}
clean_build_parallelGC {
tasks = [":app:assembleDebug"]
jvm-args = ["-XX:+UseParallelGC"]
cleanup-tasks = ["clean"]
}
clean_build_G1GC_4gb {
tasks = [":app:assembleDebug"]
jvm-args = ["-Xmx4096m", "-XX:+UseG1GC"]
cleanup-tasks = ["clean"]
}
A execução de gradle-profiler --benchmark --project-dir
<root-project> --scenario-file scenarios.txt
executará três cenários, e será possível comparar o tempo de
:app:assembleDebug em cada uma dessas configurações.
Como criar perfis de diferentes versões do plug-in Gradle
Para descobrir como a mudança da versão do plug-in Gradle afeta os tempos de compilação, crie um cenário para fins de comparação. Isso requer alguma preparação para tornar a versão do plug-in injetável a partir do cenário. Mude seu build.gradle raiz:
# <root-project>/build.gradle
buildscript {
def agpVersion = providers.systemProperty("agpVersion").forUseAtConfigurationTime().orNull ?: '4.1.0'
ext.kotlin = providers.systemProperty('kotlinVersion').forUseAtConfigurationTime().orNull ?: '1.4.0'
dependencies {
classpath "com.android.tools.build:gradle:$agpVersion"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin"
}
}
Agora você pode especificar as versões do Plug-in do Android para Gradle e do Kotlin para Gradle no arquivo de cenários e adicionar um novo método aos arquivos de origem:
# <root-project>/scenarios.txt
non_abi_change_agp4.1.0_kotlin1.4.10 {
tasks = [":app:assembleDebug"]
apply-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
System-properties {
"agpVersion" = "4.1.0"
"kotlinVersion" = "1.4.10"
}
non_abi_change_agp4.2.0_kotlin1.4.20 {
tasks = [":app:assembleDebug"]
apply-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
System-properties {
"agpVersion" = "4.2.0-alpha16"
"kotlinVersion" = "1.4.20"
}
Como criar perfis para um build incremental
A maioria dos builds é incremental, o que torna esse um dos cenários mais importantes para o perfil. O Gradle profiler tem ampla compatibilidade com a criação de perfis de builds incrementais. Ele pode implementar mudanças a um arquivo de origem automaticamente, alterando o corpo de um método, adicionando um novo método ou mudando um layout ou recurso de string. Por exemplo, é possível criar cenários incrementais como este:
# <root-project>/scenarios.txt
non_abi_change {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to = ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
}
abi_change {
tasks = [":app:assembleDebug"]
apply-abi-change-to = ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
}
layout_change {
tasks = [":app:assembleDebug"]
apply-android-layout-change-to = "app/src/main/res/your_layout_file.xml"
}
string_resource_change {
tasks = [":app:assembleDebug"]
apply-android-resource-value-change-to = "app/src/main/res/values/strings.xml"
}
A execução de gradle-profiler --benchmark --project-dir <root-project>
--scenario-file scenarios.txt
irá gerar o relatório HTML com os dados de comparação.
É possível combinar cenários incrementais com outras configurações, como tamanho da alocação de heap, número de workers ou versão do Gradle:
# <root-project>/scenarios.txt
non_abi_change_4g {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
jvm-args = ["-Xmx4096m"]
}
non_abi_change_4g_8workers {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
jvm-args = ["-Xmx4096m"]
gradle-args = ["--max-workers=8"]
}
non_abi_change_3g_gradle67 {
tasks = [":app:assembleDebug"]
apply-non-abi-change-to ["app/src/main/java/com/example/your_app/your_code_file.java,
"app/src/main/java/com/example/your_app/your_code_file.kt"]
jvm-args = ["-Xmx3072m"]
version = ["6.7"]
}
Como criar perfis para um build limpo
Para comparar um build limpo, você pode criar um cenário que será usado para conduzir a execução do gradle-profiler:
# <root-project>/scenarios.txt
clean_build {
tasks = [":app:assembleDebug"]
cleanup-tasks = ["clean"]
}
Para executar esse cenário, use o seguinte comando:
gradle-profiler --benchmark --project-dir <root-project> --scenario-file scenarios.txt
Como usar a opção --profile do Gradle
Para gerar e ver um perfil de build na linha de comando do Gradle, execute as seguintes etapas:
Abra um terminal de linha de comando na raiz do projeto.
Execute uma compilação limpa inserindo o seguinte comando. Ao analisar o perfil do build, faça um build limpo entre cada build analisado, porque o Gradle pula tarefas quando as entradas de uma tarefa (como o código-fonte) não mudam. Assim, um segundo build sem mudanças de entrada sempre é executado mais rápido, porque as tarefas não são executadas novamente. Portanto, executar a tarefa
cleanentre os builds garante que você analise todo o processo de build.// On Mac or Linux, run the Gradle wrapper using "./gradlew". gradlew cleanExecute um build de depuração de uma das variações de produto, como a variação "dev", com as seguintes flags:
gradlew --profile --offline --rerun-tasks assemble<var>Flavor</var>Debug--profile: ativa a criação de perfil.--offline: impede que o Gradle busque dependências on-line. Isso garante que os atrasos causados pela tentativa do Gradle de atualizar as dependências não interfiram nos dados de criação de perfil. Você já deve ter criado seu projeto uma vez para garantir que o Gradle já tenha baixado e armazenado em cache suas dependências.--rerun-tasks: força o Gradle a executar novamente todas as tarefas e ignorar as otimizações de tarefas.
Depois que o build for concluído, use a janela Project para navegar até o diretório
project-root/build/reports/profile/, como mostrado na Figura 1.
Figura 1. Visualização do projeto indicando o local dos relatórios de perfil.
Clique com o botão direito do mouse no arquivo
profile-timestamp.htmle selecione Open in Browser > Default. O relatório será semelhante ao mostrado na figura 2. Você pode inspecionar cada guia no relatório para Aprenda Mais sobre sua compilação, como a guia Task Execution, que mostra quanto tempo o Gradle levou para executar cada tarefa de compilação.
Figura 2. Visualização de um relatório em um navegador.
Opcional: antes de fazer mudanças no projeto ou na configuração do build, repita o comando na etapa 3, mas omita a flag
--rerun-tasks. Como o Gradle tenta poupar tempo evitando repetir a execução de tarefas cujas entradas não mudaram (indicadas comoUP-TO-DATEna guia Task Execution do relatório, conforme mostrado na Figura 3), você pode identificar quais tarefas estão trabalhando quando não deveriam estar. Por exemplo, se o:app:processDevUniversalDebugManifestnão estiver marcado comoUP-TO-DATE, isso pode sugerir que a configuração do build está atualizando dinamicamente o manifesto a cada build. No entanto, algumas tarefas precisam ser executadas durante cada build, como:app:checkDevDebugManifest.
Figura 3. Visualização dos resultados da execução da tarefa.
Agora que você tem um relatório de perfil de build, pode começar a procurar oportunidades de otimização
inspecionando as informações em cada guia do relatório. Algumas
configurações de build exigem experimentação, porque os benefícios podem variar entre
projetos e estações de trabalho. Por exemplo, projetos com uma base de código grande podem
se beneficiar da redução de código para remover o código não utilizado e reduzir o tamanho do app.
No entanto, projetos menores podem se beneficiar mais da desativação total da redução de código. Além disso, aumentar o tamanho do heap do Gradle (usando
org.gradle.jvmargs) pode afetar negativamente o desempenho em
máquinas com pouca memória.
Após fazer uma alteração na configuração do build, observe os resultados das suas alterações repetindo as etapas anteriores e gerando um novo perfil de build. Por exemplo, a Figura 4 mostra um relatório do mesmo app de exemplo depois de aplicar algumas das otimizações básicas descritas nesta página.
Figura 4. Visualização de um novo relatório após otimizar a velocidade de compilação.