O Bazel é complexo e faz muitas coisas diferentes durante um build, algumas das quais podem afetar o 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. Em comparação com o início de uma compilação limpa do zero (que leva mais tempo devido a um cache frio), as compilações incrementais acontecem com muito mais frequência à medida que os desenvolvedores iteram no código (geralmente mais rápido, já que o cache geralmente já está quente).
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, observando o número de pacotes carregados (`PackageMetrics.packages_loaded`).
Métricas de build determinísticas como um proxy para o desempenho do build 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).
O tamanho de uma solicitação de build pode ter uma implicação significativa no desempenho do build. 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.
Podemos dividir este problema nas várias fases de build e usar as seguintes métricas como métricas proxy para o trabalho realizado em cada fase:
PackageMetrics.packages_loaded: o número de pacotes carregados com sucesso. `PackageMetrics.packages_loaded`: o número de pacotes carregados com sucesso.TargetMetrics.targets_configured: representando o número de alvos e aspectos configurados na compilação. `TargetMetrics.targets_configured`: representa o número de destinos e aspectos configurados no build.- Uma regressão representa mais trabalho na construção e na travessia do gráfico de destino configurado.
- 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.- If the number of actions executed did not increase, then it is likely that a rule implementation was changed.
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.
Todas essas métricas são afetadas pelo estado do cache local. Portanto, é necessário garantir que os builds dos quais você extrai essas métricas sejam **limpos**.
Observamos que uma regressão em qualquer uma dessas métricas pode ser acompanhada de regressões no tempo real, 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 de outras tarefas.
Tempo gasto 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 de parede é o tempo real decorrido.
- Se apenas o tempo real regredir, sugerimos coletar um perfil de rastreamento JSON e procurar diferenças. Caso contrário, seria provavelmente mais eficiente investigar outras métricas regredidas, uma vez que poderiam ter afetado o tempo real.
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 do seu sistema de arquivos.
Se o tempo do sistema regredir, ele será mais correlacionado 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**.
Perfil que inclui a média de carga do sistema. Você pode querer considerar
ajustar
--local_cpu_resources
e --local_ram_resources,
especialmente em ambientes de contêiner (pelo menos até
#16512 ser mesclado).
Talvez seja necessário ajustar `--local_cpu_resources` e `--local_ram_resources`, especialmente em ambientes de contêiner (pelo menos até que #16512 seja mesclado).
Como monitorar o uso de 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 de 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 uso 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.
Criação de perfil de memória de workers persistentes 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 de 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. **Figura 2**.
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.
Como monitorar o tráfego de rede para builds remotos 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 seu 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 de disco local para economizar largura de banda de download.