Ejecución dinámica

Informar un problema Ver fuente Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

La ejecución dinámica es una función en Bazel con la que la ejecución local y remota de la misma acción se inician en paralelo, con el resultado de la primera rama que finalice, cancelando la otra rama. Combina la potencia de ejecución o la gran caché compartida de un sistema de compilación remoto con la baja latencia de la ejecución local, lo que proporciona lo mejor de ambos mundos para compilaciones limpias e incrementales.

En esta página, se describe cómo habilitar, ajustar y depurar la ejecución dinámica. Si tienes configurada la ejecución local y remota y estás tratando de ajustar la configuración de Bazel para obtener un mejor rendimiento, esta página es para ti. Si aún no tienes configurada la ejecución remota, primero ve a la Descripción general de la ejecución remota de Bazel.

¿Quieres habilitar la ejecución dinámica?

El módulo de ejecución dinámica es parte de Bazel, pero para usar ya debes poder compilar de forma local y remota con la misma configuración de Bazel.

Para habilitar el módulo de ejecución dinámica, pasa la marca --internal_spawn_scheduler a Bazel. Esto agrega una nueva estrategia de ejecución llamada dynamic. Ahora puedes use esto como su estrategia para los mnemónicos que desea ejecutar dinámicamente, como --strategy=Javac=dynamic Consulta la siguiente sección para saber cómo elegir para qué mnemotecnias habilitar la ejecución dinámica.

Para cualquier mnemónico que use la estrategia dinámica, las estrategias de ejecución remota se toman de la marca --dynamic_remote_strategy y las estrategias locales de la marca --dynamic_local_strategy. Aprobación --dynamic_local_strategy=worker,sandboxed establece el valor predeterminado de la configuración de ejecución dinámica para probar con trabajadores o la ejecución de zona de pruebas en el orden personalizado. Pasar --dynamic_local_strategy=Javac=worker anula el valor predeterminado solo para la mnemónica de Javac. La versión remota funciona de la misma manera. Ambas marcas pueden especificar varias veces. Si una acción no se puede ejecutar localmente, es se ejecuten de forma remota como de costumbre, y viceversa.

Si tu sistema remoto tiene una caché, la marca --dynamic_local_execution_delay agrega un retraso en milisegundos a la ejecución local después de que el sistema remoto indicó un acierto de caché. Esto evita que se ejecute la ejecución local cuando más aciertos de caché más probables. El valor predeterminado es 1,000 ms, pero debería ajustarse para ser solo un poco más tiempo del que suelen tardar los aciertos de caché. La hora real depende tanto del control remoto del sistema y cuánto tiempo demora un recorrido de ida y vuelta. Por lo general, el valor será el mismo para todos los usuarios de un sistema remoto determinado, a menos que algunos de ellos estén lo suficientemente lejos como para agregar latencia de ida y vuelta. Puedes usar las funciones de generación de perfiles de Bazel para ver cuánto tiempo tardan los hits de caché típicos.

La ejecución dinámica se puede usar con la estrategia de zona de pruebas local y con trabajadores persistentes. Los trabajadores persistentes se ejecutarán automáticamente con la zona de pruebas cuando se usen con la ejecución dinámica y no podrán usar trabajadores de multiplexación. En los sistemas Darwin y Windows, la zona de pruebas la estrategia puede ser lenta; puedes pasar --reuse_sandbox_directories para reducir la sobrecarga de crear zonas de pruebas en estos sistemas.

La ejecución dinámica también se puede ejecutar con la estrategia standalone, aunque, como esta estrategia debe tomar el bloqueo de salida cuando comienza a ejecutarse, bloquea de manera eficaz que la estrategia remota termine primero. La marca --experimental_local_lockfree_output permite evitar este problema, ya que permite que la ejecución local escriba directamente en el resultado, pero que la ejecución remota la cancele si esta termina primero.

Si una de las ramas de la ejecución dinámica termina primero, pero falla, falla toda la acción. Esta es una opción intencional para evitar que pasen desapercibidas las diferencias entre la ejecución local y la remota.

Para obtener más información sobre cómo funcionan la ejecución dinámica y su bloqueo, consulta las excelentes entradas de blog de Julio Merino.

¿Cuándo debo usar la ejecución dinámica?

La ejecución dinámica requiere algún tipo de sistema de ejecución remota. Actualmente, no es posible usar un sistema remoto solo de caché, ya que una omisión de caché se consideraría una acción fallida.

No todos los tipos de acciones son adecuados para la ejecución remota. Los mejores candidatos son los que son inherentemente más rápidos a nivel local, por ejemplo, a través de el uso de trabajadores persistentes o aquellos que se ejecutan rápido para que la sobrecarga de la ejecución remota domine el tiempo de ejecución. Dado que cada acción ejecutada de forma local bloquea una cantidad de recursos de CPU y memoria, ejecutar acciones que no se encuentran en esas categorías solo retrasa la ejecución de las que sí lo hacen.

A partir de la versión 5.0.0-pre.20210708.4, la generación de perfiles de rendimiento contiene datos sobre la ejecución de los trabajadores, incluido el tiempo dedicado a finalizar una solicitud de trabajo después de perder una carrera de ejecución dinámica. Si ves subprocesos de trabajador de ejecución dinámica dedican mucho tiempo a adquirir recursos o a invertir async-worker-finish, es posible que tengas algunas acciones locales lentas que retrasan al trabajador conversaciones.

Cómo generar perfiles de datos con un rendimiento deficiente de ejecución dinámica

En el perfil anterior, que usa 8 trabajadores Javac, vemos muchos trabajadores Javac. perdieron las carreras y terminaron su trabajo en el async-worker-finish conversaciones. Esto se debe a que un mnemotécnico no trabajador que tomó suficientes recursos para retrasar a los trabajadores.

Cómo crear perfiles de datos con un mejor rendimiento de ejecución dinámica

Cuando solo se ejecuta Javac con ejecución dinámica, solo la mitad de los trabajadores iniciados terminan perdiendo la carrera después de iniciar su trabajo.

La marca --experimental_spawn_scheduler recomendada anteriormente dejó de estar disponible. Se activa la ejecución dinámica y se establece dynamic como la estrategia predeterminada para todos. mnemotécnicas que a menudo daría lugar a este tipo de problemas.

Rendimiento

El enfoque de ejecución dinámica supone que hay suficientes recursos disponibles de forma local y remota que vale la pena invertir algunos recursos adicionales para mejorar el rendimiento general. Sin embargo, el uso excesivo de recursos puede ralentizar Bazel o la máquina en la que se ejecuta, o ejercer una presión inesperada sobre un sistema remoto. Existen varias opciones para cambiar el comportamiento de la ejecución dinámica:

--dynamic_local_execution_delay retrasa el inicio de una rama local por una cantidad de milisegundos después de que se inicia la rama remota, pero solo si hubo un hit de caché remoto durante la compilación actual. Esto hace que las compilaciones que se beneficien del almacenamiento en caché remoto no desperdician recursos locales cuando es probable que la mayoría los resultados de búsqueda en la caché. Según la calidad de la caché, reducir este valor podría mejorar las velocidades de compilación, a costa de usar más recursos locales.

--experimental_dynamic_local_load_factor es una opción experimental de administración de recursos avanzada. Toma un valor de 0 a 1, 0 desactiva esta función. Cuando se establece en un valor superior a 0, Bazel ajusta la cantidad de acciones programadas de forma local cuando hay muchas acciones que esperan programación. Si se establece en 1, se podrán programar tantas acciones como haya hay CPU disponibles (según --local_cpu_resources). Los valores más bajos establecen el número de acciones programadas a un número menor de acciones a medida que aumenta la cantidad de acciones. que están disponibles para ejecutarse. Esto puede sonar contraintuitivo, pero con un buen control remoto de procesamiento, la ejecución local no es de mucha ayuda cuando se ejecutan muchas acciones y usar la CPU local para administrar acciones remotas.

--experimental_dynamic_slow_remote_time prioriza el inicio de ramas locales cuando la rama remota se ejecuta durante al menos este tiempo. Por lo general, la acción programada más recientemente tiene prioridad, ya que tiene más probabilidades de ganar la carrera, pero si el sistema remoto se bloquea o tarda demasiado, esto puede hacer que una compilación avance. Esta opción no está habilitada de forma predeterminada, ya que podría ocultar problemas con el sistema remoto que deberían corregirse. Asegúrate de que para supervisar el rendimiento del sistema remoto si habilitas esta opción.

Se puede usar --experimental_dynamic_ignore_local_signals para permitir que la rama remota se haga cargo cuando se cierre un inicio local debido a un indicador determinado. Este es es útil principalmente junto con los límites de recursos de los trabajadores (consulta --experimental_worker_memory_limit_mb, --experimental_worker_sandbox_hardening, y --experimental_sandbox_memory_limit_mb)), en las que los procesos de los trabajadores podrían finalizarse cuando usan demasiados recursos.

El perfil de seguimiento de JSON contiene una serie de gráficos relacionados con el rendimiento que pueden ayudar a identificar formas de mejorar el equilibrio entre el rendimiento y el uso de recursos.

Solución de problemas

Los problemas con la ejecución dinámica pueden ser sutiles y difíciles de depurar, ya que solo se pueden manifestar en algunas combinaciones específicas de ejecución local y remota. --debug_spawn_scheduler agrega un resultado adicional del sistema de ejecución dinámico que puede ayudar a depurar estos problemas. También puedes ajustar la marca --dynamic_local_execution_delay y la cantidad de trabajos remotos en comparación con los locales para facilitar la reproducción de los problemas.

Si tienes problemas con la ejecución dinámica con standalone prueba correr sin --experimental_local_lockfree_output o ejecuta tu zona de pruebas de acciones locales. Esto puede ralentizar un poco la compilación (consulta la sección anterior si está en Mac o Windows), pero quita algunas de las posibles causas de errores.