Otimizar a velocidade de iteração

Informar um problema Ver origem

Nesta página, descrevemos como otimizar o desempenho de build do Bazel ao executá-lo repetidamente.

Estado do ambiente de execução do Bazel

Uma invocação do Bazel envolve várias partes que interagem.

  • A interface de linha de comando (CLI) bazel é a ferramenta de front-end voltada para o usuário e recebe comandos dele.

  • A ferramenta CLI inicia um servidor Bazel para cada base de saída distinta. O servidor do Bazel geralmente é persistente, mas vai ser desligado após algum tempo de inatividade para não desperdiçar recursos.

  • O servidor do Bazel executa as etapas de carregamento e análise de um determinado comando (build, run, cquery etc.), em que ele constrói as partes necessárias do gráfico de build na memória. As estruturas de dados resultantes são retidas no servidor do Bazel como parte do cache de análise.

  • O servidor do Bazel também pode executar a ação ou enviá-las para execução remota, se estiver configurado para isso. Os resultados das execuções de ações também são armazenados em cache, ou seja, no cache de ações (ou cache de execução, que pode ser local ou remoto e pode ser compartilhado entre servidores do Bazel).

  • O resultado da invocação do Bazel é disponibilizado na árvore de saída.

Como executar o Bazel iterativamente

Em um fluxo de trabalho típico de desenvolvedor, é comum criar (ou executar) uma parte de código repetidamente, geralmente com uma frequência muito alta (por exemplo, para resolver algum erro de compilação ou investigar um teste com falha). Nessa situação, é importante que as invocações repetidas de bazel tenham a menor sobrecarga possível em relação à ação repetida e subjacente, por exemplo, invocar um compilador ou executar um teste.

Com isso em mente, vamos analisar novamente o estado do tempo de execução do Bazel:

O cache de análise é um dado essencial. Uma quantidade significativa de tempo pode ser gasta apenas nas fases de carregamento e análise de uma execução a frio, ou seja, uma execução logo após a inicialização do servidor do Bazel ou quando o cache de análise foi descartado. Esse custo é aceitável para um build a frio único e bem-sucedido (por exemplo, para uma versão de produção). No entanto, para criar repetidamente o mesmo destino, é importante que esse custo seja amortizado e não repetido a cada invocação.

O cache de análise é bastante volátil. Primeiro, ele faz parte do estado em processo do servidor do Bazel. Portanto, se o servidor for perdido, o cache será perdido. Mas o cache também é invalidado com muita facilidade: por exemplo, muitas sinalizações de linha de comando bazel fazem com que o cache seja descartado. Isso ocorre porque muitas sinalizações afetam o gráfico do build, por exemplo, devido a atributos configuráveis. Algumas mudanças de flag também podem fazer com que o servidor do Bazel seja reiniciado (por exemplo, mudar as opções de inicialização).

Um bom cache de execução também é vantajoso para o desempenho do build. Ele pode ser mantido localmente no disco ou remotamente. O cache pode ser compartilhado entre servidores Bazel e, até mesmo, entre desenvolvedores.

Evite descartar o cache de análise

O Bazel vai imprimir um aviso se o cache de análise for descartado ou o servidor for reiniciado. Evite qualquer uma destas situações durante o uso iterativo:

  • Tenha cuidado ao mudar as sinalizações bazel no meio de um fluxo de trabalho iterativo. Por exemplo, misturar um bazel build -c opt com um bazel cquery faz com que cada comando descarte o cache de análise do outro. Em geral, tente usar um conjunto fixo de sinalizações durante um determinado fluxo de trabalho.

  • Se o servidor do Bazel for perdido, o cache de análise será perdido. O servidor do Bazel tem um tempo de inatividade configurável. Depois disso, ele é desligado. É possível configurar esse tempo por meio do arquivo bazelrc para atender às suas necessidades. O servidor também é reiniciado quando as sinalizações de inicialização mudam. Portanto, evite alterá-las, se possível.

  • Esteja ciente de que o servidor do Bazel será encerrado se você pressionar Ctrl-C repetidamente enquanto o Bazel estiver em execução. É tentador tentar economizar tempo interrompendo um build em execução que não é mais necessário, mas pressione Ctrl-C apenas uma vez para solicitar um final otimizado da invocação atual.

  • Para usar vários conjuntos de sinalizações do mesmo espaço de trabalho, utilize várias bases de saída distintas com a sinalização --output_base. Cada base de saída recebe um servidor do Bazel próprio.

Para transformar essa condição em um erro em vez de um aviso, use a flag --noallow_analysis_cache_discard (introduzida no Bazel 6.4.0).