Execução dinâmica

Reportar um problema Ver código-fonte Nightly · 8.0 . 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

A execução dinâmica é um recurso do Bazel desde a versão 0.21, em que a execução local e remota da mesma ação são iniciadas em paralelo, usando a saída da primeira ramificação que é concluída, cancelando a outra ramificação. Ele combina a capacidade de execução e/ou o cache compartilhado grande de um sistema de build remoto com a baixa latência da execução local, oferecendo o melhor dos dois mundos para builds limpos e incrementais.

Esta página descreve como ativar, ajustar e depurar a execução dinâmica. Se você configurou a execução local e remota e está tentando ajustar as configurações do Bazel para melhorar o desempenho, esta página é para você. Se você ainda não tiver configurado a execução remota, acesse a Visão geral da execução remota do Bazel.

Ativando a execução dinâmica?

O módulo de execução dinâmica faz parte do Bazel, mas, para usar a execução dinâmica, você precisa ser capaz de compilar local e remotamente na mesma configuração do Bazel.

Para ativar o módulo de execução dinâmica, transmita a flag --internal_spawn_scheduler para o Bazel. Isso adiciona uma nova estratégia de execução chamada dynamic. Agora é possível usar essa estratégia para os mnemônicos que você quer executar dinamicamente, como --strategy=Javac=dynamic. Consulte a próxima seção para saber como escolher quais mnemônicos ativar para a execução dinâmica.

Para qualquer mnemônico que use a estratégia dinâmica, as estratégias de execução remota são tomadas da flag --dynamic_remote_strategy, e as estratégias locais da flag --dynamic_local_strategy. A transmissão de --dynamic_local_strategy=worker,sandboxed define o padrão para a execução dinâmica local a ser testada com workers ou execução em sandbox nessa ordem. A transmissão de --dynamic_local_strategy=Javac=worker substitui o padrão apenas para a mnemônica Javac. A versão remota funciona da mesma forma. Ambas as flags podem ser especificadas várias vezes. Se uma ação não puder ser executada localmente, ela será executada remotamente normalmente e vice-versa.

Se o sistema remoto tiver um cache, a flag --local_execution_delay adiciona um atraso em milissegundos à execução local depois que o sistema remoto indicar uma correspondência de cache. Isso evita a execução local quando mais acertos de cache são prováveis. O valor padrão é 1000ms, mas precisa ser ajustado para ser um pouco mais longo do que as ocorrências em cache geralmente são. O tempo real depende do sistema remoto e do tempo que uma ida e volta leva. Normalmente, o valor será o mesmo para todos os usuários de um determinado sistema remoto, a menos que alguns deles estejam longe o suficiente para adicionar latência de ida e volta. Você pode usar os recursos de criação de perfil do Bazel para conferir o tempo médio de acessos ao cache.

A execução dinâmica pode ser usada com a estratégia de sandbox local e com workers persistentes. Os workers persistentes são executados automaticamente com sandboxing quando usados com execução dinâmica e não podem usar workers múltiplos. Em sistemas Darwin e Windows, a estratégia de sandbox pode ser lenta. Você pode transmitir --reuse_sandbox_directories para reduzir a sobrecarga da criação de sandboxes nesses sistemas.

A execução dinâmica também pode ser executada com a estratégia standalone. No entanto, como a estratégia standalone precisa usar o bloqueio de saída quando começa a ser executada, ela bloqueia efetivamente a estratégia remota para que ela não termine primeiro. A flag --experimental_local_lockfree_output permite contornar esse problema, permitindo que a execução local seja gravada diretamente na saída, mas seja abortada pela execução remota, caso ela termine primeiro.

Se uma das ramificações da execução dinâmica terminar primeiro, mas falhar, a ação inteira falhará. Essa é uma escolha intencional para evitar que as diferenças entre a execução local e remota passem despercebidas.

Para mais informações sobre como a execução dinâmica e o bloqueio funcionam, consulte as excelentes postagens do blog de Julio Merino.

Quando devo usar a execução dinâmica?

A execução dinâmica requer algum tipo de sistema de execução remota. No momento, não é possível usar um sistema remoto somente de cache, porque uma falha de cache seria considerada uma ação com falha.

Nem todos os tipos de ação são adequados para execução remota. Os melhores candidatos são aqueles que são inerentemente mais rápidos localmente, por exemplo, pelo uso de workers persistentes, ou aqueles que são executados rápido o suficiente para que a sobrecarga da execução remota domine o tempo de execução. Como cada ação executada localmente bloqueia uma quantidade de recursos de CPU e memória, a execução de ações que não se enquadram nessas categorias apenas atrasa a execução das que se enquadram.

A partir da versão 5.0.0-pre.20210708.4, o Perfil de desempenho contém dados sobre a execução do worker, incluindo o tempo gasto para concluir uma solicitação de trabalho depois de perder uma corrida de execução dinâmica. Se você notar que as linhas de execução de execução dinâmica gastam muito tempo adquirindo recursos ou muito tempo no async-worker-finish, talvez algumas ações locais lentas estejam atrasando as linhas de execução.

Criar perfis de dados com desempenho de execução dinâmica ruim

No perfil acima, que usa oito workers Javac, muitos workers Javac perderam as corridas e terminaram o trabalho nas linhas de execução async-worker-finish. Isso foi causado por uma mnemônica não relacionada a workers que consumiu recursos suficientes para atrasar os workers.

Criar perfis de dados com melhor performance de execução dinâmica

Quando apenas o Javac é executado com execução dinâmica, apenas cerca de metade dos workers iniciais acabam perdendo a corrida depois de iniciar o trabalho.

A flag --experimental_spawn_scheduler recomendada anteriormente foi descontinuada. Ele ativa a execução dinâmica e define dynamic como a estratégia padrão para todos os mnemônicos, o que geralmente leva a esse tipo de problema.

Solução de problemas

Problemas com a execução dinâmica podem ser sutis e difíceis de depurar, já que podem se manifestar apenas em algumas combinações específicas de execução local e remota. O --debug_spawn_scheduler adiciona uma saída extra do sistema de execução dinâmico que pode ajudar a depurar esses problemas. Também é possível ajustar a flag --local_execution_delay e o número de jobs remotos e locais para facilitar a reprodução dos problemas.

Se você tiver problemas com a execução dinâmica usando a estratégia standalone, tente executar sem --experimental_local_lockfree_output ou execute suas ações locais em modo sandbox. Isso pode deixar seu build um pouco mais lento (confira acima se você estiver usando Mac ou Windows), mas remove algumas causas possíveis de falhas.