- Zig cambió la ruta predeterminada en objetivos x86_64, donde LLVM bajaba bitcode a archivos objeto, por su backend x86 autoalojado, reduciendo de forma importante la velocidad de compilación y el uso de memoria en builds de depuración
- El backend x86 autoalojado pasa 1987 behavior tests, más que los 1980 del backend de LLVM, y algunas pruebas adicionales de un total de 2084 solo se ejecutan en las pruebas de x86 autoalojado
- En el benchmark de
hello.zig, el promedio de 918ms de la ruta con LLVM bajó a 275ms con el backend autoalojado predeterminado, lo que reduce el wall time en 70.1%, y el peak RSS también baja de 214MB a 137MB - Incluso en proyectos grandes como el propio compilador Zig, el tiempo de build se redujo de 75 segundos a 20 segundos, aunque Windows todavía no entra en este cambio predeterminado porque el COFF linker aún requiere más trabajo
- El trabajo pendiente incluye paralelización completa de la generación de código, mejoras del linker, estabilización de la compilación incremental, mejora de la calidad del código x86 y expansión del backend aarch64
Cambio del backend predeterminado en x86_64
- En builds para objetivos x86_64, Zig ahora usa por defecto su backend x86 autoalojado
- La ruta predeterminada anterior consistía en que LLVM bajara archivos bitcode a archivos objeto
- En Windows, el valor predeterminado todavía no cambia
- Esto se debe a que aún hace falta más trabajo en el COFF linker
Estado de los behavior tests superados
- El backend x86 autoalojado supera 1987 behavior tests
- El backend de LLVM supera 1980 behavior tests
- El total de behavior tests es 2084, pero las pruebas adicionales en su mayoría se superponen con las pruebas del backend x86 propio de LLVM
- Estas pruebas adicionales solo se ejecutan durante las pruebas de x86 autoalojado
- Medido por cantidad de pruebas superadas, el backend x86 de Zig ya va por delante del backend de LLVM en la implementación del lenguaje Zig
Por qué compite con la ruta de LLVM
- La razón principal por la que Zig compite con LLVM en generación de código es que puede marcar una gran diferencia en la velocidad de compilación
- El contexto relacionado está resumido en la explicación en Ziggit
Benchmark de hello.zig
- Resultado de
zig build-exe hello.zig -fllvm:- wall time promedio: 918ms
- peak RSS: 214MB
- CPU cycles: 4.53G
- instructions: 8.50G
- Resultado de la ruta predeterminada con
zig build-exe hello.zig:- wall time promedio: 275ms
- peak RSS: 137MB
- CPU cycles: 1.57G
- instructions: 3.21G
- El backend autoalojado predeterminado reduce varias métricas frente a la ruta con LLVM
- wall time 70.1% menos
- peak RSS 36.2% menos
- CPU cycles 65.2% menos
- instructions 62.2% menos
- cache misses 86.1% menos
- branch misses 78.3% menos
Efecto en proyectos grandes
- En proyectos más grandes, como el propio compilador Zig, el tiempo de build baja de 75 segundos a 20 segundos
- El backend x86 autoalojado puede reducir de forma importante el tiempo de compilación no solo en ejemplos pequeños, sino también en codebases grandes
Próximo trabajo
- Zig ya comenzó el trabajo de paralelización completa de la generación de código
- Hay una demo relacionada disponible en este registro de asciinema
- A medida que avancen las mejoras del linker y las correcciones de errores, será posible hacer que la compilación incremental sea estable y robusta junto con este backend
- La calidad del código x86 generado todavía tiene margen de mejora
- El siguiente objetivo es aarch64, y se espera que el trabajo se acelere gracias al nuevo Legalize pass
- Se puede descargar y probar directamente la build más reciente de la rama master desde la página de descargas de Zig
1 comentarios
Comentarios de Hacker News
Por lo que sé, Zig tiene mucho trabajo en curso para mejorar la experiencia de desarrollo. Casi todos los días se trabaja en algo, y justo acaba de aparecer algo como https://github.com/ziglang/zig/pull/24124
Tengo entendido que antes también estaba planeado el reemplazo de código en caliente, y al ritmo actual de desarrollo no me sorprendería que funcione en x86_64 dentro de un año
Ahora mismo, personalmente, mi mayor dolor es la velocidad de
comptime. El compilador tiene mucho que hacer ahí, y ejecutar un DSL brainF** en tiempo de compilación es bastante lento. Lo probé yo mismo y fue un experimento graciosoEn general me entusiasman mucho los nuevos backends que Zig está incorporando. Me gustaría intentar hacer yo mismo un backend URCL(https://github.com/ModPunchtree/URCL) para Zig
comptime, y hace tiempo incluso se empezó a trabajar en una rama. Pero requiere retrabajar bastante el código de análisis semántico, así que sin duda se puede hacer, se debe hacer y se hará, pero compite con otras prioridadescomptimesea lento es realmente un problema. Estoy creando una biblioteca JSON-RPC y dependo mucho decomptimepara despachar solicitudes JSON a funciones arbitrariasDebido al tipado estático estricto, no hay forma de hacer despacho dinámico en runtime hacia una función con parámetros arbitrarios, y la única forma que encontré fue averiguar en tiempo de compilación, con
comptime, el mapeo de tipos de funciónSupongo que el tamaño del código crecerá porque aumenta la cantidad de copias de código hechas con
comptimepor cada función arbitrariaEn concreto, creo que se podría crear un backend que reciba AIR y genere un reporte de seguridad de memoria. Algo que identifique uso de valores indefinidos, escape de punteros de stack, uso después de liberar, doble liberación, alias xor mut, y cosas por el estilo
Ya es un logro enorme, pero como dice el registro de desarrollo, todavía queda mucho más por delante. La idea de un compilador que durante la compilación solo modifique las partes necesarias del binario es fresca y a la vez completamente radical, y parece que ya está al alcance del proyecto Zig
Me entusiasma lo que viene
Me emociona la parte que dice: “Un proyecto grande como el compilador Zig baja de 75 segundos a 20 segundos. Esto apenas empieza”. Me da curiosidad ver qué podrá hacer esta persona con esto; parece realmente brillante
Me pregunto en qué estado está la gestión de paquetes. Intenté hacer una app con QuickJS + SDL3, pero por el caos del lado de C++ me fui a Rust, y ahí simplemente funcionó. Ojalá también pueda intentarlo en Zig
También tiene ventajas: puedes depender de archivos arbitrarios, y muchos paquetes Zig que envuelven bibliotecas C se parecen más a scripts de build que dependen de releases en tarball sin modificar. Claro que para principiantes es un poco más difícil
SDL3 tiene un wrapper nativo en Zig: https://github.com/Gota7/zig-sdl3
También hay una versión más básica que reempaqueta la biblioteca/API C: https://github.com/castholm/SDL
Para QuickJS, la API C es la única opción: https://github.com/allyourcodebase/quickjs-ng
Zig hace muy fácil usar directamente paquetes C de esta forma, pero los tipos de Zig son mucho más estrictos, así que acabas haciendo bastantes conversiones de tipo al interactuar con la API
real 0m18.444s,user 0m17.408s,sys 0m1.688sIncluso en un procesador muy viejo va así de rápido, así que no sentí necesidad de actualizar
Son especificaciones como
AMD Athlon(tm) 64 X2 Dual Core Processor 4400+, 2 núcleos, 2.3GHz, caché de 512KBComo dije también con D y Nature, para todo lenguaje que tenga su propio backend, tenemos la obligación de apoyar los proyectos que intentan no depender de LLVM
Siento que LLVM estancó la investigación y desarrollo de compiladores, que demasiados lenguajes decidieron depender de LLVM, y que demasiada gente dejó de valorar los ciclos de iteración rápidos o dejó de esperar algo mejor
La iteración rápida mediante compilación incremental y parcheo de binarios, junto con una buena depuración, debería ser una expectativa para los lenguajes nuevos, no una función de nicho ni algo tratado como demasiado difícil
Toda la industria del renderizado en tiempo real está construida, en la práctica, sobre LLVM o forks de LLVM; Microsoft también cambió su compilador de shaders a LLVM y apenas ahora está empezando a subir el código upstream
La mayor parte de la infraestructura de compiladores de consolas de videojuegos también está basada en Clang. Xbox ha seguido aferrándose a MSVC hasta ahora, pero es más bien una excepción
En conjunto, LLVM ha sido un éxito enorme, especialmente para el bootstrap de cosas nuevas
No quiero sonar como si estuviera exigiendo algo o no lo agradeciera. Zig es un trabajo que se hace gratis. Pero lo que más me intriga es un cronograma realista para 1.0
Zig coincide casi exactamente con lo que quería en un lenguaje de bajo nivel, y estoy esperando a que se estabilice
Por supuesto, aprecio muchísimo la filosofía de diseño minimalista de Zig
El programa hello world creado con
zig initpesa 9.3 MB al compilarse. Comparado con los 7.6 KB de-Doptimize=ReleaseSmall, es más de 1000 veces más grande, una barbaridad-OReleaseSmall -fno-stripgenera un ejecutable de 580 KB, y-ODebug -fstripgenera un ejecutable de 1.4 MBEl backend x86 de Zig ofrece una experiencia de depuración mucho mejor junto con un fork de lldb que entiende Zig: https://github.com/ziglang/zig/wiki/LLDB-for-Zig
No recuerdo si ahora se puede ejecutar paso a paso la lógica de
comptime. Fue un tema que se discutió recientementeCreo que Julia debería considerar pasarse a Zig para obtener ganancias de rendimiento importantes. Recuerdo a los autores de Julia angustiándose cada vez que salía una versión de LLVM por miedo a regresiones de rendimiento
El compilador es bastante retargeteable, y esta también es un área en desarrollo activo. Así que en el futuro quizá se podría imaginar Zig como un compilador alternativo para algunas partes del lenguaje
@code_llvmque muestran el IRCosas como una caché de compilación más granular, mejores herramientas para evitar invalidaciones, eliminar la optimización de world splitting, aprovechar más el multithreading en el compilador, precompilación automática de firmas concretas y una generación de código más perezosa que haga hot-swap del código cuando ya esté compilado
Desde la perspectiva de un principiante total, me da curiosidad saber en qué es mejor Zig que otros lenguajes. Lo entiendo como un C más moderno, pero ¿cuál es esa parte moderna?
A diferencia de los arrays de C, Zig tiene slices que conocen su longitud, lo cual es mejor frente a desbordamientos de búfer, y los tipos opcionales explícitos se deben verificar obligatoriamente; no se permiten punteros nulos. Incluso cuando se permiten al integrarse con código C, el tipo lo deja claro
También tiene enums, tagged unions y verificación exhaustiva obligatoria en expresiones
switchEl manejo de errores es explícito: las funciones devuelven errores (valores enum) que el llamador debe manejar de alguna forma. En C, aunque una función devuelva un entero que representa un error, se puede ignorar por completo
Dicho eso, el lenguaje no trae integrada una forma estándar de devolver datos junto con errores. El patrón de pasar una estructura de error como parámetro se siente agregado a posteriori; creo que debería haber una sintaxis especial para eso
Hay bloques
deferyerrdeferpara hacer limpieza después de retornar de una función o de que ocurra un error, y en vez de macros se puede usar generación de código concomptimey reflexión de tipos como@typeInfoAl pasar asignadores a las bibliotecas, normalmente quien llama decide dónde y cómo asignar memoria, y solo con usar
GeneralPurposeAllocatores más fácil encontrar fugas de memoriaDespués de empezar a programar seguí usando lenguajes de alto nivel, y odiaba las partes crípticas y contraintuitivas de C y su ecosistema alrededor; gracias a Zig, por primera vez empecé a disfrutar la programación de sistemas
¿Esto solo reemplaza el backend? Me pregunto si todos los pases de análisis y tipos siguen ahí, o si también reduce la verificación
Los ciclos rápidos de compilación ayudan a la productividad, pero creo que solo si también incluyen tests rápidos
Entonces, ¿no sería más fácil simplemente interpretar y ejecutar Zig para depuración? Eso también resolvería el problema de repetir el trabajo para cada target
gdbolldb, porque esas herramientas esperan un ejecutable con información de depuración DWARFAdemás, especialmente en áreas como desarrollo de videojuegos, el rendimiento en modo debug también es realmente muy importante
No hay una necesidad real de agregar un intérprete. Tener un backend personalizado significa que hoy se usa para debug, pero en un futuro mucho más lejano también podría competir con LLVM en velocidad
Agregar un intérprete sirve de poco, porque de todos modos habría que escribir un backend personalizado
El problema es que LLVM es lento tanto en debug como en release
¿No es este uno de los prerrequisitos para volver a traer async/await a Zig?
https://github.com/ziglang/zig/wiki/FAQ#what-is-the-status-o...