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 extensa, 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, crescem em complexidade e se tornam mais caras para criar.
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 fechamento transitivo.
- Use cquery para encontrar onde novas dependências podem ter sido adicionadas.
ActionSummary.actions_created: representa as ações criadas na compilação, e uma regressão representa mais trabalho na construção do grafo 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; nós
sugerimos começar com
--output=summaryantes de aprofundar com--skyframe_state.
- Use aquery para depurar regressões; nós
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 de 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 regredir apenas o tempo decorrido, 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 deveria 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 deveria 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 lê arquivos dos seus sistemas 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.
Criação de 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
Como monitorar o uso da memória do Bazelinfo
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, existem
peak-heap-size,max-heap-size,used-heap-sizeecommitted-heap-size(consulte 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.
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 profiler de trace JSON também coleta o uso da memória persistente do worker durante a invocação ao passar a flag --experimental_collect_system_network_usage (novo no Bazel 6.0).

Figura 2. Perfil que inclui o uso da memória dos workers.
Diminuir 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. Assim, a largura de banda da sua rede pode afetar o desempenho da sua build.
Assim, a largura de banda da rede pode afetar o desempenho do build.NetworkMetrics.SystemNetworkStats--experimental_collect_system_network_usage
Além disso, os perfis de rastreamento JSON
permitem que você
visualize o uso da rede em todo o sistema durante o build, passando o
--experimental_collect_system_network_usage flag (novo no Bazel
6.0).

Figura 3. **Figura 3**.
Perfil que inclui o uso da rede em todo o sistema.--remote_download_minimal
Isso acelerará seus builds evitando o download de artefatos intermediários desnecessários.
Outra opção é configurar um cache de disco local para economizar largura de banda de download.