Esta página descreve como otimizar o desempenho do build do Bazel ao executar o Bazel repetidamente.
Estado 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 ao usuário e recebe comandos dele.A ferramenta CLI inicia um servidor do Bazel para cada base de saída distinta. O servidor do Bazel geralmente é persistente, mas é encerrado após um período de inatividade para não desperdiçar recursos.
O servidor do Bazel executa as etapas de carregamento e análise para 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 enviar ações para execução remota, se estiver configurado para isso. Os resultados das execuções de ação também são armazenados em cache, especificamente no cache de ação (ou cache de execução, que pode ser local ou remoto e compartilhado entre servidores do Bazel).
O resultado da invocação do Bazel é disponibilizado na árvore de saída.
Como executar o Bazel de forma iterativa
Em um fluxo de trabalho típico de desenvolvedor, é comum criar (ou executar) um 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 o menor overhead possível em relação à
ação repetida subjacente (por exemplo, invocar um compilador ou executar um teste).
Com isso em mente, vamos analisar novamente o estado de execução do Bazel:
O cache de análise é um conjunto de dados importante. Uma quantidade significativa de tempo pode ser gasta apenas nas fases de carregamento e análise de uma execução fria (ou seja, uma execução logo após o servidor do Bazel ter sido iniciado ou quando o cache de análise foi descartado). Para um único build a frio bem-sucedido (por exemplo, para uma versão de produção), esse custo é aceitável, mas, para criar repetidamente o mesmo destino, é importante que esse custo seja amortizado e não repetido em cada invocação.
O cache de análise é bastante volátil. Primeiro, ele faz parte do estado em processo
do servidor do Bazel. Portanto, perder o servidor significa perder o cache. No entanto, o cache
também é invalidado com muita facilidade. Por exemplo, muitas flags de linha de comando bazel
fazem com que o cache seja descartado. Isso acontece porque muitas flags afetam o gráfico
de build, por exemplo, por causa de
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 é valioso para o desempenho do build. Um cache de execução pode ser mantido localmente no disco ou remotamente. O cache pode ser compartilhado entre os servidores do Bazel e, de fato, entre os desenvolvedores.
Evite descartar o cache de análise
O Bazel vai mostrar um aviso se o cache de análise for descartado ou se o servidor for reiniciado. Evite as seguintes práticas durante o uso iterativo:
Não mude as flags
bazel
no meio de um fluxo iterativo. Por exemplo, misturar umbazel build -c opt
com umbazel cquery
faz com que cada comando descarte o cache de análise do outro. Em geral, tente usar um conjunto fixo de flags durante um fluxo de trabalho específico.A perda do servidor do Bazel faz com que o cache de análise seja perdido. O servidor do Bazel tem um tempo de inatividade configurável, após o qual ele é encerrado. É possível configurar esse tempo usando o arquivo bazelrc para atender às suas necessidades. O servidor também é reinicializado quando as flags de inicialização mudam. Portanto, evite mudar essas flags, se possível.
Cuidado: o servidor do Bazel é 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 uma vez para solicitar um encerramento suave da invocação atual.
Se você quiser usar vários conjuntos de flags no mesmo espaço de trabalho, use várias bases de saída distintas, alternadas com a flag
--output_base
. Cada base de saída recebe o próprio servidor do Bazel.