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 compilação. Por exemplo, se o perfil da compilação
mostra que o Gradle passa tempo demais configurando o projeto, isso pode
sugerir que é preciso retirar a lógica de compilação
personalizada da fase de configuração.
Além disso, se a tarefa mergeDevDebugResources
consome uma grande parte
do tempo de compilação, 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 compilação é usar o Build Analyzer.
Além disso, há duas opções de criar perfil do build fora do Android Studio:
A ferramenta
gradle-profiler
autônoma, uma ferramenta robusta para análise detalhada do seu build.A opção
--profile
do Gradle, uma ferramenta conveniente, disponível da 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 compilação, 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 compilação e executá-los múltiplas vezes, evitando grande variação entre resultados e garantindo a reprodução dos resultados.
O Modo de comparação é 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 granulares sobre a execução, incluindo snapshots da 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.
- Builds limpos para simular mudanças na próprio build (por exemplo, atualização do
Plug-in do Android para Gradle, atualização do Gradle ou edições no seu código de compilação
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. Veja alguns dos cenários comuns abaixo.
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 aplicar mudanças a um arquivo de origem automaticamente mudando um corpo de método, adicionando um novo método ou mudando um recurso de layout ou string. Por exemplo, é possível criar cenários incrementais como estes:
# <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 compilação na linha de comando do Gradle, execute as seguintes etapas:
- Abra um terminal de linha de comando na raiz do projeto.
- Execute um build limpo inserindo o seguinte comando. Ao criar perfis para
seu build, faça um build limpo entre cada build para o qual você criar um perfil,
porque o Gradle pula tarefas quando entradas para uma delas (como o código-fonte) não
mudam. Dessa forma, um segundo build sem mudanças nas entradas sempre será executado mais rapidamente, porque
as tarefas não estão sendo repetidas. Portanto, executar a tarefa
clean
entre os builds garante que o perfil seja feito para todo o processo de compilação.// On Mac or Linux, run the Gradle wrapper using "./gradlew". gradlew clean
- Execute um build de depuração de uma das suas variações de produto, como a variação “dev”,
com as seguintes sinalizações:
gradlew --profile --offline --rerun-tasks assembleFlavorDebug
-
--profile
: ativa a criação de perfis. -
--offline
: impede o Gradle de buscar dependências on-line. Isso garante que qualquer atraso causado pelo Gradle ao tentar atualizar as dependências não interfira nos dados de perfil. Você precisa ter criado o projeto uma vez para garantir que o Gradle já tenha feito o download das dependências e as armazenado em cache. -
--rerun-tasks
: força o Gradle a executar todas as tarefas novamente e ignorar qualquer otimização de tarefas.
-
-
Quando a criação for concluída, use a janela Project para navegar até o diretório
project-root/build/reports/profile/
(conforme mostrado na Figura 1). -
Com o botão direito do mouse, clique no arquivo
profile-timestamp.html
e selecione Open in Browser > Default. O relatório será semelhante ao mostrado na Figura 2. Você pode inspecionar cada guia do relatório para aprender sobre seu build, como a guia Task Execution, que mostra quanto tempo o Gradle levou para executar cada tarefa de compilação. -
Opcional: antes de fazer qualquer alteração no projeto ou na configuração da compilação, repita o comando na etapa 3, mas omita a sinalização
--rerun-tasks
. Como o Gradle tenta poupar tempo evitando repetir a execução de tarefas cujas entradas não mudaram (indicadas comoUP-TO-DATE
na 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:processDevUniversalDebugManifest
não estiver marcado comoUP-TO-DATE
, pode ser indício de que a configuração da sua compilação atualiza o manifesto dinamicamente com cada build. Entretanto, algumas tarefas precisam ser executadas em todos os builds, como:app:checkDevDebugManifest
.
Agora que você tem um relatório de perfil de compilação, pode começar a buscar
oportunidades de otimização inspecionando as informações em cada guia do
relatório. Algumas configurações de compilação exigem experimentação, porque os benefícios podem
variar entre projetos e estações de trabalho. Por exemplo, projetos com uma grande
base de códigos podem se beneficiar da redução de código
para remover códigos não utilizados e reduzir o tamanho do app. Entretanto, para projetos
menores, talvez seja mais vantajoso desativar a redução de código. Além disso,
aumentar o tamanho de 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 acima e gerando um novo perfil de compilação. Por exemplo, a Figura 4 mostra um relatório para o mesmo exemplo de app após aplicar algumas das otimizações básicas descritas nesta página.