3 points par GN⁺ 2025-06-19 | 1 commentaires | Partager sur WhatsApp
  • Le crate bzip2 remplace sa dépendance au code C par une implémentation 100 % Rust
  • Les performances s’améliorent globalement par rapport à avant, et la cross-compilation devient plus simple
  • L’implémentation Rust améliore à la fois la vitesse de compression et de décompression par rapport à la version C
  • Les problèmes de dépendances de bibliothèques, comme les conflits de symboles, sont fortement réduits
  • Après un audit de sécurité, un bug logique critique a été corrigé, ce qui a permis de valider la stabilité

Sortie de bzip2 crate 0.6.0 et transition vers Rust

  • La version 0.6.0 de bzip2 a été publiée aujourd’hui
  • Elle utilise désormais par défaut libbz2-rs-sys, une implémentation de l’algorithme bzip2 en Rust développée en interne
  • Grâce à cette transition, le crate bzip2 est plus rapide et la cross-compilation est devenue plus simple
  • Le crate libbz2-rs-sys peut aussi être compilé sous forme de bibliothèque dynamique C. Les projets C peuvent ainsi profiter eux aussi des gains de performance

Pourquoi cette transition ?

  • L’algorithme bzip2 a été créé dans les années 90 et n’est plus très utilisé aujourd’hui, mais il reste nécessaire dans plusieurs protocoles et bibliothèques pour des raisons de conformité aux spécifications
  • De nombreux projets dépendent de bzip2, non pas directement, mais quelque part en profondeur dans leur arbre de dépendances
  • Forts de l’expérience accumulée avec zlib-rs, nous avons modernisé cette fois l’implémentation de bzip2
  • Les détails d’implémentation de libbz2-rs-sys ont été abordés dans un précédent billet de blog. Ici, nous examinons les avantages de cette transition

Performances améliorées

  • L’implémentation Rust affiche globalement de meilleures performances que la version C
  • Dans certains cas, les performances sont équivalentes, mais elles ne sont jamais inférieures
  • Performances de compression : bzip2 propose une option level, mais son impact sur les performances reste limité
  • Les tests montrent que, sur des fichiers d’exemple représentatifs, la version Rust gagne plus de 10 % en vitesse

Compression :

Fichier C (cycles d’exécution) Rust (cycles d’exécution) Variation relative
sample3.ref (level 1) 38.51M 33.53M -14.87%
silesia-small.tar (level 1) 3.43G 3.00G -14.30%
silesia-small.tar (level 9) 3.47G 3.17G -9.66%

La décompression montre elle aussi des gains de performance dans tous les cas :

Fichier C (cycles d’exécution) Rust (cycles d’exécution) Variation relative
sample3.bz2 2.53M 2.42M -4.48%
sample1.bz2 9.63M 8.86M -8.63%
sample2.bz2 20.47M 19.02M -7.67%
dancing-color.ps.bz2 87.46M 83.16M -5.17%
re2-exhaustive.txt.bz2 1.89G 1.76G -7.65%
zip64support.tar.bz2 2.32G 2.11G -10.00%

En revanche, sur macOS, on observe parfois des variations dans les mesures de décompression. Les limites des outils de benchmark ont rendu l’analyse difficile

Support de la cross-compilation

  • Dans les projets Rust avec dépendances C, la cross-compilation fonctionne généralement bien grâce au crate cc, mais lorsqu’elle échoue, le débogage est très difficile
  • Des problèmes inattendus surviennent facilement lors de l’édition des liens avec des bibliothèques système, et cela devient un véritable obstacle dans certains environnements, notamment pour les builds WebAssembly
  • Le passage à une implémentation Rust fait disparaître complètement les problèmes liés au C
  • Il est désormais possible de cross-compiler vers Windows, Android, WebAssembly et d’autres cibles sans particularité notable
  • C’est un avantage majeur non seulement pour l’expérience utilisateur, mais aussi pour la maintenance

Plus de conflits de symboles (export) par défaut

  • Avec une dépendance C, il faut exporter des symboles depuis des blocs externes Rust, ce qui provoque des conflits si une autre dépendance exporte les mêmes symboles
  • libbz2-rs-sys est conçu pour ne pas exporter de symboles par défaut
  • Il n’y a donc pas de risque de conflit de symboles avec d’autres bibliothèques externes. Si besoin, l’export peut être activé via un feature flag

Exécution des tests avec MIRI

  • Pour implémenter bzip2 efficacement en Rust, l’usage de code unsafe est inévitable, et la reproduction de l’interface C nécessite elle aussi beaucoup de code unsafe
  • Heureusement, ce code peut être exécuté et testé dans l’environnement MIRI
  • Mieux encore, les bibliothèques ou applications de plus haut niveau qui utilisent bzip2 peuvent désormais elles aussi être testées avec MIRI

Conclusion

Le crate bzip2 est désormais plus rapide. Sans même avoir à y penser, il offre naturellement une meilleure expérience

1 commentaires

 
GN⁺ 2025-06-19
Commentaires Hacker News
  • En voyant la possibilité que l’implémentation de Trifecta Tech remplace l’implémentation officielle utilisée par les distributions Linux, certains estiment que ce n’est pas impossible, en rappelant que Fedora a déjà remplacé l’ancien zlib Adler par zlib-ng. Selon eux, l’essentiel est de fournir une ABI C compatible avec l’original
    • Si aucune release upstream n’a eu lieu depuis 2019, quelqu’un se demande si cette implémentation n’est pas tout simplement déjà terminée. S’il n’y a plus de bugs à corriger ni de fonctionnalités à ajouter, cela peut suffire en soi
    • Puisque Ubuntu utilise un sudo écrit en Rust, ce type de remplacement paraît tout à fait plausible
    • Trifecta Tech fournit bien une ABI C compatible, mais au final il faut quand même que quelqu’un fasse concrètement le travail pour que le changement ait lieu
    • Il est mentionné que l’objectif de uutils va lui aussi dans le sens de ce type de remplacement officiel, avec partage du lien vers le site de uutils
    • Après un rapide coup d’œil, la présence d’une configuration cargo-c semble encourageante, mais comme l’espace de noms est différent, les programmes C ne détecteront pas automatiquement l’ancienne libbz2. L’auteur précise ne pas assez bien connaître les symboles de bzip2 pour juger de la compatibilité ABI exacte, et ajoute qu’il n’a pas le temps de maintenir lui-même une implémentation GNU complète, mais que les PR sont bienvenues sur platypos, son projet expérimental, quand il aura du temps
  • J’utilise ce crate pour traiter des centaines de To de données Common Crawl. Je suis très satisfait du gain de vitesse
    • Quelqu’un demande pourquoi utiliser bz2 ici. Pour une grosse conversion unique, passer à zstd apporterait, d’après lui, bien plus d’avantages, avec de meilleurs résultats que bzip2 sur pratiquement tous les plans à taux de compression élevé
    • Quelqu’un demande si les données de Common Crawl sont publiées sous forme de torrents
    • Un gain de 14 % sur la vitesse de compression est jugé franchement impressionnant
  • Quelqu’un se demande si cette implémentation corrige d’office les 11 CVE encore ouverts. Il note ironiquement que le crate bzip2 a lui aussi fait l’objet de signalements CVE et partage un lien connexe
    • Le contraste est jugé intéressant entre les vulnérabilités signalées dans ce crate, du type « échec à l’exécution sur de gros fichiers », et les problèmes de type « bounds miss » dans l’implémentation C. Quelqu’un se demande si ce genre de faille de dépassement de limites pourrait réellement aller jusqu’à l’exécution de code
    • Citation d’un avertissement indiquant que « le crate bzip2 est vulnérable dans les versions antérieures à 0.4.4 ». Il est aussi précisé que la version 0.6.0 est sortie aujourd’hui
  • À la question « pourquoi améliorer à tout prix un algorithme des années 90 ? », quelqu’un répond qu’il est curieux de savoir quels algorithmes sont utilisés aujourd’hui. Il cite zstd et partage un lien vers un benchmark comparatif d’algorithmes de compression
  • Quelqu’un se demande comment un gain de vitesse est possible si les backends de génération de code des compilateurs C et Rust sont identiques. Plusieurs facteurs sont évoqués : auto-SIMD côté Rust, optimisations manuelles ou utilisation de nouvelles bibliothèques d’optimisation
    • Hypothèse avancée : Rust peut fournir davantage d’indices au générateur de code. Par exemple, contrairement aux pointeurs C, il y a moins à s’inquiéter des problèmes d’aliasing. Un lien explicatif sur l’aliasing est partagé
    • Quelqu’un affirme que le langage C est vraiment peu adapté à l’écriture de code moderne haute performance. Entre C99 et C21, sur près de 20 ans, le langage aurait manqué de mécanismes propres pour exploiter de nouvelles instructions comme clz, popcnt, clmul ou pdep. Selon lui, ce type d’abstractions aide énormément à optimiser ce genre de code
    • D’autres rappellent qu’une réécriture, quel que soit le langage, offre souvent des opportunités d’amélioration des performances, et que Rust ne garantit pas à lui seul un gain de vitesse intrinsèque
  • Quelqu’un dit espérer que Nana ou Prossimo réécrivent de la même manière les protocoles Internet essentiels (BGP, OSPF, RIP, etc.), ainsi que les implémentations de routage et les serveurs DNS
    • Sont cités des fonds qui soutiennent depuis quelques années la réécriture en Rust et dans d’autres langages sûrs des outils clés de l’Internet et des OS, avec des liens vers les projets NLnet et Sovereign Tech Fund. Le projet BGP in Rust est également mentionné en exemple
    • La Memory Safety Initiative présente aussi des efforts de réécriture sûre de services critiques comme TLS et DNS, ce qui rejoint en partie cette proposition
    • Un développeur a créé Ironsides DNS en SPARK Ada, un langage qui permet des preuves formelles plus solides
  • Sur macOS, quelqu’un estime que l’absence du profiler perf n’empêche pas de faire une bonne analyse de performances avec dtrace. Le script flame graph original en Perl utilisait déjà dtrace, et sa réimplémentation en Rust fonctionne de la même façon. Il manque certes certaines métriques comme les cache miss ou les micro-instructions retired, mais cela reste très utile
  • Remarque humoristique disant qu’il faudrait maintenant réécrire Rust en Javascript
  • Quelqu’un demande si le projet prend en charge la décompression parallèle comme lbzip2, ou s’il permet au moins du parallélisme via un pré-scan des block magic. Ajout édité : « apparemment non »
  • Quelqu’un raconte que Lbzip2 lui a déjà montré des vitesses de décompression très élevées en utilisant tous les cœurs CPU. Il regrette qu’en 2025, beaucoup de programmes majeurs, comme Python, n’exploitent toujours qu’un seul cœur
    • Quelqu’un répond qu’il ne comprend pas bien la situation de Python