← retour à la vitrine

Vitrine TAKT : décompression bzip2 (corpus Silesia)

Un même programme en deux builds : bz2dec décompresse des fichiers .bz2 vers la sortie standard, comme bzip2 -dc. bz2dec-original utilise la crate bzip2-rs 0.1.2 (un décodeur bzip2 en Rust pur) telle que publiée sur crates.io ; bz2dec-takt utilise la même crate après optimisation par TAKT. Le programme pilote est le même fichier source, les options de compilation sont les mêmes, et la sortie des deux programmes est identique à l’octet près. Vous trouverez ici les deux programmes prêts à l’emploi, le code source du build d’origine, un script qui télécharge le corpus et les scripts qui reproduisent la mesure et les vérifications.

Ce que fait le benchmark

Les douze fichiers du corpus Silesia (texte, exécutables, bases de données, images, XML ; 211 938 580 octets), chacun compressé avec bz2.compress(data, 9) de Python (libbz2 1.0.8, un flux par fichier, 54 506 769 octets au total), sont décompressés dans un seul processus :

bz2dec -c dickens.bz2 mozilla.bz2 mr.bz2 nci.bz2 ooffice.bz2 osdb.bz2 reymont.bz2 \
          samba.bz2 sao.bz2 webster.bz2 xml.bz2 x-ray.bz2 > /dev/null

Le bzip2 -dc du système (l’implémentation C de référence) exécute la même tâche à titre de comparaison.

Mesure (banc TAKT)

AMD Threadripper PRO 5975WX (Zen 3), Linux, un cœur dédié (son jumeau SMT inactif, son CCX réservé à la mesure). perf stat compte les cycles et les instructions en mode utilisateur du processus de décodage, ainsi que son temps écoulé ; 9 tours entrelacés (l’ordre des programmes change d’un tour à l’autre), médiane. Ce sont exactement ces fichiers qui ont été mesurés. Les trois programmes sont des exécutables glibc liés dynamiquement ; les deux builds de bz2dec utilisent les mêmes options : Rust 1.96.0, LTO, codegen-units 1, target-cpu=x86-64-v3, panic abort, symboles supprimés.

L’ensemble complet, un processus par programme :

Programme Décodeur Cycles, M Instructions, M Temps, ms Mo/s Accélération
bz2dec-original bzip2-rs 0.1.2 depuis crates.io 17 867,0 22 191,1 4 129 51,3 1,00×
bzip2 -dc bzip2 en C / libbz2 1.0.8 (paquet Ubuntu 24.04) 21 148,9 25 378,5 4 884 43,4 0,84×
bz2dec-takt la même crate après optimisation par TAKT 5 104,7 10 028,5 1 204 176,0 3,50×

bz2dec-takt face au bzip2 -dc en C : 4,14× en cycles, 4,06× en temps. Face à bz2dec-original en temps : 3,43×. L’accélération est le rapport des médianes de cycles ; Mo/s correspond aux mégaoctets décompressés (10⁶ octets) par seconde de temps écoulé.

Chaque fichier dans son propre processus (mêmes tours ; temps en ms, accélération en cycles) :

Fichier Brut, Mo Original, ms TAKT, ms bzip2 -dc, ms face à l’original face à bzip2 -dc
dickens 10,2 247,3 65,8 286,7 4,16× 4,82×
mozilla 51,2 1 048,6 370,9 1 272,9 2,96× 3,64×
mr 10,0 177,2 48,4 206,1 4,04× 4,64×
nci 33,6 461,7 111,0 516,6 4,32× 4,81×
ooffice 6,2 169,4 59,0 205,5 3,20× 3,95×
osdb 10,1 229,3 63,0 265,5 3,92× 4,68×
reymont 6,6 136,0 35,8 152,9 4,25× 4,87×
samba 21,6 333,1 115,0 404,9 3,08× 3,75×
sao 7,3 241,3 85,7 270,0 3,05× 3,43×
webster 41,5 843,6 216,1 972,2 4,10× 4,79×
xml 5,3 72,3 20,9 82,6 4,04× 4,64×
x-ray 8,5 236,4 80,1 255,6 3,22× 3,50×

L’accélération dépend des données : de 2,96× à 4,32× face à l’original et de 3,43× à 4,87× face à bzip2 -dc sur ces fichiers. Le temps écoulé inclut aussi le démarrage du processus, la lecture de l’entrée et le travail du noyau, identiques pour tous les programmes ; c’est pourquoi les rapports en temps sont un peu inférieurs aux rapports en cycles. D’autres données et d’autres CPU donneront d’autres chiffres. Les détails et tous les échantillons figurent dans measurements.json.

Exécution

python3 tools/fetch_silesia.py      # télécharge silesia.zip (68 Mo), le vérifie, écrit data/raw et data/bz2
tools/run_bench.sh 7 2              # vérifie chaque octet de sortie, puis 7 tours entrelacés sur le cœur 2
bin/bz2dec-takt -c data/bz2/dickens.bz2 | cmp - data/raw/dickens      # identique à l’octet près
sha256sum -c SHA256SUMS

tools/fetch_silesia.py ne nécessite que Python 3 et vérifie l’archive (sha256) et chaque fichier (taille, MD5 publié sur la page du corpus, sha256) ; il indique aussi si vos entrées .bz2 sont exactement les octets que nous avons mesurés. tools/run_bench.sh compte aussi les cycles lorsque perf est disponible.

Utilisation : bz2dec -c FILE.bz2 [FILE.bz2 ...] > OUT. Codes de sortie : 0 succès ; 1 erreur d’utilisation, d’E/S ou de CPU ; 2 flux invalide (le message d’erreur du décodeur est écrit sur stderr) ; 3 erreur interne du décodeur.

Linux x86-64 (glibc). Les deux programmes sont compilés pour x86-64-v3 : AVX2, BMI1, BMI2, FMA (Intel Haswell et plus récents, AMD Zen et plus récents) ; ils ne fonctionnent pas sur des CPU plus anciens.

Équivalence

Recompiler l’original

cd source
RUSTFLAGS="-C target-cpu=x86-64-v3 --remap-path-prefix=$(ls -d ~/.cargo/registry/src/index.crates.io-*)=. \
  --remap-path-prefix=$HOME/.rustup=. --remap-path-prefix=$PWD=." cargo +1.96.0 build --release --locked
strip --strip-all target/release/bz2dec

Lors de notre vérification, cela a reproduit bin/bz2dec-original bit à bit (Rust 1.96.0 installé via rustup, dans un autre répertoire). bin/bz2dec-takt est le même source/src/main.rs lié au build TAKT de la crate, qui conserve l’API publique, le type d’erreur et les messages de la crate.

Contenu

Le code source du build TAKT de bzip2-rs n’est pas publié : nous livrons des builds.

Texte source : README.fr.md

Telegram