O Bazel é complexo e faz muitas coisas diferentes durante um build, algumas das quais podem ter um impacto no desempenho do build. Esta página tenta mapear alguns desses conceitos do Bazel para as implicações deles no desempenho do build. Embora não seja abrangente, incluímos alguns exemplos de como detectar problemas de desempenho do build extraindo métricas e o que você pode fazer para corrigi-los. Com isso, esperamos que você possa aplicar esses conceitos ao investigar regressões de desempenho do build.
Builds limpos x incrementais
Um build limpo é aquele que cria tudo do zero, enquanto um build incremental reutiliza alguns trabalhos já concluídos.
Sugerimos analisar builds limpos e incrementais separadamente, especialmente ao coletar / agregar métricas que dependem do estado dos caches do Bazel (por exemplo métricas de tamanho da solicitação de build ). Eles também representam duas experiências de usuário diferentes. Eles também representam duas experiências de usuário diferentes.
Você pode usar o campo CumulativeMetrics.num_analyses no BEP para classificar
builds. Se num_analyses <= 1, é uma compilação limpa; caso contrário, podemos categorizá-la amplamente
como provavelmente uma compilação incremental - o usuário pode ter mudado
para diferentes sinalizadores ou diferentes destinos, causando uma compilação efetivamente limpa. Qualquer definição mais rigorosa de incrementalidade provavelmente terá que vir na forma de uma heurística, por exemplo, olhando para o número de pacotes carregados (PackageMetrics.packages_loaded).
Qualquer definição mais rigorosa de incrementalidade provavelmente terá que vir na forma de uma heurística, por exemplo, analisando o número de pacotes carregados (`PackageMetrics.packages_loaded`).
Medir o desempenho do build pode ser difícil devido à natureza não determinística de certas métricas (por exemplo, Tempo de CPU do Bazel ou tempos de fila em um cluster remoto). Medir o desempenho do build pode ser difícil devido à natureza não determinística de determinadas métricas (por exemplo, o tempo de CPU do Bazel ou os tempos de fila em um cluster remoto).
Assim, pode ser útil usar métricas determinísticas como um proxy para a quantidade de trabalho feito pelo Bazel, o que, por sua vez, afeta o desempenho dele. O tamanho de uma solicitação de build pode ter uma implicação significativa no desempenho do build. Um build maior pode representar mais trabalho na análise e construção dos gráficos de build.
O crescimento orgânico dos builds ocorre naturalmente com o desenvolvimento, à medida que mais dependências são adicionadas/criadas e, portanto, aumentam em complexidade e ficam mais caras para serem criadas.
PackageMetrics.packages_loaded: o número de pacotes carregados com sucesso. Uma regressão aqui representa mais trabalho que precisa ser feito para ler e analisar cada arquivo BUILD adicional na fase de carregamento.TargetMetrics.targets_configured: representando o número de alvos e aspectos configurados na compilação. Uma regressão representa mais trabalho na construção e travessia do grafo de destino configurado.- Isso geralmente se deve à adição de dependências e à necessidade de construir o grafo de seu fecho transitivo.
- Use cquery para encontrar onde novas dependências podem ter sido adicionadas.
ActionSummary.actions_createdrepresenta as ações criadas na compilação, e uma regressão representa mais trabalho na construção do gráfico de ação. `ActionSummary.actions_created`: representa as ações criadas no build, e uma regressão representa mais trabalho na construção do gráfico de ações.- Use aquery para depurar regressões;
sugerimos começar com
--output=summaryantes de detalhar mais com--skyframe_state.
- Use aquery para depurar regressões;
sugerimos começar com
ActionSummary.actions_executed: o número de ações executadas, uma regressão representa diretamente mais trabalho na execução dessas ações.- O BEP escreve as estatísticas de ação
ActionDataque mostram os tipos de ação mais executados. Por padrão, ele coleta os 20 principais tipos de ação, mas você pode passar em--experimental_record_metrics_for_all_mnemonicspara coletar esses dados para todos os tipos de ação que foram executados. - Isso deve ajudar você a descobrir que tipo de ações foram executadas (adicionalmente).
- O BEP escreve as estatísticas de ação
BuildGraphSummary.outputArtifactCount: o número de artefatos criados por ações executadas.- `BuildGraphSummary.outputArtifactCount`: o número de artefatos criados pelas ações executadas.
Estas métricas são todas afetadas pelo estado da cache local, pelo que irá querer garantir que as compilações das quais extrai estas métricas são compilações limpas.
Observamos que uma regressão em qualquer uma dessas métricas pode ser acompanhada por regressões no tempo decorrido, Tempo de CPU e uso da memória.
Observamos que uma regressão em qualquer uma dessas métricas pode ser acompanhada de regressões no tempo de parede, no tempo de CPU e no uso de memória.
Uso de recursos locais
O Bazel consome vários recursos na sua máquina local (tanto para analisar o gráfico de build e impulsionar a execução quanto para executar ações locais). Isso pode afetar o desempenho/disponibilidade da sua máquina na execução do build e também outras tarefas.
Talvez as métricas mais suscetíveis a ruído (e que podem variar muito de build para build) sejam o tempo; em particular, o tempo decorrido, o tempo de CPU e o tempo de sistema. Você pode
usar bazel-bench para obter
um benchmark para essas métricas, e com um número suficiente de --runs, você pode
aumentar a significância estatística da sua medição.
Tempo decorrido é o tempo real decorrido.
- Se apenas o tempo decorrido regredir, sugerimos coletar um perfil de rastreamento JSON e procurar diferenças. Caso contrário, provavelmente seria mais eficiente investigar outras métricas regredidas, pois elas podem ter afetado o tempo de parede.
Tempo de CPU é o tempo gasto pela CPU executando código de usuário.
- Se o tempo de CPU regredir entre dois commits de projeto, sugerimos coletar
um perfil de CPU Starlark. Você provavelmente também deve usar
--nobuildpara restringir a compilação à fase de análise, já que é onde a maior parte do trabalho pesado da CPU é feito.
- Se o tempo de CPU regredir entre dois commits de projeto, sugerimos coletar
um perfil de CPU Starlark. Você provavelmente também deve usar
Você também deve usar `--nobuild` para restringir o build à fase de análise, já que é nela que a maior parte do trabalho pesado da CPU é feita.
- Se o tempo do sistema regredir, isso estará principalmente correlacionado com E/S quando o Bazel ler arquivos dos seus sistemas de arquivos.
Se o tempo do sistema regredir, ele será correlacionado principalmente com a E/S quando o Bazel lê arquivos do seu sistema de arquivos.
Perfil de carga em todo o sistema--experimental_collect_load_average_in_profiler

Figura 1. **Figura 1**.
Uma carga alta durante uma invocação do Bazel pode ser uma indicação de que o Bazel escalona muitas ações locais em paralelo para sua máquina. Você pode querer considerar
ajustar
--local_cpu_resources
e --local_ram_resources,
especialmente em ambientes de contêiner (pelo menos até
#16512 ser mesclado).
Monitoramento do uso da memória do Bazel
Monitorar o uso da memória do Bazel: há duas fontes principais para obter o uso da memória do Bazel, Bazel info e o
BEP.
bazel info used-heap-size-after-gc: A quantidade de memória usada em bytes após uma chamada paraSystem.gc().- `bazel info used-heap-size-after-gc`: a quantidade de memória usada em bytes após uma chamada para `System.gc()`.
- Além disso, há
peak-heap-size,max-heap-size,used-heap-sizeecommitted-heap-size(consulte a documentação), mas são menos relevantes.
BEP’s
MemoryMetrics.peak_post_gc_heap_size: Tamanho do pico do tamanho do heap da JVM em bytes após o GC (requer a configuração--memory_profileque tenta forçar um GC completo).
Uma regressão no uso da memória geralmente é resultado de uma regressão nas métricas de tamanho de solicitação de build, que geralmente se devem à adição de dependências ou a uma alteração na implementação da regra.
Para analisar o consumo de memória do Bazel em um nível mais granular, recomendamos usar o criador de perfil de memória integrado para regras.
Para analisar a ocupação de memória do Bazel em um nível mais granular, recomendamos usar o criador de perfil de memória integrado para regras.
Embora workers persistentes possam ajudar a acelerar builds significativamente (especialmente para linguagens interpretadas), o consumo de memória deles pode ser problemático. Bazel coleta métricas sobre seus workers, em particular, o campo
WorkerMetrics.WorkerStats.worker_memory_in_kb informa quanta memória
os workers usam (por mnemônico).
O gerador de perfil de trace JSON também coleta o uso da memória persistente do worker durante a invocação ao transmitir a --experimental_collect_system_network_usage flag (novo no Bazel 6.0).

Figura 2. Perfil que inclui o uso da memória dos workers.
Reduzir o valor de
--worker_max_instances
(padrão 4) pode ajudar a reduzir
a quantidade de memória usada por workers persistentes. Estamos trabalhando ativamente para tornar o gerenciador de recursos e o agendador do Bazel mais inteligentes, para que esse ajuste fino seja necessário com menos frequência no futuro.
Estamos trabalhando ativamente para tornar o gerenciador de recursos e o programador do Bazel mais inteligentes, para que esse ajuste fino seja necessário com menos frequência no futuro.
Na execução remota, o Bazel faz o download de artefatos que foram criados como resultado da execução de ações. Na execução remota, o Bazel faz o download de artefatos criados como resultado da execução de ações.
Assim, a largura de banda da rede pode afetar o desempenho do build.NetworkMetrics.SystemNetworkStats--experimental_collect_system_network_usage
Além disso, perfis de rastreamento JSON
permitem que você visualize o uso da rede em todo o sistema durante o curso da compilação
passando o sinalizador --experimental_collect_system_network_usage (novo no Bazel
6.0).

Figura 3. **Figura 3**.
Perfil que inclui o uso de rede em todo o sistema.--remote_download_minimal
Um uso de rede alto, mas bastante plano, ao usar a execução remota pode indicar que a rede é o gargalo no build. Se você ainda não estiver usando, considere ativar o build sem os bytes transmitindo `--remote_download_minimal`.
Outra opção é configurar um cache em disco local para economizar largura de banda de download.