← zurück zum Showcase

TAKT-Showcase: bzip2-Dekompression (Silesia-Korpus)

Ein Programm in zwei Builds: bz2dec entpackt .bz2-Dateien auf die Standardausgabe, wie bzip2 -dc. bz2dec-original verwendet das Crate bzip2-rs 0.1.2 (ein bzip2-Decoder in reinem Rust) in der auf crates.io veröffentlichten Fassung; bz2dec-takt verwendet dasselbe Crate nach der TAKT-Optimierung. Der Treiber ist dieselbe Quelldatei, das Build-Rezept ist dasselbe, und die Ausgabe beider Programme ist bis aufs Byte identisch. Das Paket enthält beide fertigen Programme, den Quellcode des ursprünglichen Builds, ein Skript, das das Korpus herunterlädt, sowie die Skripte, mit denen sich Messung und Prüfungen wiederholen lassen.

Was der Benchmark macht

Die zwölf Dateien des Silesia-Korpus (Text, ausführbare Dateien, Datenbanken, Bilder, XML; 211.938.580 Bytes), jeweils mit Pythons bz2.compress(data, 9) komprimiert (libbz2 1.0.8, ein Stream pro Datei, insgesamt 54.506.769 Bytes), werden in einem Prozess entpackt:

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

Zum Vergleich führt das System-bzip2 -dc (die C-Referenzimplementierung) dieselbe Aufgabe aus.

Messung (TAKT-Messstand)

AMD Threadripper PRO 5975WX (Zen 3), Linux, ein dedizierter Kern (sein zweiter SMT-Thread bleibt im Leerlauf, sein CCX ist für die Messung reserviert). perf stat zählt die Takte und Instruktionen des Dekodierprozesses im User-Modus sowie seine Laufzeit (Wall-Time); 9 abwechselnde Runden (die Reihenfolge der Programme rotiert von Runde zu Runde), Median. Gemessen wurden genau diese Dateien. Alle drei Programme sind dynamisch gelinkte glibc-Executables; beide bz2dec-Builds verwenden dasselbe Rezept: Rust 1.96.0, LTO, codegen-units 1, target-cpu=x86-64-v3, panic abort, gestrippt.

Der gesamte Satz, ein Prozess pro Programm:

Programm Decoder Takte, Mio. Instruktionen, Mio. Zeit, ms MB/s Beschleunigung
bz2dec-original bzip2-rs 0.1.2 von crates.io 17.867,0 22.191,1 4.129 51,3 1,00×
bzip2 -dc C-bzip2 / libbz2 1.0.8 (Paket aus Ubuntu 24.04) 21.148,9 25.378,5 4.884 43,4 0,84×
bz2dec-takt dasselbe Crate nach der TAKT-Optimierung 5.104,7 10.028,5 1.204 176,0 3,50×

bz2dec-takt gegenüber dem C-Programm bzip2 -dc: 4,14× nach Takten, 4,06× nach Zeit. Gegenüber bz2dec-original nach Zeit: 3,43×. Die Beschleunigung ist das Verhältnis der Mediane der Takte; MB/s sind entpackte Megabytes (10⁶ Bytes) pro Sekunde Wall-Time.

Jede Datei in einem eigenen Prozess (dieselben Runden; Zeit in ms, Beschleunigung nach Takten):

Datei Unkomprimiert, MB Original, ms TAKT, ms bzip2 -dc, ms ggü. Original ggü. bzip2 -dc
dickens 10,2 247,3 65,8 286,7 4,16× 4,82×
mozilla 51,2 1048,6 370,9 1272,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×

Die Beschleunigung hängt von den Daten ab: auf diesen Dateien von 2,96× bis 4,32× gegenüber dem Original und von 3,43× bis 4,87× gegenüber bzip2 -dc. Die Wall-Time umfasst außerdem Prozessstart, Lesen der Eingabe und Kernel-Arbeit, die für alle Programme gleich sind; deshalb fallen die Verhältnisse nach Zeit etwas niedriger aus als nach Takten. Andere Daten und andere CPUs ergeben andere Zahlen. Details und alle Einzelmessungen stehen in measurements.json.

Ausführen

python3 tools/fetch_silesia.py      # lädt silesia.zip (68 MB) herunter, prüft es, schreibt data/raw und data/bz2
tools/run_bench.sh 7 2              # prüft jedes Ausgabebyte, dann 7 abwechselnde Runden auf Kern 2
bin/bz2dec-takt -c data/bz2/dickens.bz2 | cmp - data/raw/dickens      # bis aufs Byte identisch
sha256sum -c SHA256SUMS

tools/fetch_silesia.py benötigt nur Python 3 und prüft das Archiv (sha256) und jede Datei (Größe, die auf der Korpus-Seite veröffentlichte MD5, sha256); außerdem meldet es, ob Ihre .bz2-Eingaben exakt die von uns gemessenen Bytes sind. tools/run_bench.sh zählt auch Takte, wenn perf verfügbar ist.

Aufruf: bz2dec -c FILE.bz2 [FILE.bz2 ...] > OUT. Exit-Codes: 0 Erfolg; 1 Aufruf-, E/A- oder CPU-Fehler; 2 ungültiger Stream (die Fehlermeldung des Decoders wird auf stderr ausgegeben); 3 interner Decoder-Fehler.

Linux x86-64 (glibc). Beide Programme sind für x86-64-v3 gebaut: AVX2, BMI1, BMI2, FMA (Intel Haswell und neuer, AMD Zen und neuer); auf älteren CPUs laufen sie nicht.

Äquivalenz

Original bauen

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

Bei unserer Prüfung ergab dies bin/bz2dec-original Bit für Bit (Rust 1.96.0 aus rustup, in einem anderen Verzeichnis). bin/bz2dec-takt ist dieselbe source/src/main.rs, gelinkt mit dem TAKT-Build des Crates, der die öffentliche API, den Fehlertyp und die Meldungen des Crates beibehält.

Inhalt

Der Quellcode des TAKT-Builds von bzip2-rs wird nicht veröffentlicht: Wir liefern Builds.

Quelldatei: README.de.md

Telegram