Detalhamento do desempenho do build

Informar um problema Mostrar fonte Por noite · 7,3 · 7,2 · 7,1 · 7,0 · 6,5

O Bazel é complexo e faz muitas coisas diferentes ao longo de um build, algumas delas podem ter impacto no desempenho do build. Esta página tenta mapear alguns desses conceitos do Bazel às implicações deles no desempenho do build. não é extenso, incluímos alguns exemplos de como detectar o desempenho do build problemas por meio da extração de 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 vs. incrementais

Um build limpo é aquele que cria tudo do zero, enquanto um build incremental reutiliza parte do trabalho já concluído.

Sugerimos analisar builds limpos e incrementais separadamente, especialmente quando você está coletando / agregando métricas que dependem do estado do 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 lançamento um build limpo do zero (o que leva mais tempo devido a um cache frio), builds acontecem com muito mais frequência à medida que os desenvolvedores fazem iterações no código (normalmente mais rápido, porque o cache geralmente já está quente).

É possível usar o campo CumulativeMetrics.num_analyses no BEP para classificar builds. Se for num_analyses <= 1, será um build limpo. de outra forma, podemos amplamente categorizá-lo como sendo uma versão incremental. O usuário poderia ter mudado para diferentes sinalizações ou destinos diferentes, causando um build efetivamente limpo. Qualquer um uma definição mais rigorosa de incrementabilidade provavelmente terá que de uma heurística, por exemplo, analisar o número de pacotes carregados (PackageMetrics.packages_loaded).

Métricas deterministas de build como substitutos do desempenho do build

Medir o desempenho do build pode ser difícil devido à natureza não determinista de determinadas métricas, como o tempo de CPU do Bazel ou os tempos de fila em um controle cluster). Assim, pode ser útil usar métricas determinísticas como substitutos 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 consequência significativa na criação desempenho. Um build maior pode representar mais trabalho de análise e a construção dos gráficos de build. O crescimento orgânico de construções ocorre naturalmente com desenvolvimento, à medida que mais dependências são adicionadas/criadas, aumentando a complexidade e o custo de criação deles será maior.

Podemos dividir esse problema nas várias fases de compilação e usar o seguinte como métricas substitutas para o trabalho realizado em cada fase:

  1. PackageMetrics.packages_loaded: o número de pacotes carregados. Uma regressão aqui representa mais trabalho que precisa ser feito para ler e analisar cada arquivo BUILD adicional na fase de carregamento.

    • Isso geralmente se deve à adição de dependências e à necessidade de carregar fechamento transitivo.
    • Use query / cquery para encontrar em que novas dependências podem ter sido adicionadas.
  2. TargetMetrics.targets_configured: representa o número de segmentações e de configuração configurados no build. Uma regressão representa mais trabalho construindo e atravessando o gráfico de destino configurado.

    • Isso geralmente se deve à adição de dependências e à necessidade de construir o gráfico do fechamento transitivo.
    • Use cquery para descobrir onde novos dependências podem ter sido adicionadas.
  3. 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. Observação isso também inclui ações não usadas que podem não ter sido executadas.

  4. ActionSummary.actions_executed: o número de ações executadas, um a regressão representa diretamente mais trabalho na execução dessas ações.

    • O BEP grava as estatísticas da ação ActionData que mostra os tipos de ação mais executados. Por padrão, ele que coleta os 20 principais tipos de ação, mas você pode passar o --experimental_record_metrics_for_all_mnemonics para 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 (além disso).
  5. BuildGraphSummary.outputArtifactCount: o número de artefatos criados por as ações executadas.

    • Se o número de ações executadas não aumentou, é provável que a implementação de uma regra foi alterada.

Todas essas métricas são afetadas pelo estado do cache local. Portanto, você para garantir que os builds dos quais você extrai essas métricas sejam builds limpos.

Observamos que uma regressão em qualquer uma dessas métricas pode ser acompanhada regressões em tempo decorrido, tempo de CPU e uso de memória.

Uso de recursos locais

O Bazel consome vários recursos na máquina local (ambos para análise o gráfico de build e a execução da execução, e para executar ações locais), isso pode afetar o desempenho e a disponibilidade da máquina na realização criação e também outras tarefas.

Tempo gasto

Talvez as métricas mais suscetíveis ao ruído (e possam variar muito da criar) é o tempo. especificamente em tempo decorrido, tempo de CPU e do sistema. Você pode use o bazel-bench para um comparativo de mercado para essas métricas e, com um número suficiente de --runs, é possível aumentar a significância estatística da medição.

  • O tempo decorrido é o tempo real decorrido.

    • Se apenas o tempo decorrido regressar, sugerimos coletar uma perfil de trace JSON e analisando para conferir as diferenças. Caso contrário, provavelmente seria mais eficiente investigar outras métricas regressivas, porque elas poderiam ter afetado o muro tempo de resposta.
  • Tempo de CPU é o tempo gasto pela CPU executando o código do usuário.

    • Se o tempo de CPU regressar em duas confirmações de projeto, sugerimos coletar um perfil de CPU Starlark. Você provavelmente também deve usar --nobuild para restringir o build à fase de análise, já que é nela que a maioria dos O trabalho pesado de CPU foi concluído.
  • O tempo do sistema é o tempo gasto pela CPU no kernel.

    • Se o tempo do sistema regressa, isso é principalmente 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

Usar o --experimental_collect_load_average_in_profiler introduzida no Bazel 6.0, a O criador de perfil de trace JSON coleta a média de carga do sistema durante a invocação.

Perfil que inclui a média de carga do sistema

Figura 1. Perfil que inclui a média de carga do sistema.

Uma carga alta durante uma invocação do Bazel pode ser uma indicação de que o Bazel programa muitas ações locais em paralelo na sua máquina. Talvez você queira analisar ajustando --local_cpu_resources e --local_ram_resources, especialmente em ambientes de contêiner (pelo menos até #16512 foi mesclado).

Como monitorar o uso de memória do Bazel

Há duas origens principais para conferir o uso da memória do Bazel: a info do Bazel e a BEP:

  • bazel info used-heap-size-after-gc: a quantidade de memória usada em bytes após uma chamada para System.gc().

    • Banco Bazel também fornece comparativos de mercado para essa métrica.
    • Além disso, há peak-heap-size, max-heap-size e used-heap-size e committed-heap-size (consulte documentação), mas são menos relevantes.
  • BEP MemoryMetrics.peak_post_gc_heap_size: tamanho do tamanho do heap de pico da JVM em bytes pós-GC (requer configuração --memory_profile que tenta forçar uma GC completa).

Uma regressão no uso da memória geralmente é resultado de uma regressão na métricas de tamanho de solicitação de build, que geralmente ocorrem devido à adição de dependências ou a uma mudança na regra implementação.

Para analisar o consumo de memória do Bazel em um nível mais granular, recomendamos usar o Memory Profiler integrado para conhecer as regras.

Criação de perfil de memória de workers permanentes

Os workers permanentes podem ajudar a acelerar os builds significativamente (especialmente para linguagens interpretadas), o consumo de memória pode ser problemáticos. O Bazel coleta métricas dos workers, principalmente O campo WorkerMetrics.WorkerStats.worker_memory_in_kb informa quanta memória que os trabalhadores usam (mnemônicos).

O criador de perfil de rastreamento JSON também coleta o uso da memória do worker persistente durante a invocação passando o --experimental_collect_system_network_usage (nova no Bazel 6.0).

Perfil que inclui o uso de memória dos workers

Figura 2. Perfil que inclui o uso de memória dos workers.

Diminuir o valor --worker_max_instances (padrão 4) pode ajudar a reduzir a quantidade de memória usada pelos workers permanentes. Estamos trabalhando tornando o gerenciador de recursos e o programador do Bazel mais inteligentes para que serão necessários com menos frequência no futuro.

Como monitorar o tráfego de rede para compilações remotas

Na execução remota, o Bazel faz o download dos artefatos criados como resultado de e executar ações. Dessa forma, a largura de banda da rede pode afetar o desempenho do seu build.

Se você estiver usando a execução remota para suas compilações, convém considerar monitorar o tráfego de rede durante a invocação usando o .proto NetworkMetrics.SystemNetworkStats do BEP; (é necessário passar em --experimental_collect_system_network_usage).

Além disso, os perfis de trace JSON permitem que você confira o uso da rede em todo o sistema durante o build passando a flag --experimental_collect_system_network_usage (nova no Bazel 6.0).

Perfil que inclui o uso de rede em todo o sistema

Figura 3. Perfil que inclui o uso de rede em todo o sistema.

Um uso de rede alto, mas plano ao utilizar a execução remota, pode indicar essa rede é o gargalo no seu build. caso ainda não o use, considere ativar o build sem os bytes passando --remote_download_minimal Isso acelera os builds, evitando o download de artefatos intermediários desnecessários.

Outra opção é configurar uma cache em disco para economizar largura de banda de download.