20 Punkte von GN⁺ 2025-08-16 | 3 Kommentare | Auf WhatsApp teilen
  • What the Fork ist ein plattformübergreifendes Tool, das verschiedene Build-Prozesse wie C/C++/Rust in Echtzeit visualisiert
  • Strukturelle Probleme bestehender Build-Systeme wie mangelnde Parallelisierung und ineffiziente Prozesse lassen sich damit leicht erkennen
  • Funktioniert mit allen Build-Systemen und Programmiersprachen und unterstützt verschiedene Build-Tools wie make, ninja, gradle, zig und cargo
  • Über Systemaufruf-Monitoring werden Laufzeit, Befehle und Abhängigkeiten jedes Prozesses in Form von Boxen visualisiert
  • Ein sehr nützliches Tool für Build-Optimierung, Engpassanalyse und die Verbesserung der CI-Performance

Einführung und Hintergrund

  • What the Fork ist ein Echtzeit-Tool zur Build-Visualisierung, das entwickelt wurde, um die Ursachen langsamer Builds visuell zu diagnostizieren
  • Bei Projekten wie LLVM kann die Kompilierung wegen der schieren Code-Menge langsam sein, aber die meisten Builds dauern vor allem wegen ineffizienter Konfigurationen unnötig lange
  • Bisher war es schwierig, Probleme im Build direkt zu erkennen oder strukturelle Schwächen auf einen Blick zu erfassen, weshalb ein solches Tool nötig war
  • Das Tool wurde plattformübergreifend konzipiert und ist auf alle Build-Systeme und Sprachen anwendbar

Hauptfunktionen und Verwendung

  • What the Fork ist kein einfacher System-Profiler, sondern ein Tool zur Diagnose build-spezifischer Probleme
  • Beispiele sind das Fehlen des -j-Flags bei make, Zeitballungen bei bestimmten Dateien oder Kompilierungsschritten sowie das Erkennen von Befehlen, die trotz möglicher Parallelisierung sequentiell ausgeführt werden
  • Besonders wirksam ist es bei der Analyse und Optimierung der Clean-Build-Performance in CI-Umgebungen
  • Verwendet wird es, indem der Befehl wtf vor den eigentlichen Build-Befehl gesetzt wird (z. B. wtf make, wtf cargo build, wtf npm run build)
  • Sobald der Build startet, wird die UI geöffnet und aktualisiert den Fortschritt jedes Prozesses in Echtzeit

UI und Visualisierung

  • Jeder Build-Prozess wird als Box auf einer Zeitleiste dargestellt und per Farbe typisiert
  • Die Eltern-Kind-Beziehungen der Prozesse werden als verschachtelte Struktur angezeigt
  • Im unteren Panel werden Laufzeit, Arbeitsverzeichnis und vollständige Befehlsargumente des ausgewählten Prozesses angezeigt

Funktionsweise

  • Ein Build ist eine Kombination aus mehreren Prozessen (z. B. bash, clang, ld)
  • Große Builds verwenden verschiedene Build-Tools wie cargo, make, bazel, gradle und xcodebuild, die tatsächlich viele Befehle, Abhängigkeiten, Caches und Scheduling-Aufgaben ausführen
  • Allein anhand der Terminalausgabe lassen sich verschachtelte Prozesse (z. B. ld, das intern von clang aufgerufen wird) und die detaillierte Timing-Struktur nicht erfassen
  • Deshalb nutzt das Tool je nach Betriebssystem Systemaufrufe zur Erkennung von Prozessstart und -ende (macOS: Endpoint Security API, Linux: ptrace(), Windows: Event Tracing for Windows)
  • Auf diese Weise lassen sich der gesamte Build-Ablauf und die Zeitleiste rekonstruieren sowie Ausführungspfade und Laufzeiten der einzelnen Schritte identifizieren
  • Es kann nicht nur für Builds, sondern auch zur Verfolgung verschiedener anderer Subprozesse eingesetzt werden

Praxisbeispiele und Beobachtungen

  • Mehrere Ingenieure (von Delta, Mozilla und Apple) haben das Tool tatsächlich in Projekten eingesetzt und dabei unerwartete Probleme entdeckt
  • Beispiel 1: In einem Open-Source-Projekt mit Cargo wurde festgestellt, dass Dateien sequentiell kompiliert wurden, also zu wenig Parallelität vorhanden war (bei einer 10-Kern-CPU wurde ein Beschleunigungspotenzial von mehr als dem 10-Fachen festgestellt)
  • Beispiel 2: Bei einem LLVM-Build mit Ninja arbeiteten alle CPU-Kerne effizient parallel und erreichten eine ideale Build-Effizienz
  • Beispiel 3: In einem CMake-basierten Projekt wurde eine ineffiziente Struktur entdeckt, bei der verschachtelte Aufrufe von cmake/make/clang sowie erneute Prüfungen von Xcode-/OS-Versionen 85-mal wiederholt wurden (die eigentliche Arbeit machte nur einen sehr kleinen Teil aus)
  • Beispiel 4: In einem großen Objective-C-Projekt mit xcodebuild wurde gegen Ende des Builds zu wenig Parallelisierung beobachtet, außerdem gab es vor dem Build-Start eine sechssekündige Inaktivitätsphase (im Vergleich dazu begann ninja schon nach 0,4 Sekunden direkt mit der Kompilierung)
  • Beispiel 5: Wenn Zig das Orca Project kompiliert, wird die Reihenfolge der Abhängigkeits-Builds zufällig festgelegt, wodurch die Effizienz der Parallelisierung vom Glück abhängt. Es wurde beobachtet, dass manche Abhängigkeiten erst ganz am Ende ausgeführt werden und dadurch die Parallelität sinkt
  • Beispiel 6: Im GitHub-CLI-Projekt mit make/go ist die Zeit für das Herunterladen von Abhängigkeiten hoch. Durch eine Reduzierung der Abhängigkeiten ist eine schnellere Build-Zeit zu erwarten

Nutzen und Grenzen

  • Durch die Analyse der visuellen Zeitleiste lassen sich unerwartete Engpässe, unnötige Wiederholungen von Abhängigkeiten und Bereiche mit zu wenig Parallelität erkennen
  • Probleme bei Abhängigkeiten, unnötige Nacharbeit oder Ineffizienzen bestimmter Tools lassen sich schnell als strukturelle Verbesserungsmöglichkeiten identifizieren und direkt zur Optimierung der Build-Performance nutzen
  • Durch die Einsicht in den vollständigen Befehl jedes Prozesses ist eine noch detailliertere Analyse möglich

Beta-Programm

  • What the Fork läuft unter Windows, Linux und macOS
  • Einzelpersonen und Teams, die Feedback geben möchten, können sich für die private Beta anmelden (Google-Formular-Link vorhanden)

3 Kommentare

 
brain1401 2025-08-17

Der Befehl ist echt zu lustig, haha — ausgerechnet wtf

 
t7vonn 2025-08-17

Wäre schön, wenn es als Open Source veröffentlicht würde.

 
GN⁺ 2025-08-16
Hacker-News-Kommentare
  • Ich stecke derzeit in einer Umgebung fest, in der nur CMake, GCC und Unix Make verfügbar sind, sodass es fast unmöglich ist, detaillierte Informationen darüber zu bekommen, warum der Build langsam ist. Der Build ist chaotisch, mit komplizierten Schritten wie dem Kopieren von Dateien aus dem Source-Verzeichnis in das Build-Verzeichnis, mehreren Sprachen (C, C++, Fortran, Python), benutzerdefinierten CMake-Schritten usw. Wenn dieses Tool auch in so einer chaotischen Umgebung gut funktioniert, könnte man wirklich sehr viel daraus lernen.

    • tsoding hat unter https://github.com/tsoding/nob.h eine plattformübergreifende Single-Header-C-Bibliothek für Builds geschrieben. Man braucht nur cc, und mit GDB-Profiling-Tools kann man sich die Build-Schritte ansehen. Ich halte das für eine coole Idee. Vielleicht passt das nicht zum Autor dieses Beitrags, aber wenn man mit mehreren Sprachen arbeiten muss, ist Nix ein großartiges Build-Tool.

    • Ich habe selbst ein Tool zum Tracing/Profiling von Compile-Zeiten als GCC-Plugin gebaut. Falls es jemanden interessiert: https://github.com/royjacobson/externis

    • Als ich versucht habe, die Compile-Zeiten meiner Game-Engine zu reduzieren, habe ich die Größe der kompilierten Artefakte als Ersatzmetrik verwendet. Da die Wall-Clock-Zeit so instabil war, war die Messung identischer Binärgrößen von Build zu Build und sogar zwischen verschiedenen Maschinen leichter handhabbar. Es ist zwar nicht zu 100 % deckungsgleich, war aber in der Praxis hilfreich.

    • Ich habe ein ähnliches Problem. Ich habe oft gesehen, dass CMake sogar Dateien neu kompiliert, die ich gar nicht verändert habe. Zum Beispiel werden schon bei kleinen Änderungen an einer .cpp ohne Interface-Änderung völlig unabhängige Objekte neu kompiliert. Ich frage mich manchmal, ob CMake stärkere Abhängigkeiten erzeugt, als die tatsächlichen Dateien rechtfertigen, und ob deshalb die Build-Zeit unnötig lang wird.

  • Ich würde dem Blog-Autor vorschlagen, ein GIF eines macOS-App-Builds oben auf der Seite direkt unter dem Header zu zeigen. Es wirkt schöner, wenn man zuerst das Ergebnis sieht und danach die Erklärung liest.

    • Guter Vorschlag. Ich habe den Blog direkt entsprechend aktualisiert.
  • Ich mag dieses Projekt wirklich. Ich habe 2018 mit strace, dtruss und https://buildinfer.loopperfect.com/ etwas Ähnliches ausprobiert, etwa für das automatische Erzeugen von BUCK-Dateien. Visualisiert habe ich es mit graphviz, perfetto.dev usw. Schade, dass ich es nie als richtiges Produkt verpackt habe, aber im Consulting hat es enorm geholfen, Ursachen zu diagnostizieren und Migrationen zu BUCK/Bazel zu unterstützen. In letzter Zeit schaue ich wieder darauf, weil ich über breitere Einsatzmöglichkeiten nachdenke. Es gibt bei diesem Ansatz allerdings auch grundlegende technische Herausforderungen: Wenn Syscall-Logs auf die Festplatte geschrieben werden, wachsen sie auf Dutzende bis Hunderte GB an (z. B. LLVM 50 GB, in manchen Fällen über 100 GB). Außerdem muss man auch Build-Schritte über https, IPC usw. sauber behandeln. Ein Kunde hat früher bei jedem Build Code per Perl aus einer Firebird-Datenbank gezogen. Und weil es Laufzeitanalyse ist, muss die Analyse für jede Build-Konfiguration erneut durchgeführt werden.

    • Reine Neugier: Wie habt ihr das Syscall-Logging umgesetzt? Mit Tricks wie LD_PRELOAD oder mit eBPF-Filterung?
  • Ich finde das großartig. Mir ist oft aufgefallen, wie viele Probleme man ohne solche Visualisierung übersieht. Als wir vor zehn Jahren das Mozilla-Build-System optimiert haben, wäre so ein Tool unglaublich hilfreich gewesen. Im Artikel hätte ich gern noch mehr darüber gelesen, welche konkreten Probleme tatsächlich gefunden wurden.

    • (Autor) Danke. Mein Gespräch mit einem Mozilla-Ingenieur wurde plötzlich unterbrochen, deshalb habe ich nicht im Detail erfahren, welche Probleme gefunden wurden. Ich würde das selbst gern genauer wissen.
  • Ich habe in einem mit CMake verwalteten C++-Projekt erfolgreich ninjatracing und Clangs -ftime-trace zur Visualisierung der Build-Performance verwendet. Zusätzlich kann man mit ClangBuildAnalyzer feiner analysieren, wofür der Compiler seine Zeit aufwendet.

  • Ich finde das wirklich großartig. Gibt es Pläne für Open Source? Ich baue etwas Ähnliches und würde gern zusammenarbeiten.

  • Wenn man unter Windows den Visual-C++-Compiler verwendet, kann ich auch vcperf empfehlen. Es ist standardmäßig in VS2022 enthalten oder lässt sich direkt von GitHub bauen und verwenden. Ich habe es auch auf mit UBT oder CMake generierte Projekte angewendet. Ich weiß nicht mehr, ob man damit die Qualität der Build-Parallelisierung direkt beurteilen kann, aber Frontend-Informationen des Compilers lassen sich leicht ansehen. Besonders nützlich ist es, um Header-Dateien zu finden, die häufig inkludiert werden oder an sich schwergewichtig sind.

    • Ich empfehle auch Incredibuild. Schon die kostenlose Version reicht aus, um Builds zu visualisieren und Engpässe zu erkennen.
  • Ein wichtiger, oft übersehener Punkt ist die Beobachtung, dass die im Build-System „eingebackene“ vorab berechnete Build-Logik nicht fein granular danach nachverfolgt wird, welche Änderungen sie tatsächlich beeinflussen. Bei ninja ist zum Beispiel ein Teil der Build-Logik vorab eingetragen, was es schnell macht. Ich habe einen Full-Build-Benchmark von Xerces-C++ einmal mit ninja (per CMake konfiguriert) und einmal mit build2 durchgeführt, das Konfiguration und Änderungsverfolgung im Build selbst behandelt. ninja brauchte 3,23 s, build2 3,54 s. Wenn man wiederholt baut und dabei einige von CMake erzeugte Dateien beibehält, sinkt es auf 3,28 s. Zum Vergleich: Der reine Konfigurationsschritt von CMake allein dauert 4,83 s. Ein Full-Stack-Build mit CMake+ninja dauert in der Praxis also eher rund 8 Sekunden, und genau diese Zeit erlebt man typischerweise als Nutzer der Bibliothek.

    • kbuild sorgt in Make dafür, dass jedes Target von einer Dummy-Datei abhängt, damit Änderungen an Optionen wie CFLAGS korrekt berücksichtigt werden. Es ist außerdem so aufgebaut, dass nicht der gesamte Build-Graph in jeden Make-Prozess geladen werden muss, damit Make eher wie ninja genutzt werden kann. Ich frage mich, wie ein direkter Vergleich ausfallen würde.
  • Ich habe etwas Ähnliches gemacht, indem ich Instruments während des Builds laufen ließ, um zu sehen, welcher Prozess wann was tut. Der Nachteil ist, dass Instruments bei langen Builds träge wird, und es ist unpraktisch, weil die Prozessbaum-Filterung fehlt. Trotzdem hat es sehr geholfen, als wir die Build-Zeit des iOS-Codes bei Twitter drastisch reduziert haben. Inzwischen ist das Tracing von „All Processes“ in Instruments kaputt, sodass diese Methode nicht mehr funktioniert.

  • Das wirkt wirklich großartig. Gibt es vielleicht schon eine macOS-Version, die man sofort testen kann? Ich würde es gern mit Rust- oder C++/Swift-Arbeit ausprobieren.

    • Nach ein paar Bugfixes plane ich, als Nächstes macOS-Versionen an Beta-Tester zu verteilen. Wenn du dich unten im Artikel anmeldest und diesen Kommentar erwähnst, nehme ich dich auf jeden Fall in die Beta-Gruppe auf.

    • Soweit ich weiß, gibt es für noch kein Betriebssystem einen öffentlichen Release, man kann sich bisher nur für Early Access anmelden.