Ce qui se passe
Jarred Sumner, architecte de Bun, annonçait un build Linux plus de 5× plus rapide après le passage de Zig à Rust. Un détail de l'annonce était passé presque inaperçu : l'ancien build utilisait Full LTO, le nouveau ThinLTO. Lalit Maganti, qui travaille sur Perfetto, a voulu savoir quelle part du gain venait de là — et a écrit l'outil qui manquait pour le dire.
Les chiffres se reproduisent. Rejeu des builds CI Linux x64 de Bun 1.3.14 et 1.4.0 sur une VM de 6 cœurs / 12 threads :
| Build Linux x64 | Ère Zig | Ère Rust |
|---|---|---|
| Médiane CI annoncée par Bun | 30 min 06 s | 5 min 37 s |
| Rejeu sur une seule machine | 24 min 24 s | 5 min 40 s |
Comment buildprof s'y prend
Il se place devant la commande existante, sans intégration à écrire :
buildprof -- make -j16
buildprof -- cargo build
buildprof -- ninja -C out/target
buildprof -- ./dev/custom-build-script.shUn build ressemble à un seul programme, mais c'est un arbre de processus : Cargo
lance rustc, qui lance cc, qui lance collect2, qui lance ld.lld. Du point
de vue du système, tous les systèmes de build font la même chose — lancer des
processus. C'est donc la seule couche à observer, et elle couvre Cargo, Ninja,
CMake, Make et Zig sans cas particulier, scripts maison compris.
L'enregistrement utilise ptrace, l'interface des débogueurs, qui signale
fork, exec et exit ; un filtre seccomp intercepte en plus les seuls
appels système nécessaires aux accès fichiers. eBPF aurait demandé CAP_BPF,
CAP_PERFMON et l'accrochage à des points de trace instables. L'interface est un
dérivé de celle de Perfetto.
Ce que la trace a montré
Sur le build de l'ère Zig, ld.lld tournait seul, à la fin, plus de seize
minutes — environ les deux tiers du build total. Sa ligne de commande, capturée
automatiquement, portait bien Full LTO.
Changer le réglage pour Bun seul n'a pas suffi : WebKit, gros morceau du build, restait en Full LTO. Les deux passés en ThinLTO, le build Zig descend de 24 à 15 minutes, dont encore 7 de lien.
Et l'écart restant n'est pas le langage : il est structurel. Rust répartit la compilation sur plus de 90 crates, là où le build Zig faisait tout passer par un seul module.
Ce que ça change
Les outils existants ne couvraient chacun qu'une tranche : ninjatracing ne voit
pas les scripts au-dessus de Ninja, et les timings de Cargo ne couvraient que
1 min 51 s des 5 min 40 s du build CI, sans regarder dans un build.rs.
Le surcoût de buildprof dépend surtout du nombre de fichiers ouverts :
| Build | Sans traçage | Processus seuls | Processus + fichiers |
|---|---|---|---|
| ripgrep / Cargo | 12,27 s | 12,30 s | 12,43 s |
| Redis / Make | 26,78 s | 27,04 s | 31,89 s |
L'option --no-file-events retire le traçage des fichiers et garde la frise des
processus.
À retenir
LalitMaganti/buildprof est publié sous Apache-2.0, pour Linux uniquement ;
macOS et Windows sont envisagés, ainsi que npm, Gradle, Bazel et le calcul du
chemin critique. Et la leçon est indépendante de l'outil : une annonce de gain de
compilation qui change le langage et le réglage de LTO dans le même mouvement ne
dit pas lequel des deux a payé.