2 points par GN⁺ 2025-09-12 | 1 commentaires | Partager sur WhatsApp
  • L’installation de paquets de Bun fonctionne à une vitesse très élevée par rapport aux gestionnaires de paquets existants
  • Le cœur de cette rapidité repose sur une approche relevant de la programmation système et sur la minimisation des appels système
  • Les performances sont améliorées grâce à des stratégies fines, comme du code natif basé sur le langage Zig, l’utilisation d’un cache binaire et des optimisations selon l’OS
  • Même dans les étapes de décompression des tarballs et de copie de fichiers, des méthodes hautes performances tirant parti des caractéristiques matérielles ont été adoptées
  • L’optimisation des structures de données comme le graphe de dépendances et le lockfile améliore l’efficacité du cache CPU et l’accessibilité mémoire

Pourquoi Bun Install est rapide

  • En moyenne, bun install de Bun offre des performances d’installation de paquets 7 fois plus rapides que npm, 4 fois plus rapides que pnpm et 17 fois plus rapides que yarn
  • Ce n’est pas simplement le résultat d’un benchmark, mais d’une approche du problème de l’installation de paquets sous l’angle de la programmation système plutôt que de JavaScript
  • Bun applique activement des optimisations à plusieurs niveaux : minimisation des appels système, cache binaire des manifests, optimisation de l’extraction des tarballs et copie de fichiers native selon l’OS

Les limites de Node.js et de l’architecture des gestionnaires de paquets

  • Depuis la sortie de Node.js en 2009, le modèle d’IO asynchrone fondé sur une boucle d’événements et un pool de threads s’est propagé aux gestionnaires de paquets
  • À l’époque, en raison des limites matérielles (disques lents, réseau lent), la stratégie fondée sur l’IO asynchrone et une forte fréquence d’appels système était rationnelle
  • Mais sur les systèmes modernes, les SSD NVMe, les réseaux rapides et les CPU haute performance sont devenus courants, et le véritable goulet d’étranglement n’est plus l’IO mais le surcoût des appels système

Le coût des appels système et des changements de mode

  • Lorsqu’un programme demande une opération comme la lecture d’un fichier, il doit passer du user mode au kernel mode, un processus qui consomme un nombre élevé de cycles CPU (1000 à 1500 cycles)
  • L’installation de paquets nécessite fondamentalement des dizaines de milliers, voire des centaines de milliers d’appels système, si bien que le seul coût de ces transitions représente déjà plusieurs secondes de temps CPU
  • Par exemple, lors de l’installation de React et de ses dépendances, npm utilise environ 1 million d’appels système, yarn 4 millions, pnpm 500 000, et bun 160 000

Différences d’approche entre les gestionnaires de paquets existants et Bun

  • npm, pnpm et yarn sont tous basés sur Node.js, ce qui oblige à exécuter JavaScript à travers plusieurs couches d’abstraction (libuv, boucle d’événements, pool de threads, médiation des appels système)
  • Cela accumule la conversion d’arguments, les files d’attente du pool de workers, la répartition des tâches dans la boucle d’événements et les appels système futex (synchronisation par verrou), au point que la gestion des appels système finit par être plus lente que l’IO elle-même
  • À cause de cette limite structurelle, un gestionnaire de paquets construit avec Node.js a du mal à atteindre des performances réellement proches du natif

Bun : un moteur d’installation natif implémenté en Zig

  • Bun appelle directement les appels système en langage Zig, en éliminant entièrement le moteur JavaScript et les couches d’abstraction
  • Par exemple, la lecture de fichier exécute directement l’appel système openat() dans le code Zig et renvoie immédiatement les données
  • Ainsi, la lecture de dizaines de milliers de fichiers fonctionne à très grande vitesse, sans pool de threads, boucle d’événements ni conversion de données
  • Dans les benchmarks, Bun peut lire 146 057 package.json par seconde, tandis que Node.js est plus de deux fois plus lent, autour de 60 000

Gestion des dépendances et optimisation DNS

  • Lors de l’exécution de bun install, Bun déclenche l’analyse des dépendances et le DNS prefetch de manière asynchrone en parallèle
  • Par exemple, sur macOS, il utilise l’API DNS asynchrone non officielle d’Apple (getaddrinfo_async_start()), ce qui permet de traiter simultanément les opérations réseau sans bloquer de thread
  • Les gestionnaires de paquets existants reposent sur le pool de threads de libuv, où du code bloquant s’exécute en réalité en interne, ce qui gaspille des ressources

Cache binaire des manifests de paquets

  • npm et d’autres mettent les manifests en cache au format JSON, mais Bun les parse une fois, puis stocke le résultat converti en binaire (fichier .npm)
  • Cela réduit au minimum la duplication des chaînes et le coût du parsing, et en mémoire l’accès aux valeurs se fait immédiatement par simple calcul d’offset (sans création de nouveaux objets, parsing ou garbage collection)
  • Les en-têtes ETag et If-None-Match permettent de vérifier uniquement les changements et de valider l’actualité des données sans parsing inutile
  • D’après les benchmarks, une installation depuis le cache de Bun est plus rapide qu’une fresh install avec npm

Performances de traitement des tarballs

  • Les gestionnaires de paquets classiques reçoivent généralement les tarballs en flux, ce qui entraîne une succession de réallocations, copies et redimensionnements dès que la mémoire tampon devient insuffisante
  • Bun reçoit d’abord l’intégralité du tarball puis le décompresse ; il détermine à l’avance la taille décompressée grâce aux 4 derniers octets du gzip, puis n’alloue la mémoire qu’une seule fois
  • En utilisant notamment libdeflate, Bun accélère la décompression tout en supprimant les copies redondantes et les redimensionnements inutiles

Optimisation du graphe de dépendances et des structures de données

  • Les gestionnaires de paquets existants construisent des arbres de dépendances à base d’objets JavaScript et de pointeurs, ce qui disperse aléatoirement la mémoire et provoque fréquemment des défauts de cache CPU (problème de pointer chasing)
  • Bun applique le modèle Structure of Arrays (SoA) et stocke tous les paquets, chaînes et dépendances dans de grands blocs de mémoire contigus
    • Grâce à un accès fondé sur les offsets et longueurs, le CPU peut lire plusieurs paquets en une fois au niveau des lignes de cache (structure favorable au cache)
    • Le lockfile aussi, au lieu d’utiliser JSON/YAML, est stocké suivant le modèle SoA, ce qui facilite l’élimination des doublons de chaînes et l’accès séquentiel en mémoire
  • Un format binaire de lockfile (bun.lockb) a également été introduit à titre expérimental, mais a été abandonné au profit d’un format texte plus lisible, car il dégradait la collaboration via Git

Optimisation de la copie de fichiers selon l’OS

macOS

  • Utilisation de clonefile : duplication d’un répertoire entier en Copy-On-Write via un seul appel système
  • Cela minimise l’usage redondant de l’espace disque et maximise la vitesse d’installation
  • En cas d’échec de clonefile, Bun applique un fallback progressif : clonage par répertoire, puis copyfile

Linux

  • Tentative prioritaire de hardlink : au lieu de créer un nouveau fichier, seul un nouveau pointeur vers le fichier existant est créé (sans déplacement des données sur le disque)
  • Si le hardlink n’est pas possible, Bun applique le Copy-On-Write via ioctl_ficlone sur Btrfs/XFS
  • Ensuite, il bascule si nécessaire vers copy_file_range, sendfile, puis en dernier recours vers une copie classique avec copyfile

Bilan

  • Bun dépasse les limites traditionnelles de performance des gestionnaires de paquets grâce à la minimisation des appels système, aux structures binaires, aux optimisations spécifiques à l’OS et à l’amélioration des structures de données
  • Cela apporte non seulement des installations ultra-rapides, mais améliore aussi l’efficacité mémoire et CPU
  • Par rapport aux gestionnaires basés sur Node.js, il peut être adopté dans les projets sans remplacement de runtime distinct, tout en conservant la compatibilité
  • Dans de grandes bases de code réelles, il offre une expérience où des installations qui prenaient plusieurs minutes sont réduites à quelques millisecondes à quelques secondes
  • C’est un excellent exemple d’optimisation sur mesure adaptée au système, au matériel et à l’OS, avec une forte valeur d’étude et de référence

1 commentaires

 
GN⁺ 2025-09-12
Avis Hacker News
  • J’ai essayé de vérifier l’affirmation selon laquelle mon MacBook M4 Max ferait partie du top 50 des supercalculateurs du TOP500 de 2009
    Pour entrer dans le TOP500 en 2009, il fallait plus de 75 TFlop/s de performance
    Le M4 Max atteint 18,4 TFlop/s en FP32, mais le TOP500 utilise le FP64 (LINPACK)
    D’après des benchmarks du M2, le FP64 représente environ un quart du FP32, donc on peut estimer environ 9 TFlop/s
    À ce niveau, il n’entrerait pas dans le TOP500 de 2009
    Voir la liste TOP500 de 2009

    • Si chaque connexion effectue plusieurs opérations d’E/S en parallèle, il faut alors multiplier par des milliers de connexions
      J’ai entendu dire qu’un serveur passait environ 95 % de son temps à attendre les E/S, mais en réalité cela s’applique à chaque thread, pas au serveur entier
      En pratique, un serveur monte souvent à 70–80 % d’utilisation CPU (au-delà, la tail latency se dégrade fortement)
      Si le CPU n’est qu’à 5 % à pleine charge, c’est qu’il y a un manque de processus parallèles ou un problème de mémoire
      C’est un petit détail technique, mais ce genre d’erreur peut nuire à la crédibilité du billet (je dis ça en tant que fan de Bun)

    • Cette conclusion donne un peu l’impression d’une hallucination produite par un LLM
      La partie conclusion, en particulier, ressemble à quelque chose généré par un LLM
      « Cela m’a fait comprendre que les gestionnaires de paquets benchmarkés n’étaient pas mauvais, mais constituaient des solutions adaptées à leur époque »
      « Ce qui est mis en avant avec l’approche de Bun, ce n’est pas tant son caractère révolutionnaire que le fait qu’elle résulte d’un regard lucide sur les causes actuelles de la lenteur »
      « Si l’installation des paquets est 25 fois plus rapide, ce n’est pas par magie, mais simplement parce que l’outil a été conçu pour le matériel moderne »

  • J’ai vraiment aimé la façon dont un sujet complexe était expliqué de manière simple et facile à lire
    C’est impressionnant de voir qu’il existe encore des gens passionnés qui remettent en cause le statu quo et s’attaquent à des problèmes difficiles
    Chaque mois, le matériel informatique progresse, mais les logiciels deviennent plus lents, et ça me semble anormal
    J’aimerais que tout le monde code plus efficacement

    • Je ne savais pas que bun était écrit en Zig
      Zig est un langage très récent, donc c’est intéressant de le voir utilisé sérieusement en pratique
  • J’ai essayé bun pour la première fois, et j’ai été très impressionné
    Grâce au serveur intégré et à SQLite, il suffit d’installer bun et le développement devient bien plus pratique
    J’utilise généralement seulement du vanilla js et je n’ai jamais beaucoup aimé l’écosystème node, donc je me dis que j’aurais dû essayer bun plus tôt

    • J’ai essayé Bun plusieurs fois et l’expérience d’utilisation m’a beaucoup plu
      Je l’ai trouvé meilleur que Node
      Mais je finis toujours par tomber sur un problème bloquant, donc je reviens à Node
      Au début, le module crypto n’était pas compatible avec Nodejs (c’est corrigé maintenant), puis Playwright ne fonctionnait pas sur Bun

    • De nos jours, Node prend aussi en charge un serveur intégré et SQLite
      Si tu as besoin de plus de fonctionnalités, Hono est aussi une bonne alternative

  • Je n’ai pas bien compris la partie de l’article qui explique que les hard links de Linux et clonefile de MacOS seraient équivalents
    Avec les hard links, si on modifie une copie, est-ce que cela ne change pas aussi de façon inattendue le fichier dans tous les projets ?

  • Malgré une explication techniquement assez complexe, c’est vraiment écrit de façon très lisible et agréable

    • Lydia est très douée pour rendre des concepts complexes faciles à comprendre
      J’ai vu la plupart de ses travaux et de ses vidéos, et on sent qu’elle prépare ses sujets en profondeur
      Si vous avez le temps, je recommande vivement ses articles et ses contenus YouTube
      Ces derniers temps, j’ai l’impression qu’elle est moins active, sans doute à cause de son travail actuel
  • Dans la section Binary Manifest Caching, il semble que le temps de benchmark de « npm (cached) » manque
    Il n’y a que bun, bun (cached) et npm, et même les statistiques récapitulatives ne semblent pas tout à fait cohérentes

  • J’ai adoré le style d’écriture de ce billet
    Ça ferait un très bon exemple réutilisable pour expliquer l’importance de io_uring
    Je me demande si la récente mise à jour io de Zig v0.15 pourrait encore améliorer les performances de Bun

  • Ça fait plus d’un an que j’attends beaucoup de bun
    Je pensais que 2025 serait l’année de sa démocratisation, mais contre toute attente, il n’est toujours pas si populaire
    Parmi les 100 000 principaux dépôts GitHub, pour les nouveaux dépôts en 2025, npm est utilisé 35 fois plus souvent et pnpm 11 fois plus souvent
    Même Deno n’est pas aussi populaire que je l’imaginais
    Je me demande pourquoi
    Est-ce parce qu’il est plus difficile d’assurer la compatibilité pour un runtime que pour un gestionnaire de paquets ?
    J’aimerais entendre l’avis de ceux qui ont essayé bun sans l’adopter
    Statistiques associées
    Commentaire HN associé

    • J’ai essayé plusieurs fois d’aimer à la fois Bun et Deno, mais à chaque fois je suis tombé sur un défaut bloquant, donc j’ai fini par abandonner
      Le plus gros problème récent que j’ai rencontré sur Bun, c’était un souci où les streams se fermaient prématurément
      Lien vers l’issue correspondante
      Sur Deno, j’ai rencontré un problème de fuite mémoire
      Lien vers l’issue correspondante
      Au final, j’ai l’impression que l’écosystème Node finira par intégrer d’abord les avantages de Bun et Deno

    • Bun est un nouveau venu financé par du capital-risque, en concurrence avec un produit open source dominant et éprouvé (Node)
      Il y a une incitation au lock-in, et au fond ce n’est pas si différent de Node
      Son avantage stratégique n’est pas évident, et il n’apporte rien de vraiment nouveau qu’on ne puisse pas faire avec Node
      Je n’ai jamais vu de cas d’usage vraiment sérieux, seulement des usages légers

    • Quand on regarde l’issue tracker, on a l’impression que le langage Zig n’est pas très sûr, vu la fréquence des crashs
      Pour ma part, je vais rester sur Node

    • Moi aussi, je suis curieux d’avoir l’avis des autres
      À mon sens, Node est un projet mature, démocratique, et très porté par sa communauté
      C’est aussi parce qu’il a bien surmonté l’épisode du fork io.js
      En revanche, bun et deno sont tous deux des projets soutenus par des VC, donc je n’ai pas l’impression qu’ils soient vraiment pilotés de manière démocratique par leur communauté

    • Je suis un grand fan de Bun
      J’utilise Bun dans tous les projets où c’est possible, et j’écris aussi toutes sortes de scripts one-off en Bun/TS
      Cela dit, il existe quelques problèmes, peu nombreux mais préoccupants, qui me font encore hésiter à le déployer en production
      Par exemple, j’ai déjà eu un cas où un simple serveur web Express lancé dans Docker se figeait lorsqu’il tournait avec bun
      En remplaçant uniquement par node, tout fonctionnait normalement
      Il y a un an, j’avais aussi eu un serveur qui plantait à cause d’une fuite mémoire avec la combinaison Bun + Prisma (j’imagine que c’est corrigé aujourd’hui)
      Malgré tout, j’aime tellement Bun que j’accepte ces défauts, car au global il me fait gagner du temps de développement
      Le confort apporté par le transpile, les modules, les workspaces, etc., est énorme
      Je comprends tout à fait qu’il ne soit pas encore aussi largement adopté que npm

  • J’ai pris énormément de plaisir à lire cet article
    C’est un bon exemple de l’importance concrète des principes d’informatique théorique dans le développement logiciel
    Big O, localité temporelle et spatiale, complexité algorithmique, espace utilisateur/espace noyau, système de fichiers, copy-on-write, etc.
    Dans ce genre de développement de paquets bas niveau, tous les concepts appris dans un cursus d’informatique sont réellement mis en pratique

    • En réalité, cela relève davantage du génie logiciel (SE) que de l’informatique théorique (CS)
      Le CS étudie le calcul et la théorie (langages de programmation, algorithmes, cryptographie, machine learning, etc.)
      Le SE applique des principes d’ingénierie pour construire des logiciels extensibles et fiables
  • Je ne comprends pas bien pourquoi il serait avantageux d’attendre d’avoir entièrement lu une archive compressée avant de la décompresser
    J’imagine qu’il serait au contraire plus avantageux de commencer la décompression avant la fin du téléchargement, malgré l’inconvénient lié à l’augmentation du nombre de recopies mémoire