Bazel es complejo y realiza muchas acciones diferentes en el transcurso de una compilación, algunas de las cuales pueden afectar el rendimiento de la compilación. Esta página intenta asignar algunos de estos conceptos de Bazel a sus implicaciones en el rendimiento de la compilación. Mientras que no es exhaustiva, incluimos algunos ejemplos de cómo detectar el rendimiento de la compilación problemas a través de la extracción de métricas y lo que puedes hacer para solucionarlos. Con esto, esperamos que puedas aplicar estos conceptos cuando investigues regresiones de rendimiento de compilación.
Compilaciones limpias vs. compilaciones incrementales
Una compilación limpia es aquella que compila todo desde cero, mientras que una compilación compilación reutiliza algunos trabajos ya completados.
Sugerimos analizar las compilaciones incrementales y limpias por separado, en especial, cuando recopilas o agregas métricas que dependen del estado de Cachés de Bazel (por ejemplo, métricas de tamaño de las solicitudes de compilación ). También representan dos experiencias de usuario diferentes. En comparación con los valores iniciales una compilación limpia desde cero (lo que tarda más debido a una caché en frío), un proceso incremental las compilaciones ocurren con mucha más frecuencia a medida que los desarrolladores iteran en el código (por lo general, más rápido, dado que la caché ya suele estar caliente).
Puedes usar el campo CumulativeMetrics.num_analyses
en el BEP para clasificar
compilaciones. Si es num_analyses <= 1
, es una compilación limpia. De lo contrario, podemos ampliar
categorizarlo como una compilación incremental; el usuario podría haber cambiado
a diferentes marcas u objetivos diferentes, lo que causa una compilación limpia de forma efectiva. Cualquiera
es probable que una definición más rigurosa de incrementalidad deba presentarse
de una heurística, por ejemplo, observar la cantidad de paquetes cargados
(PackageMetrics.packages_loaded
).
Métricas de compilación deterministas como proxy para el rendimiento de la compilación
Medir el rendimiento de compilación puede ser difícil debido a su naturaleza no determinista. de ciertas métricas (por ejemplo, el tiempo de CPU de Bazel o los tiempos de cola en un clúster). Puede ser útil usar métricas deterministas como sustitutos la cantidad de trabajo que realiza Bazel, lo que, a su vez, afecta su rendimiento.
El tamaño de una solicitud de compilación puede tener una implicación significativa en la compilación rendimiento. Una compilación más grande podría representar más trabajo en el análisis y construir los grafos de compilación. El crecimiento orgánico de las compilaciones es natural a medida que se agregan/crean más dependencias y, por lo tanto, aumentan en complejidad y será cada vez más costoso crearlos.
Podemos dividir este problema en varias fases de compilación y usar lo siguiente como métricas sustitutas del trabajo realizado en cada fase:
PackageMetrics.packages_loaded
: Es la cantidad de paquetes que se cargaron de forma correcta. Aquí, una regresión representa más trabajo que se debe hacer para leer y analizar cada archivo de COMPILACIÓN adicional en la fase de carga.TargetMetrics.targets_configured
: que representa la cantidad de objetivos y configurados en la compilación. Una regresión representa más trabajo en construir y recorrer el grafo de destino configurado.- A menudo, esto se debe a la adición de dependencias y a tener que construir el gráfico de su cierre transitivo.
- Usa cquery para encontrar dónde se ingresa dependencias podría haberse agregado.
ActionSummary.actions_created
: Representa las acciones creadas en la compilación. y una regresión representa más trabajo en la construcción del gráfico de acciones. Nota también incluye las acciones sin usar que podrían no haberse ejecutado.- Usar aquery para depurar regresiones
te sugerimos que empieces
--output=summary
antes de desglosar aún más--skyframe_state
.
- Usar aquery para depurar regresiones
te sugerimos que empieces
ActionSummary.actions_executed
: Es la cantidad de acciones ejecutadas, una la regresión representa directamente más trabajo en la ejecución de estas acciones.- El BEP escribe las estadísticas de acción.
ActionData
, que muestra los tipos de acciones más ejecutadas. De forma predeterminada, recopila los 20 tipos de acciones principales, pero puedes pasar los--experimental_record_metrics_for_all_mnemonics
para recopilar estos datos en todos los tipos de acciones que se ejecutaron. - Esto debería ayudarte a determinar qué tipo de acciones se ejecutaron (adicionalmente).
- El BEP escribe las estadísticas de acción.
BuildGraphSummary.outputArtifactCount
: La cantidad de artefactos que crea las acciones ejecutadas.- Si la cantidad de acciones ejecutadas no aumentó, es probable que se cambió la implementación de una regla.
Todas estas métricas se ven afectadas por el estado de la caché local, por lo que deberás debes asegurarte de que las compilaciones de las que extraes estas métricas compilaciones limpias.
Notamos que una regresión en cualquiera de estas métricas puede estar acompañada de en tiempo real, tiempo de CPU y uso de memoria.
Uso de recursos locales
Bazel consume una variedad de recursos en tu máquina local (tanto para analizar el grafo de compilación, controlar la ejecución y ejecutar acciones locales). puede afectar el rendimiento o la disponibilidad de tu máquina a la hora de realizar la compilar y otras tareas.
Tiempo transcurrido
Quizás las métricas más susceptibles al ruido (y pueden variar mucho de la compilación
de construir) es tiempo; en particular: tiempo de pared, tiempo de CPU y tiempo del sistema. Puedes
usa bazel-bench para obtener
una comparativa para estas métricas y, con una cantidad suficiente de --runs
, puedes
aumentar la importancia estadística de tus mediciones.
El tiempo real es el tiempo real transcurrido.
- Si solo disminuye el tiempo, te sugerimos recopilar un el perfil de seguimiento de JSON y buscar para ver las diferencias. De lo contrario, probablemente sería más eficiente investigar otras métricas regresivas, ya que podrían haber afectado el muro tiempo.
El tiempo de CPU es el tiempo que dedica la CPU a ejecutar el código de usuario.
- Si el tiempo de CPU disminuye en dos confirmaciones del proyecto, te sugerimos recopilar
un perfil de CPU de Starlark. Es probable que también debas usar
--nobuild
para restringir la compilación a la fase de análisis, ya que allí es donde la mayoría de se completó el trabajo pesado de la CPU.
- Si el tiempo de CPU disminuye en dos confirmaciones del proyecto, te sugerimos recopilar
un perfil de CPU de Starlark. Es probable que también debas usar
El tiempo del sistema es el tiempo que dedica la CPU al kernel.
- Si el tiempo del sistema disminuye, se correlaciona principalmente con la E/S cuando Bazel lee desde tu sistema de archivos.
Creación de perfiles de carga en todo el sistema
Con el
--experimental_collect_load_average_in_profiler
estándar que se introdujo en Bazel 6.0, el
El Generador de perfiles de seguimiento de JSON recopila
promedio de carga del sistema durante la invocación.
Figura 1: Perfil que incluye la carga promedio del sistema.
Una carga alta durante una invocación de Bazel puede indicar que Bazel programa
demasiadas acciones locales en paralelo para tu máquina. Te recomendamos analizar
ajustando
--local_cpu_resources
y --local_ram_resources
,
especialmente en entornos de contenedores (al menos hasta
#16512 está combinado).
Supervisa el uso de memoria de Bazel
Hay dos fuentes principales para obtener el uso de memoria de Bazel: info
de Bazel y el
BEP:
bazel info used-heap-size-after-gc
: La cantidad de memoria usada en bytes después de una llamada aSystem.gc()
.- Banco Bazel ofrece comparativas para esta métrica.
- Además, hay
peak-heap-size
,max-heap-size
yused-heap-size
ycommitted-heap-size
(consulta documentación), pero están menos relevantes.
BEP
MemoryMetrics.peak_post_gc_heap_size
: El tamaño máximo del montón de JVM en bytes después de la recolección de elementos no utilizados (requiere configuración--memory_profile
que intenta forzar una recolección de elementos no utilizados completa).
Una regresión en el uso de la memoria suele ser el resultado de una regresión en métricas de tamaño de las solicitudes de compilación, que, a menudo, se deben a la adición de dependencias o a un cambio en la regla para implementarlos.
Para analizar el uso de memoria de Bazel en un nivel más detallado, te recomendamos usar el generador de perfiles de memoria integrado para las reglas.
Generación de perfiles de memoria de trabajadores persistentes
Si bien los trabajadores persistentes pueden ayudar a acelerar las compilaciones,
significativamente (especialmente para lenguajes interpretados) su espacio en memoria puede
ser problemático. Bazel recopila métricas sobre sus trabajadores, en particular, el
El campo WorkerMetrics.WorkerStats.worker_memory_in_kb
indica cuánta memoria
que usan los trabajadores (por mnemotecnia).
El generador de perfiles de seguimiento de JSON también
recopila el uso de memoria persistente del trabajador durante la invocación pasando el valor
--experimental_collect_system_network_usage
(nueva en Bazel 6.0).
Figura 2: Perfil que incluye el uso de memoria de los trabajadores.
Disminuir el valor de
--worker_max_instances
(valor predeterminado 4) puede ayudar a reducir
la cantidad de memoria que usan los trabajadores persistentes. Estamos trabajando activamente en
lo que hace que el programador y el administrador de recursos
de Bazel sean más inteligentes para que el ajuste
se necesitarán con menos frecuencia en el futuro.
Supervisa el tráfico de red para compilaciones remotas
En la ejecución remota, Bazel descarga artefactos que se compilaron como resultado de en la ejecución de acciones. El ancho de banda de tu red puede afectar el rendimiento de tu compilación.
Si usas la ejecución remota para tus compilaciones, te recomendamos considerar
para supervisar el tráfico de red durante la invocación
Proto NetworkMetrics.SystemNetworkStats
de BEP
(requiere pasar --experimental_collect_system_network_usage
).
Además, los perfiles de seguimiento de JSON
te permiten ver el uso de la red de todo el sistema durante la compilación
pasando la marca --experimental_collect_system_network_usage
(nuevo en Bazel)
6.0).
Figura 3: Perfil que incluye el uso de red en todo el sistema.
Un uso de red alto, pero bastante plano, cuando se usa la ejecución remota, puede indicar
esa red es el cuello de botella en tu compilación. si todavía no la estás usando,
considera activar Compilación sin los Bytes pasando
--remote_download_minimal
Esto acelerará tus compilaciones al evitar la descarga de artefactos intermedios innecesarios.
Otra opción es configurar una red local caché de disco para guardar ancho de banda de descarga.