La velocidad de compilación de Zig está mejorando
(mitchellh.com)- Con el lanzamiento de Zig 0.15.1, la velocidad de compilación mejoró notablemente frente a la versión anterior
- En el proyecto Ghostty, al medir los tiempos reales de build, se observó en general una reducción en el tiempo de ejecución del proceso
- Aunque todavía usa LLVM en parte, hay grandes expectativas de mejoras adicionales de velocidad cuando se aplique por completo su backend propio
- La compilación incremental (incremental compilation) aún no está implementada por completo, pero ya se notan ventajas de rendimiento incluso en builds parciales
- Es muy probable que en adelante se haga realidad un entorno de build más rápido y una mejor experiencia de desarrollo
Resumen
Partiendo de la frase de Andrew Kelley, "el compilador es tan lento que genera bugs", Zig ha llevado durante años diversos esfuerzos de mejora estructural con el objetivo de lograr tiempos de compilación más rápidos
- El equipo de Zig ha estado trabajando en eliminar LLVM, desarrollar su propio backend de generación de código, construir un linker propio y, en última instancia, hacer realidad la compilación incremental
- Los resultados de este desarrollo de largo plazo empezaron a hacerse visibles en la versión Zig 0.15.1, y se compartieron mediciones de los cambios en tiempo de build en un proyecto real (Ghostty)
Velocidad de compilación del Build Script
- Zig 0.14: 7 segundos 167 ms
- Zig 0.15: 1 segundo 702 ms
Es el tiempo de build del propio script build.zig, y representa un costo inicial que se paga cada vez en un entorno de compilación de código fuente nuevo
- La frecuencia de recompilación del script de build se mantiene baja, pero impacta directamente en la experiencia del usuario cuando compila el proyecto por primera vez
Build completo del binario sin caché (Ghostty)
- Zig 0.14: 41 segundos
- Zig 0.15: 32 segundos
Es el tiempo total de build del binario, incluyendo también el tiempo de compilación del script de build
- Con Zig 0.15 hay además una mejora adicional de alrededor de 2 segundos, y la diferencia inicial también es clara en tiempo real de reloj
- El backend x86_64 propio todavía no se está aprovechando por completo, y en la mayoría de los casos se sigue usando LLVM
- Se estima que, cuando Ghostty se compile por completo con el backend propio, el tiempo podría bajar de 25 segundos (aproximadamente la mitad frente a antes)
Build incremental (ejecutable de Ghostty)
- Zig 0.14: 19 segundos
- Zig 0.15: 16 segundos
Es el tiempo requerido para volver a compilar después de un cambio significativo de una línea (agregar una llamada de log en el código de emulación de terminal)
- Se trata de un build parcial en una situación donde el script de build y el grafo de dependencias ya están en caché
- Aunque la compilación incremental aún no está completamente implementada, la mejora de rendimiento ya se ve con claridad
- Si se excluye LLVM en uso, hay posibilidad de reducirlo hasta alrededor de 12 segundos
- Cuando se implemente una compilación incremental real, incluso se espera la posibilidad de builds en milisegundos
Build incremental (libghostty-vt)
- Zig 0.14: 2 segundos 884 ms
- Zig 0.15: 975 ms
Medición del tiempo para recompilar parcialmente solo libghostty-vt después de un cambio de una línea
libghostty-vtpuede compilarse por completo con el backend x86_64 propio, por lo que las mejoras de Zig se reflejan directamente sin la influencia de LLVM- Incluso sin compilación incremental, lograr un tiempo de build por debajo de 1 segundo ya es un avance considerable
- Mejora la eficiencia en el flujo de trabajo del desarrollador gracias a una experiencia de retroalimentación inmediata
- Los backends x86_64 y aarch64 están volviéndose cada vez más estables, y existe la posibilidad de aplicarlos a todo Ghostty en los próximos meses
Estado actual de las mejoras en velocidad de build
- El build de Ghostty usando Zig 0.15.1 es claramente más rápido en todos los puntos medidos
- Aunque el backend propio y la compilación incremental aún no están terminados, los resultados actuales por sí solos ya son bastante impresionantes
- Se espera que en los próximos 1 a 2 años lleguen mejoras de velocidad todavía más revolucionarias
- Cada vez se siente más razonable haber elegido Zig desde la perspectiva de la velocidad de build
1 comentarios
Comentarios en Hacker News
Al graduarme de la preparatoria en 1995, recompilar "Borland Pascal versión Turbo Vision for DOS" en una Intel 486 era más o menos así de rápido; ahora por fin vuelvo a sentir velocidades de compilación realmente rápidas
Turbo Vision era un framework de ventanas TUI, usado en el desarrollo de los IDE de Borland Pascal y C++
Se podría decir que era como un JetBrains IDE en modo carácter de 10MB en lugar de 1000MB
Wikipedia de Turbo Vision
LLVM es una especie de trampa
El bootstrap es realmente rápido y obtienes gratis todo tipo de pases de optimización y soporte para múltiples plataformas, pero pierdes la capacidad de ajustar con detalle el rendimiento en la etapa final de optimización o de linking
Creo que Cranelift pronto se activará en Rust
Pero Rust tiene la posición que tiene hoy justamente porque al inicio eligió LLVM
Go decidió desde hace mucho encargarse por sí mismo de la generación de código y el enlazado, sin delegarlo afuera, y ha aprovechado muchísimo esa decisión
Me cuesta estar de acuerdo con la idea de que LLVM sea una trampa, y Rust más bien es un buen ejemplo
En la práctica, la parte que genera código con LLVM ocupa una porción muy pequeña del compilador, y si quieres reemplazarla puedes cambiar a
codegen_craneliftocodegen_gccLa dependencia de intrínsecos SIMD de los vendors sí es un problema de lock-in, pero eso es un tema de la estructura del lenguaje
Para la mayoría de los lenguajes, empezar con un backend de LLVM es razonable
En lenguajes parecidos a C/C++, el pipeline base de LLVM ya optimiza bien, pero mientras más diferente sea el lenguaje, más sentido tiene escribir tu propio pipeline de optimización
El caso de Go, que integró su propio backend desde el principio, sí parece exitoso, pero no es algo especialmente diferenciador, y construirlo tú mismo implica un costo de oportunidad bastante alto
Los compiladores de Go y Ocaml son realmente rápidos
Construyeron bien sus propias librerías desde el inicio y ahora ya no tienen nada que perder en velocidad
No quisiera trabajar en un entorno donde compilar tarde más de 1 minuto
Ojalá cada proyecto tuviera un compilador exclusivo para
dev, y que solo en el build final se usara algo pesado como llvmSi un lenguaje basado en LLVM busca reemplazar a C++, seguirá dependiendo de C++
Un lenguaje debe poder hacer bootstrap por sí mismo
Al principio hay herramientas convenientes, pero solo sirven para ahorrar tiempo, no son indispensables
Comparto por completo la decisión que tomó el equipo de Go
Ojalá Cranelift siga creciendo
El LLVM actual está inundado de forks por vendor de CPU, y cada uno trae mejoras específicas del CPU amarradas a paquetes cerrados
Si usas otro frontend de lenguaje o aparece un bug del compilador, la situación puede volverse muy dura
Se plantea la duda de cómo puede ser una trampa si los lenguajes pueden migrar libremente a otros backends
Si la velocidad de compilación estorba el desarrollo, surge la duda de por qué no hacer un intérprete
La velocidad de ejecución y la velocidad de compilación son, por naturaleza, independientes
Con un intérprete también sería fácil crear herramientas adicionales de desarrollo, como instrumentación de código o control del runtime
Hay casos muy puntuales en los que debes depurar únicamente un binario RELEASE optimizado, pero en la mayoría de los casos basta con un intérprete o un build DEBUG
He oído que Rust se ordena como seguridad, rendimiento y usabilidad, mientras que Zig se ordena como rendimiento, usabilidad y seguridad
Visto así, mejorar la velocidad de build sí resulta convincente, pero un intérprete es una alternativa más adecuada cuando la prioridad es la usabilidad
Me gusta el enfoque de Julia
En un entorno totalmente interactivo, el intérprete en realidad compila el código y luego lo ejecuta de inmediato
Lo mismo pasa en entornos Common Lisp como SBCL
Llevándolo al extremo, la velocidad de ejecución y la de compilación sí son independientes
Entre ambos extremos hay una "zona de compromiso", donde se puede hacer el compilador más rápido sin perder rendimiento en el ejecutable
Se afirma que el sector de los videojuegos no es un caso especial
Hasta ahora, la mejor velocidad de compilador ha sido la de TCC (obra de Fabrice Bellard)
Incluso sin multithreading ni optimizaciones complejas, es abrumadoramente rápido
Para releases uso Clang, pero la generación de código de TCC tampoco está nada mal
Creo que Delphi ofrece una expresividad y seguridad mucho mayores, y aun así una velocidad de compilación muy alta
El compilador de Go también es bastante rápido
Pensaba que DMD era el "gold standard" por poder compilar tanto C como D
Ojalá TCC llegara a soportar C23
No existe una sola cosa que sea el "verdadero gold standard"
En vlang una recompilación también termina en segundos, y el compilador de Go igualmente es muy rápido
Además existen técnicas como el build caching para evitar por completo la recompilación, así que no es algo exclusivo de nadie
Al compilar una app con zig, me dejó muy satisfecho el incremental build
Es posible compilar un solo binario estático usando varias librerías como SQLite y luau tan rápido como en Go
Eso sí, el compilador self-hosted todavía tiene bastantes bugs
Por ejemplo, SQLite requiere usar llvm, y el issue relacionado puede verse aquí
Me pregunto si Zig puede integrarse bien con sistemas de build como Bazel o Buck2
El script de build de Zig es Turing-completo, así que me preocupa que en estos sistemas no sea fácil hacer caching ni automatización del build
Es la misma razón por la que se prefieren más las librerías que pueden usarse en Rust sin
build.rsTambién me pregunto si en las librerías de Zig hay mucho build personalizado
El script de build de Zig es completamente opcional
Se pueden compilar o ejecutar archivos fuente individuales directamente, incluso sin
build.zigZig puede integrarse en cualquier workflow donde entren GCC o Clang
Por cierto, Zig también funciona como reemplazo de compilador de C
Artículo relacionado
Como ejemplo de integración entre Bazel y Zig, se presenta rules_zig
El proyecto real ZML también lo aprovecha
Proyecto ZML
Me pregunto cómo se comparan la compilación y la generación de código de Zig frente a TPDE
Se dice que es entre 10 y 20 veces más rápido que LLVM
-O0, pero parece que sí hay límitesLa estrategia de Zig me parece audaz
Pero todavía me pregunto si sigue siendo correcto usar el backend de LLVM
LLVM es competitivo en velocidad de compilación y soporte de plataformas, pero en producción de código máquina óptimo no tiene rival
Solo en los builds Release se usa el backend de LLVM, y en los builds debug el enfoque self-hosted es el predeterminado para las plataformas compatibles
Como los builds de depuración se repiten muchas veces durante las pruebas reales, este enfoque resulta más razonable
No comparto la obsesión con el rendimiento del compilador
Al final es un trade-off entre pases de optimización (inlining, eliminación de código muerto, etc.) y tiempo de compilación
Un compilador sin optimizaciones solo se volverá linealmente más rápido; si quieres ir más allá, el costo en tiempo inevitablemente aumenta
La "excelente salida en ensamblador" en realidad no es un tema tan importante
Según la ley de Proebsting, el avance de la tecnología de compiladores es mucho más lento que el aumento del rendimiento del hardware
La conclusión es que con optimizaciones simples y rápidas ya se obtiene algo suficientemente práctico
LLVM tampoco ofrece optimización absoluta y, al compararlo con la velocidad de compilación, enseguida choca con límites
Al crear una librería Java que envuelve una librería C con JNI, compilar librerías dinámicas para cada plataforma es demasiado engorroso, así que estoy considerando usar zig para builds multiplataforma
Si solo es un shim simple, en Java moderno probablemente sea mejor usar Panama y jextract
Zig incluye headers, código fuente de libc y su propio LLVM, y la compilación cruzada es realmente fácil
De verdad al punto de no tener que preocuparte por casi nada
Se preguntan por qué Ghostty todavía no puede compilarse con el backend self-hosted x86_64
El compilador de Zig se cae por un bug
Todavía es una tecnología nueva y compleja, pero pronto se resolverá
La mayoría de los usuarios de Ghostty están en plataformas
aarch64