2 Punkte von GN⁺ 2025-10-05 | 1 Kommentare | Auf WhatsApp teilen
  • Mit der Veröffentlichung von Zig 0.15.1 wurde die Kompilierungsgeschwindigkeit im Vergleich zur Vorversion deutlich verbessert
  • Messungen der tatsächlichen Build-Zeiten im Ghostty-Projekt zeigen insgesamt kürzere Laufzeiten
  • Obwohl LLVM teilweise noch verwendet wird, sind mit dem eigenen Backend weitere Geschwindigkeitssteigerungen zu erwarten
  • Inkrementelle Kompilierung ist noch nicht vollständig implementiert, dennoch zeigen sich bereits bei Teil-Builds Leistungsvorteile
  • Künftig ist mit einer noch schnelleren Build-Umgebung und einer verbesserten Developer Experience zu rechnen

Überblick

Ausgehend von Andrew Kelleys Aussage „Der Compiler ist so langsam, dass dadurch Bugs entstehen“ hat Zig über Jahre hinweg verschiedene strukturelle Verbesserungen mit dem Ziel schnellerer Kompilierungszeiten vorangetrieben

  • Das Zig-Team arbeitet daran, LLVM zu entfernen, ein eigenes Code-Generation-Backend zu entwickeln, einen eigenen Linker aufzubauen und langfristig inkrementelle Kompilierung zu realisieren
  • Die Ergebnisse dieser langfristigen Entwicklung werden in Version Zig 0.15.1 nun sichtbar, und die Veränderungen bei den Build-Zeiten wurden in einem realen Projekt (Ghostty) gemessen und veröffentlicht

Kompilierungsgeschwindigkeit des Build-Skripts

  • Zig 0.14: 7 Sekunden 167 ms
  • Zig 0.15: 1 Sekunde 702 ms

Dies ist die Build-Zeit des build.zig-Skripts selbst; sie stellt einen anfänglichen Kostenfaktor dar, der in einer frischen Build-Umgebung jedes Mal anfällt

  • Die Häufigkeit der Neukompilierung des Build-Skripts bleibt gering, beeinflusst aber direkt die Erfahrung von Nutzerinnen und Nutzern, die ein Projekt zum ersten Mal selbst bauen

Vollständiger nicht gecachter Binär-Build (Ghostty)

  • Zig 0.14: 41 Sekunden
  • Zig 0.15: 32 Sekunden

Dies ist die gesamte Build-Zeit für das Binärprogramm inklusive der Build-Zeit des Build-Skripts

  • Mit Zig 0.15 ergibt sich zusätzlich ein Geschwindigkeitsgewinn von rund 2 Sekunden, und auch gemessen an der tatsächlichen Wanduhrzeit ist der anfängliche Unterschied klar erkennbar
  • Das eigene x86_64-Backend wird bislang noch nicht vollständig genutzt, und größtenteils kommt weiterhin LLVM zum Einsatz
  • Wenn Ghostty künftig vollständig mit dem eigenen Backend gebaut wird, wird eine Reduzierung auf unter 25 Sekunden prognostiziert (etwa die Hälfte im Vergleich zu früher)

Inkrementeller Build (Ghostty-Executable)

  • Zig 0.14: 19 Sekunden
  • Zig 0.15: 16 Sekunden

Dies ist die Zeit für einen erneuten Build nach einer relevanten einzeiligen Änderung (Hinzufügen eines Log-Aufrufs im Terminal-Emulationscode)

  • Es handelt sich um einen Teil-Build, bei dem Build-Skript und Dependency-Graph bereits im Cache liegen
  • Die Funktion der inkrementellen Kompilierung ist noch nicht vollständig implementiert, dennoch sind die Leistungsverbesserungen bereits deutlich sichtbar
  • Ohne den noch verwendeten LLVM-Anteil wäre eine Reduktion auf etwa 12 Sekunden möglich
  • Wenn künftig echte inkrementelle Builds umgesetzt werden, könnten sogar Build-Zeiten im Millisekundenbereich realistisch werden

Inkrementeller Build (libghostty-vt)

  • Zig 0.14: 2 Sekunden 884 ms
  • Zig 0.15: 975 ms

Gemessen wurde die Zeit für einen teilweisen Neu-Build nur von libghostty-vt nach einer einzeiligen Änderung

  • libghostty-vt kann vollständig mit dem eigenen x86_64-Backend gebaut werden, sodass Zigs Verbesserungen direkt sichtbar werden, ohne Einfluss von LLVM
  • Auch ohne inkrementelle Kompilierung ist eine Build-Zeit von unter 1 Sekunde ein deutlicher Fortschritt
  • Im Developer-Workflow verbessert dies die Effizienz durch unmittelbares Feedback
  • Die Backends für x86_64 und aarch64 werden zunehmend stabiler und könnten innerhalb weniger Monate auf ganz Ghostty angewendet werden

Der aktuelle Stand der Verbesserungen bei der Build-Geschwindigkeit

  • Der Ghostty-Build mit Zig 0.15.1 ist in allen gemessenen Bereichen klar schneller geworden
  • Obwohl eigenes Backend und inkrementelle Kompilierung noch unvollständig sind, sind die bisherigen Ergebnisse bereits für sich genommen beeindruckend
  • In den kommenden 1 bis 2 Jahren werden noch deutlich innovativere Verbesserungen bei der Geschwindigkeit erwartet
  • Aus Sicht der Build-Geschwindigkeit fühlt sich die Entscheidung für Zig zunehmend als sinnvoll an

1 Kommentare

 
GN⁺ 2025-10-05
Hacker-News-Kommentare
  • Als ich 1995 die Highschool abschloss, habe ich auf einem Intel 486 „Borland Pascal Version Turbo Vision for DOS“ neu kompiliert — und inzwischen fühlt sich die Kompiliergeschwindigkeit wirklich wieder so schnell an.
    Turbo Vision ist ein TUI-Fenster-Framework, das für die Entwicklung der Borland-Pascal- und C++-IDEs verwendet wurde.
    Man könnte es als einen Zeichenmodus bezeichnen, der eine JetBrains-IDE in 10 MB statt 1000 MB umsetzt.
    Turbo Vision auf Wikipedia

  • LLVM ist eine Art Falle.
    Der Bootstrap ist wirklich schnell, und man bekommt gratis alle möglichen Optimierungs-Pässe und Unterstützung für diverse Plattformen, verliert dafür aber die Fähigkeit, die Performance des letzten Optimierungsschritts oder der Link-Phase fein abzustimmen.
    Ich denke, Cranelift wird in Rust bald aktiviert werden.
    Rust hat seine heutige Stellung aber auch deshalb, weil es anfangs LLVM gewählt hat.
    Go hat schon früh entschieden, Codegenerierung und Linking nicht nach außen auszulagern, sondern selbst zu verwalten, und profitiert stark von dieser Entscheidung.

    • Ich finde es schwer, der Behauptung zuzustimmen, LLVM sei eine Falle, und Rust ist eher ein gutes Gegenbeispiel.
      Tatsächlich macht der Teil, der mit LLVM Code erzeugt, im Compiler nur einen sehr kleinen Anteil aus, und man könnte ihn auch durch codegen_cranelift oder codegen_gcc ersetzen.
      Die Abhängigkeit von SIMD-Vendor-Intrinsics ist zwar ein Lock-in-Problem, aber das ist ein Problem der Sprachstruktur.
      Für die meisten Sprachen ist es vernünftig, mit einem LLVM-Backend zu beginnen.
      Bei C/C++-ähnlichen Sprachen optimiert schon die Standard-Pipeline von LLVM gut, während Sprachen mit anderen Eigenschaften eher ihre eigene Optimierungs-Pipeline schreiben.
      Dass Go von Anfang an ein eigenes Backend integriert hat, wirkt zwar erfolgreich, ist aber kein besonderer Differenzierungsfaktor, und die Eigenentwicklung hat ziemlich hohe Opportunitätskosten.

    • Die Compiler von Go und Ocaml sind wirklich schnell.
      Sie haben von Anfang an ihre eigenen Bibliotheken sauber aufgebaut und haben dadurch heute keinen Geschwindigkeitsnachteil.
      Ich möchte künftig nicht mehr in einer Umgebung arbeiten, in der ein Kompiliervorgang länger als eine Minute dauert.
      Ich wünschte, jedes Projekt hätte einen eigenen Compiler nur für „dev“, und nur für den finalen Build würde man etwas Schwergewichtiges wie LLVM verwenden.

    • Wenn eine LLVM-basierte Sprache darauf abzielt, C++ zu ersetzen, bleibt sie trotzdem weiter von C++ abhängig.
      Eine Sprache sollte sich aus sich selbst heraus bootstrappen.
      Anfangs gibt es praktische Werkzeuge, aber sie sparen nur Zeit und sind nicht unverzichtbar.
      Ich kann die Entscheidung des Go-Teams vollkommen nachvollziehen.

    • Ich hoffe auf das weitere Wachstum von Cranelift.
      Beim heutigen LLVM entstehen massenhaft Forks pro CPU-Hersteller, und in jedem davon stecken CPU-spezifische Verbesserungen in proprietären Paketen.
      Sobald man andere Sprach-Frontends nutzt oder Compiler-Bugs auftauchen, wird die Lage sehr unerquicklich.

    • Es wird die Frage aufgeworfen, wie es eine Falle sein könne, wenn Sprachen doch frei auf andere Backends wechseln können.

  • Wenn Kompiliergeschwindigkeit die Entwicklung behindert, warum baut man dann keinen Interpreter?
    Laufzeitgeschwindigkeit und Kompiliergeschwindigkeit stehen nicht zwingend in Beziehung zueinander.
    Mit einem Interpreter lassen sich zusätzliche Entwicklungswerkzeuge wie Code-Instrumentierung oder Runtime-Kontrolle auch leicht erstellen.
    Es gibt zwar sehr wenige Fälle, in denen man nur ein optimiertes RELEASE-Binary debuggen muss, aber in den meisten Fällen reicht ein Interpreter oder ein DEBUG-Build.

    • Ich habe gehört, Rust priorisiert Sicherheit, Performance und dann Nutzbarkeit, während Zig Performance, Nutzbarkeit und dann Sicherheit priorisiert.
      Aus dieser Sicht sind Verbesserungen der Build-Geschwindigkeit überzeugend, aber ein Interpreter ist eher dann eine passende Alternative, wenn Nutzbarkeit Vorrang hat.

    • Mir gefällt Julias Ansatz.
      In einer vollständig interaktiven Umgebung kompiliert der Interpreter den Code in Wirklichkeit und führt ihn dann sofort aus.
      Bei Common-Lisp-Umgebungen wie SBCL ist es ähnlich.

    • Laufzeitgeschwindigkeit und Kompiliergeschwindigkeit sind im Extremfall voneinander unabhängig.
      Dazwischen gibt es einen „verhandelbaren Bereich“, in dem man einen Compiler schneller machen kann, ohne Performance beim ausführbaren Programm einzubüßen.

    • Es wird behauptet, der Spielebereich sei kein Sonderfall.

  • Die bislang beste Compiler-Geschwindigkeit hat TCC (ein Werk von Fabrice Bellard).
    Auch ohne Multithreading oder komplexe Optimierungen ist es überwältigend schnell.
    Für Releases nutze ich Clang, aber auch die Codegenerierungs-Performance von TCC ist nicht schlecht.

    • Ich denke, Delphi bietet deutlich mehr Ausdruckskraft und Sicherheit und zugleich sehr hohe Kompiliergeschwindigkeit.

    • Der Go-Compiler ist auch ziemlich schnell.

    • Ich hielt DMD, das sowohl C als auch D kompilieren kann, für den „Goldstandard“.

    • Ich wünsche mir, dass TCC C23 unterstützt.

    • Es gibt nicht die eine Sache, die der „wahre Goldstandard“ ist.
      Auch vlang ist schnell genug, dass eine Neukompilierung in wenigen Sekunden fertig ist, und der Go-Compiler ist ebenfalls extrem schnell.
      Dazu kommen Techniken wie Build-Caching, die Neukompilierungen selbst ganz vermeiden, also ist das keineswegs das Alleinstellungsmerkmal eines einzelnen Projekts.

  • Beim Bauen einer App mit zig war ich mit den inkrementellen Builds sehr zufrieden.
    Ein einzelnes statisches Binary mit verschiedenen Bibliotheken wie SQLite und luau lässt sich fast so schnell bauen wie mit Go.
    Allerdings hat der self-hosted Compiler immer noch einige Bugs.
    Zum Beispiel muss SQLite LLVM verwenden; Details dazu stehen hier.

  • Ich frage mich, ob Zig gut mit Build-Systemen wie Bazel oder Buck2 zusammenspielen kann.
    Zig hat Turing-vollständige Build-Skripte, daher mache ich mir Sorgen, dass Caching und Build-Automatisierung in solchen Systemen nicht einfach sind.
    Das ist derselbe Grund, warum in Rust Bibliotheken ohne build.rs bevorzugt werden.
    Ich frage mich, ob Zig-Bibliotheken ebenfalls viele Custom-Builds haben.

    • Die Build-Skripte von Zig sind vollständig optional.
      Auch ohne build.zig kann man einzelne Quelldateien direkt bauen oder ausführen.
      Man kann Zig in jeden Workflow integrieren, in dem GCC oder Clang vorkommen.
      Zur Erinnerung: Zig funktioniert auch als Ersatz für einen C-Compiler.
      Verwandter Artikel

    • Als Beispiel für die Bazel-Integration von Zig wird rules_zig genannt.
      Auch das reale Projekt ZML nutzt das.
      ZML-Projekt

  • Ich frage mich, wie sich Kompilierung und Codegenerierung von Zig im Vergleich zu TPDE verhalten.
    Es heißt zwar, es sei 10- bis 20-mal schneller als LLVM -O0, aber offenbar gibt es Grenzen.

  • Ich halte Zigs Strategie für mutig.
    Trotzdem frage ich mich, ob es weiterhin richtig ist, das LLVM-Backend zu verwenden.
    LLVM ist bei Kompiliergeschwindigkeit und Plattformunterstützung konkurrenzfähig, aber bei der Erzeugung optimalen Maschinencodes kommt ihm weiterhin kaum etwas gleich.

    • Für Release-Builds wird nur das LLVM-Backend verwendet, während bei Debug-Builds auf unterstützten Plattformen standardmäßig der self-hosted-Ansatz genutzt wird.
      Debug-Builds werden im realen Testprozess mehrfach wiederholt gebaut, daher ist dieser Ansatz sinnvoller.

    • Ich kann die Fixierung auf Compiler-Performance nicht nachvollziehen.
      Letztlich ist es ein Trade-off zwischen Optimierungs-Pässen (Inlining, Dead-Code-Eliminierung usw.) und Kompilierzeit.
      Ein Compiler ohne Optimierungen wird nur linear schneller; sobald darüber hinaus optimiert wird, steigt der Zeitaufwand zwangsläufig deutlich.

    • „Hervorragende Assembly-Ausgabe“ ist in der Praxis kein wirklich wichtiges Thema.
      Nach Proebsting's Law entwickelt sich Compilertechnik viel langsamer als die Leistungssteigerung der Hardware.
      Das führt zu dem Schluss, dass einfache und schnelle Optimierungen praktisch oft ausreichen.
      Auch LLVM ist keine absolute Optimierungslösung und stößt im Vergleich zur Kompiliergeschwindigkeit schnell an Grenzen.

  • Ich baue eine Java-Bibliothek, die per JNI eine C-Bibliothek kapselt, und das Bauen plattformspezifischer dynamischer Bibliotheken ist so umständlich, dass ich Zig für Multi-Plattform-Builds in Erwägung ziehe.

    • Für einen einfachen Shim wären in aktuellem Java wahrscheinlich Panama und jextract die bessere Wahl.

    • Zig bringt Header, libc-Quellen und sein eigenes LLVM mit und macht Cross-Kompilierung wirklich einfach.
      Man muss sich praktisch um gar nichts kümmern.

  • Es wird gefragt, warum Ghostty derzeit nicht mit dem self-hosted-x86_64-Backend gebaut werden kann.

    • Der Zig-Compiler stürzt wegen eines Bugs ab.
      Es ist noch junge Technik und deshalb komplex, aber das wird bald behoben sein.

    • Die meisten Ghostty-Nutzer sind auf aarch64-Plattformen.