HeadlinesBriefing favicon HeadlinesBriefing.com

Buildprof Visualiza Tiempos de Compilación

Hacker News •
×

Creé buildprof (GitHub), una herramienta de código abierto que muestra dónde se gasta el tiempo cuando compilas software en Linux. Aquí hay un video en tiempo real de él perfilando una compilación limpia de ripgrep: Mira la demostración de buildprof. A veces, las compilaciones son lentas simplemente porque hay mucho código para compilar.

Pero más a menudo que no, hay problemas solucionables: paralelismo deficiente, trabajo repetido, descargas de dependencias o una enorme invocación del compilador/enlazador. buildprof hace todo esto claramente visible, para que puedas ver qué vale la pena investigar y optimizar. Lo ejecutas poniendo buildprof -- delante de cualquier comando de compilación que ya uses: buildprof -- make -j16, buildprof -- cargo build, buildprof -- ninja -C out/target, buildprof -- just build, buildprof -- ./dev/custom-build-script.sh. buildprof registra cada proceso que tu comando de compilación lanza, incluidos sus subprocesos (y los subprocesos de esos subprocesos...), y los dispone en una línea de tiempo. El tiempo se mueve de izquierda a derecha, el ancho de la barra muestra la duración, y los procesos hijos aparecen debajo de lo que los lanzó.

Creé buildprof porque este tweet de Jarred Sumner, arquitecto principal del tiempo de ejecución de Bun, estaba viviendo sin pagar alquiler en mi cabeza: Específicamente, la afirmación de que la nueva compilación Rust de Bun era más de 5 veces más rápida en Linux que su antigua compilación Zig. Realmente me preocupó. En mi experiencia, los proyectos Zig normalmente se compilaban mucho más rápido que proyectos Rust de complejidad similar.

Esa intuición fue suficiente para hacerme sentir que había un misterio por resolver. Esto se vio aún más complicado por otra importante, pero fácilmente pasada por alto, detalle en el tweet: la compilación Zig usaba Full LTO, mientras que la compilación Rust usaba Thin LTO. Los compiladores normalmente optimizan en gran medida las unidades de compilación separadas de forma aislada.

La optimización en tiempo de enlace (LTO) les permite optimizar a través de esas fronteras. Full LTO reúne esas unidades en un solo gran trabajo de optimización, mientras que Thin LTO preserva más separación de modo que gran parte del trabajo puede ejecutarse en paralelo. Basado en mi experiencia pasada, esta diferencia puede tener un efecto enorme en el tiempo de compilación.

El tweet la mencionó de pasada, pero me pregunté cuánto de la mejora en el titular realmente explicaba. Empecé intentando reproducir los números. Los números se reprodujeron.

Pero ahora qué? Descargué Bun 1.3.14 y Bun 1.4.0 y escribí scripts para reproducir sus compilaciones Linux x64 CI en una VM de Linux de 6 núcleos, 12 hilos. Los scripts preservaron los pasos de compilación y sus dependencias, ejecutando todo en una sola máquina. Mis mediciones estuvieron en la misma horquilla que las de Jarred: Linux x64 build Zig era 30m06s, Rust era 5m37s.

Mi replay de CI de una sola máquina 24m24s 5m40s. Bueno, así que la brecha también apareció en mi máquina. Pero había cambiado mucho entre las dos mediciones además del lenguaje; entonces, ¿qué era realmente responsable? ¿Era el compilador Zig el que estaba tomando todo ese tiempo extra? O quizás era el enlace Full LTO.

O quizás había algo más en la compilación de Bun que ni siquiera había pensado? Ahí es donde entró mi cerebro de análisis y herramientas para desarrolladores. Generalmente, cuando intento entender por qué algo lento, quiero un seguimiento: qué sucedió, cuándo sucedió y cuánto tiempo tomó. Sería realmente genial tener eso para estas compilaciones, para ponerlas en una línea de tiempo y ver dónde fue realmente su tiempo.

Pero una compilación involucra muchas herramientas diferentes, cada una con su propia idea de qué está sucediendo. ¿Qué podría registrar para poder ver a través de todas ellas? Las compilaciones son árboles de procesos. Cuando ejecutas cargo build o zig build, parece como si estuvieras ejecutando un solo programa. El sistema de compilación determina qué necesita reconstruir, entre esas piezas el orden y qué puede ejecutarse en paralelo.

Pero generalmente, no realiza todo ese trabajo en sí mismo; lanza compiladores, generadores de código, archivadores, enlazadores y scripts arbitrarios. Estos pueden lanzar más programas que lancen algunos más... Los diferentes sistemas de construcción describen ese trabajo de formas diferentes.

Cargo ve crates, Ninja ve bordes de construcción y CMake genera instrucciones para otro sistema de construcción. Desde el sistema operativo.