1 Punkte von GN⁺ 2025-06-09 | 1 Kommentare | Auf WhatsApp teilen
  • Für x86_64-Ziele hat Zig den bisherigen Standardpfad, bei dem LLVM Bitcode in Objektdateien absenkte, auf das selbstgehostete x86-Backend umgestellt und damit die Kompiliergeschwindigkeit sowie den Speicherverbrauch bei Debug-Builds deutlich reduziert
  • Das selbstgehostete x86-Backend besteht 1987 Behavior-Tests und damit mehr als das LLVM-Backend mit 1980; von insgesamt 2084 Tests werden einige zusätzliche Tests nur bei self-hosted-x86-Tests ausgeführt
  • Im hello.zig-Benchmark sank die durchschnittliche 918 ms des LLVM-Pfads beim standardmäßigen selbstgehosteten Backend auf 275 ms, wodurch die Wall Time um 70,1 % zurückging; auch der Peak-RSS fiel von 214 MB auf 137 MB
  • Selbst bei großen Projekten wie dem Zig-Compiler selbst sank die Build-Zeit von 75 Sekunden auf 20 Sekunden, doch unter Windows ist die Umstellung noch nicht Standard, da beim COFF Linker noch mehr Arbeit nötig ist
  • Zu den verbleibenden Aufgaben gehören vollständige Parallelisierung der Codegenerierung, Verbesserungen am Linker, Stabilisierung der inkrementellen Kompilierung, bessere x86-Codequalität und die Erweiterung des aarch64-Backends

Umstellung des Standard-Backends für x86_64

  • Bei Builds für x86_64-Ziele verwendet Zig jetzt standardmäßig das selbstgehostete x86-Backend
  • Der bisherige Standardpfad war, dass LLVM Bitcode-Dateien in Objektdateien absenkt
  • Unter Windows wurde der Standardwert noch nicht geändert
    • Dafür ist noch mehr Arbeit am COFF Linker nötig

Stand der bestandenen Behavior-Tests

  • Das selbstgehostete x86-Backend besteht 1987 Behavior-Tests
  • Das LLVM-Backend besteht 1980 Behavior-Tests
  • Insgesamt gibt es 2084 Behavior-Tests, aber die zusätzlichen Tests überschneiden sich größtenteils mit den LLVM-eigenen x86-Backend-Tests
    • Diese zusätzlichen Tests werden nur bei self-hosted-x86-Tests ausgeführt
  • Gemessen an der Zahl bestandener Tests ist Zigs x86-Backend in der Implementierung der Zig-Sprache weiter als das LLVM-Backend

Warum mit dem LLVM-Pfad konkurrieren?

  • Der wichtigste Grund, warum Zig bei der Codegenerierung mit LLVM konkurriert, ist, dass sich dadurch ein großer Unterschied bei der Kompiliergeschwindigkeit erzielen lässt
  • Der Hintergrund dazu ist in der Erklärung auf Ziggit zusammengefasst

hello.zig-Benchmark

  • Ergebnis von zig build-exe hello.zig -fllvm:
    • durchschnittliche Wall Time: 918 ms
    • Peak RSS: 214 MB
    • CPU cycles: 4.53G
    • instructions: 8.50G
  • Ergebnis des Standardpfads mit zig build-exe hello.zig:
    • durchschnittliche Wall Time: 275 ms
    • Peak RSS: 137 MB
    • CPU cycles: 1.57G
    • instructions: 3.21G
  • Das standardmäßige selbstgehostete Backend reduziert gegenüber dem LLVM-Pfad mehrere Kennzahlen
    • Wall Time 70,1 % weniger
    • Peak RSS 36,2 % weniger
    • CPU cycles 65,2 % weniger
    • instructions 62,2 % weniger
    • cache misses 86,1 % weniger
    • branch misses 78,3 % weniger

Wirkung bei großen Projekten

  • Bei größeren Projekten wie dem Zig-Compiler selbst sank die Build-Zeit von 75 Sekunden auf 20 Sekunden
  • Das selbstgehostete x86-Backend kann die Kompilierzeit also nicht nur bei kleinen Beispielen, sondern auch in großen Codebasen deutlich reduzieren

Nächste Arbeiten

  • Zig hat bereits mit der vollständigen Parallelisierung der Codegenerierung begonnen
  • Wenn weitere Verbesserungen am Linker und Bugfixes erfolgen, kann zusammen mit diesem Backend die inkrementelle Kompilierung stabil und robust gemacht werden
  • Bei der Qualität des erzeugten x86-Codes gibt es noch Raum für Verbesserungen
  • Das nächste Ziel ist aarch64; dank des neuen Legalize-Passes dürfte die Arbeit daran beschleunigt werden
  • Aktuelle Builds des Master-Branches können direkt von der Zig-Download-Seite heruntergeladen und ausprobiert werden

1 Kommentare

 
GN⁺ 2025-06-09
Hacker-News-Meinungen
  • Soweit ich weiß, passiert bei Zig viel, um die Entwicklererfahrung zu verbessern. Fast jeden Tag wird an irgendetwas gearbeitet, und gerade eben kam auch so etwas wie https://github.com/ziglang/zig/pull/24124 rein.
    Früher war meines Wissens auch Hot Code Replacement geplant; bei dem aktuellen Entwicklungstempo würde es mich nicht überraschen, wenn es auf x86_64 innerhalb eines Jahres funktioniert.
    Mein persönlich größter Schmerzpunkt ist derzeit die Geschwindigkeit von comptime. Der Compiler hat hier noch viel zu tun, und zur Compile-Zeit eine brainF**-DSL laufen zu lassen, ist ziemlich langsam. Ich habe es selbst ausprobiert; es war aber ein lustiges Experiment.
    Die neuen Backends, die Zig einführt, machen insgesamt sehr viel Hoffnung. Ich würde gern selbst ein URCL-Backend (https://github.com/ModPunchtree/URCL) für Zig bauen.

    • Bei den Performance-Verbesserungen für comptime ist bekannt, was zu tun ist, und vor langer Zeit wurde auch schon ein Branch dafür begonnen. Allerdings muss dafür viel am semantischen Analysecode überarbeitet werden; es ist also definitiv machbar, nötig und wird passieren, konkurriert aber mit anderen Prioritäten.
    • Hot Code Replacement wäre für die Spieleentwicklung riesig. Die Vorstellung, dass Zig das praktisch standardmäßig mit einem Compiler-Flag unterstützen wird, ist großartig. Ich würde gern sehen, wie man das mit clang versucht.
    • Ich frage mich, ob es wirklich ein Problem ist, dass comptime langsam ist. Ich baue gerade eine JSON-RPC-Bibliothek und verlasse mich stark auf comptime, um JSON-Requests an beliebige Funktionen zu dispatchen.
      Wegen der strengen statischen Typisierung gibt es zur Laufzeit keine Möglichkeit, dynamisch an Funktionen mit beliebigen Parametern zu dispatchen; der einzige Weg, den ich gefunden habe, war, die Zuordnung der Funktionstypen zur Compile-Zeit mit comptime zu ermitteln.
      Für jede beliebige Funktion wächst die Zahl der mit comptime erzeugten Codekopien, daher dürfte die Codegröße zunehmen.
    • Ich frage mich, ob es einfach ist, ein Custom Backend zu bauen. Ich habe es mir noch nicht angesehen, würde aber gern damit experimentieren.
      Konkret könnte ich mir vorstellen, ein Backend zu bauen, das AIR entgegennimmt und einen Bericht zur Speichersicherheit erstellt. Also Dinge wie die Nutzung undefinierter Werte, entweichende Stack-Pointer, Use-after-free, Double-free oder alias xor mut identifiziert.
    • Wegen URCL falle ich gerade in ein Kaninchenloch. Ich habe noch nicht tief hineingeschaut, aber die lustigste Zeitlinie wäre, dass eine für Minecraft erstellte Intermediate Representation zu einem praktischen Compile-Target für mehrere Sprachen wird.
  • Das ist schon eine enorme Leistung, aber wie im Entwicklungslog steht, bleibt noch viel mehr zu tun. Die Idee eines Compilers, der beim Kompilieren nur die nötigen Teile im Binary verändert, ist frisch und zugleich völlig radikal; jetzt scheint sie für das Zig-Projekt in greifbare Nähe gerückt zu sein.
    Ich bin gespannt auf das, was kommt.

  • Der Teil „ein großes Projekt wie der Zig-Compiler sinkt von 75 Sekunden auf 20 Sekunden. Wir fangen gerade erst an“ macht mich neugierig. Ich bin gespannt, was diese Person damit erreichen kann; sie wirkt wirklich sehr klug.
    Ich frage mich, wie der Stand beim Package Management ist. Ich hatte versucht, eine QuickJS- + SDL3-App zu bauen, bin wegen des Chaos auf der C++-Seite aber zu Rust gewechselt, und dort hat es einfach funktioniert. Es wäre schön, wenn man das auch mit Zig ausprobieren könnte.

    • Zigs Package Management ist manueller als das von Rust. Man holt per CLI eine Paket-URL und importiert dann die Module im Build-Skript.
      Das hat auch Vorteile: Man kann von beliebigen Archiven abhängen, und viele Zig-Pakete, die C-Bibliotheken umhüllen, sind eher Build-Skripte, die von unveränderten Tarball-Releases abhängen. Für Anfänger ist es natürlich etwas anspruchsvoller.
      Für SDL3 gibt es einen nativen Zig-Wrapper: https://github.com/Gota7/zig-sdl3
      Es gibt auch eine grundlegendere Neuverpackung der C-Bibliothek/API: https://github.com/castholm/SDL
      Bei QuickJS ist die C-API die einzige Option: https://github.com/allyourcodebase/quickjs-ng
      Zig macht es sehr einfach, C-Pakete auf diese Weise direkt zu nutzen, aber Zigs Typen sind deutlich strenger, sodass man bei der Interaktion mit APIs viel casten muss.
    • Der D-Compiler dmd kann sich selbst als Debug-Build kompilieren.
      real 0m18.444s, user 0m17.408s, sys 0m1.688s
      Selbst auf einem sehr alten Prozessor ist er so schnell, dass ich keinen Grund hatte, aufzurüsten.
      Die Spezifikationen sind etwa AMD Athlon(tm) 64 X2 Dual Core Processor 4400+, 2 Kerne, 2,3 GHz, 512 KB Cache.
    • Ich frage mich, ob es dafür eine Anleitung gibt. Als ich Zig kompiliert habe, dauerte es wegen mehrerer Schritte lange, und der ganze Prozess des Bootstrappings in wasm war enthalten.
    • Dass Zig sich selbst in 75 Sekunden kompilieren kann, ist erstaunlich. Selbst wenn es LLVM verwendet.
  • Ich habe es schon bei D und Nature gesagt: Für alle Sprachen mit eigenem Backend haben wir die Pflicht, Projekte zu unterstützen, die nicht von LLVM abhängig sein wollen.
    Wegen LLVM ist die Compiler-Forschung und -Entwicklung ins Stocken geraten, zu viele Sprachen haben sich entschieden, von LLVM abzuhängen, und zu viele Menschen scheinen schnelle Iterationszeiten nicht mehr für wertvoll zu halten oder nichts Besseres mehr zu erwarten.
    Schnelle Iteration durch inkrementelle Kompilierung und Binary-Patching sowie gutes Debugging sollten die Erwartung an neue Sprachen sein, nicht als Nischenfeature oder als zu schwieriges Problem gelten.

    • Andererseits hat LLVM dazu geführt, dass auch von Einzelpersonen entwickelte Sprachen sofort konkurrenzfähige Performance und breite Plattformunterstützung bekommen konnten und sich dadurch explosionsartig vermehrten. Zig ist eine davon.
      Die gesamte Echtzeit-Rendering-Branche ist praktisch auf LLVM oder LLVM-Forks aufgebaut, Microsoft hat seinen Shader-Compiler ebenfalls auf LLVM umgestellt und beginnt erst jetzt, Code upstream zu bringen.
      Auch der Großteil der Compiler-Infrastruktur für Spielkonsolen basiert auf Clang. Xbox hält bisher an MSVC fest, ist damit aber eher die Ausnahme.
      Insgesamt war LLVM besonders beim Bootstrap neuer Dinge ein enormer Erfolg.
    • Stimmt. Einer der wenigen Punkte, die ich an Go positiv sehe, ist, dass es gebootstrapped ist und nicht von LLVM abhängt.
  • Ich möchte nicht so klingen, als würde ich etwas einfordern oder undankbar sein. Zig ist schließlich Arbeit, die kostenlos geleistet wird. Am meisten interessiert mich aber ein realistischer Zeitplan für 1.0
    Zig entspricht ziemlich genau dem, was ich mir von einer Low-Level-Sprache gewünscht habe, und ich warte darauf, dass sie stabil wird
    Natürlich schätze ich Zigs minimalistische Designphilosophie wirklich sehr

    • Ernsthafte Projekte wie TigerBeetle pinnen ihre Versionen und verwenden vermutlich den neuesten Release. Nightly sehe ich eher als experimentell an
  • Ein mit zig init erstelltes Hello-World-Programm ist nach dem Kompilieren 9,3 MB groß. Verglichen mit 7,6 KB bei -Doptimize=ReleaseSmall ist das über 1000-mal größer, also enorm

    • Das ist eine zutreffende Beobachtung. Eine weitere Beobachtung ist, dass 82 % davon Debug-Informationen sind
      -OReleaseSmall -fno-strip erzeugt eine ausführbare Datei von 580 KB, und -ODebug -fstrip erzeugt eine ausführbare Datei von 1,4 MB
      Zigs x86-Backend bietet zusammen mit einem lldb-Fork, der Zig versteht, eine deutlich bessere Debugging-Erfahrung: https://github.com/ziglang/zig/wiki/LLDB-for-Zig
      Ich erinnere mich nicht, ob man comptime-Logik derzeit schrittweise ausführen kann. Das war kürzlich ein Thema in der Diskussion
  • Damit Julia deutliche Performance-Gewinne erzielen kann, sollte es vielleicht einen Umstieg auf Zig in Betracht ziehen. Ich erinnere mich an Julia-Autoren, die bei jedem LLVM-Release nervös wegen möglicher Performance-Regressionen waren

    • Julia ist faktisch stark an LLVM gebunden. Große Teile des Ökosystems hängen wegen Intrinsics, automatischer Differenzierung (Enzyme) und GPU-Kompilierung von der Existenz von LLVM ab. Von Base und Core ganz zu schweigen
      Der Compiler lässt sich ziemlich gut retargeten, und das ist ebenfalls ein aktiv bearbeitetes Gebiet. Vielleicht kann man sich deshalb in Zukunft Zig als alternativen Compiler für Teile der Sprache vorstellen
    • Gilt LLVM nicht als Teil von Julias öffentlicher API? Es gibt tatsächlich Makros wie @code_llvm, die IR anzeigen
    • Es könnte eine Möglichkeit sein, die Kompilierzeit zu senken, aber ich denke, auf Julia-Seite gibt es noch viel zu tun
      Etwa feingranularere Compile-Caches, bessere Werkzeuge zur Vermeidung von Invalidierungen, die Entfernung der World-Splitting-Optimierung, stärkere Nutzung von Multithreading im Compiler, automatische Vorkompilierung konkreter Signaturen und eine noch trägere Codegenerierung, die Code hot-swappt, sobald er kompiliert ist
    • Das wird jedes Mal gesagt, wenn ein neues Compiler-Backend auftaucht. Ich bin ziemlich skeptisch, aber es wäre interessant zu sehen, was passiert, wenn jemand das als Projekt übernimmt
  • Aus Sicht eines völligen Anfängers frage ich mich, worin Zig anderen Sprachen überlegen ist. Ich verstehe es als moderneres C, aber was genau ist daran modern?

    • Um nur ein paar Dinge zu nennen, die mir einfallen: Es gibt ein integriertes Build-System, statt mehrere separate, schwer durchschaubare Werkzeuge und Sprachen zu verwenden
      Anders als C-Arrays hat Zig Slices, die ihre Länge kennen, was in Bezug auf Buffer Overflows besser ist; explizite Option-Typen müssen zwingend geprüft werden, und Null-Pointer sind nicht erlaubt. Selbst wenn sie bei der Integration mit C-Code zulässig sind, macht der Typ das eindeutig sichtbar
      Es gibt außerdem enums, Tagged Unions und erzwungene Vollständigkeitsprüfungen bei switch-Ausdrücken
      Fehlerbehandlung ist explizit: Funktionen geben Fehler zurück (enum-Werte), die der Aufrufer auf irgendeine Weise behandeln muss. In C kann man eine Ganzzahl, die eine Funktion als Fehler zurückgibt, komplett ignorieren
      Allerdings ist in die Sprache kein Standardweg eingebaut, zusammen mit einem Fehler auch Daten zurückzugeben. Das Muster, eine Fehler-Struct als Parameter zu übergeben, wirkt angeflanscht; ich denke, dafür sollte es spezielle Syntax geben
      Für Aufräumarbeiten nach Funktionsrückgaben oder Fehlern gibt es defer- und errdefer-Blöcke, und statt Makros kann man comptime-Codegenerierung und Typ-Reflection wie @typeInfo verwenden
      Man übergibt Bibliotheken Allocators, sodass der Aufrufer normalerweise entscheidet, wo und wie Speicher alloziert wird, und schon mit dem GeneralPurposeAllocator lassen sich Speicherlecks leicht finden
      Seit ich mit dem Programmieren angefangen habe, habe ich durchgehend High-Level-Sprachen verwendet und die schwer durchschaubaren, kontraintuitiven Aspekte von C und seinem Umfeld gehasst; durch Zig macht mir Systemprogrammierung zum ersten Mal Spaß
  • Wurde hier nur das Backend ausgetauscht? Ich frage mich, ob alle Analyse- und Typ-Passes weiterhin vorhanden sind oder ob auch die Validierung reduziert wird
    Schnelle Kompilierzyklen helfen der Produktivität, aber meiner Meinung nach nur, wenn sie auch schnelle Tests einschließen
    Wäre es dann für Debug-Zwecke nicht einfacher, Zig einfach interpretiert auszuführen? Das würde wohl auch das Problem lösen, die Arbeit für jedes Target wiederholen zu müssen

    • Der Kern des Debug-Modus ist Debuggbarkeit, und interpretiert ausgeführtes Zig an Standard-Debugger wie gdb oder lldb anzubinden, dürfte nicht trivial sein. Solche Werkzeuge erwarten nämlich ausführbare Dateien mit DWARF-Debug-Informationen
      Außerdem ist gerade in Bereichen wie der Spieleentwicklung auch die Performance im Debug-Modus tatsächlich sehr wichtig
    • Ausgetauscht wurde nur das Backend. Tests dürften dadurch ebenfalls schneller werden
      Es gibt keinen wirklichen Bedarf, einen Interpreter hinzuzufügen. Ein eigenes Backend zu haben bedeutet, dass es derzeit für Debug genutzt wird, in deutlich fernerer Zukunft aber in Sachen Geschwindigkeit auch mit LLVM konkurrieren könnte
      Selbst wenn man einen Interpreter hinzufügt, müsste man ohnehin ein eigenes Backend schreiben, daher wäre das wenig nützlich
      Das Problem ist, dass LLVM sowohl im Debug- als auch im Release-Modus langsam ist
  • Ist das nicht eine der Voraussetzungen dafür, async/await zurück nach Zig zu bringen?
    https://github.com/ziglang/zig/wiki/FAQ#what-is-the-status-o...

    • Dieser Teil ist bereits aufgeräumt, und ich denke, wir können in den nächsten 2–3 Monaten ein interessantes Update teilen. Wir bauen I/O von Grund auf neu auf, und der Großteil davon ist Arbeit an der Standardbibliothek
    • Wenn man den Link liest, sieht es so aus, als käme async nicht zurück – oder zumindest nicht vor 2028