TAKTショーケース:bzip2の展開(Silesiaコーパス)
1つのプログラムを2通りにビルドしたものです。bz2decはbzip2 -dcと同様に、.bz2ファイルを展開して標準出力に書き出します。bz2dec-originalはcrates.ioで公開されているbzip2-rs 0.1.2クレート(純Rust実装のbzip2デコーダ)をそのまま使い、bz2dec-taktはTAKTで最適化した同じクレートを使います。ドライバは同一のソースファイル、ビルド手順も同一で、両プログラムの出力はバイト単位で一致します。ビルド済みの両プログラム、オリジナルビルドのソースコード、コーパスを取得するスクリプト、測定と検証を再現するスクリプトを収録しています。
ベンチマークの内容
Silesiaコーパスの12ファイル(テキスト、実行ファイル、データベース、画像、XML。計211,938,580バイト)を、それぞれPythonのbz2.compress(data, 9)(libbz2 1.0.8、1ファイル1ストリーム、合計54,506,769バイト)で圧縮し、1つのプロセスで展開します:
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
比較のため、システムのbzip2 -dc(C言語のリファレンス実装)で同じ処理を実行します。
測定(TAKT測定環境)
AMD Threadripper PRO 5975WX(Zen 3)、Linux、専用コア1基(SMTの兄弟スレッドはアイドル、そのCCXは測定専用に確保)。perf statで展開プロセスのユーザーモードのサイクル数と命令数、および実時間を計測しました。交互実行9ラウンド(ラウンドごとにプログラムの実行順を入れ替え)の中央値です。測定したのは、ここにあるファイルそのものです。3つのプログラムはいずれもglibcに動的リンクされた実行ファイルで、bz2decの2つのビルドは同じ手順でビルドしています:Rust 1.96.0、LTO、codegen-units 1、target-cpu=x86-64-v3、panic abort、シンボル除去(strip)。
全ファイルを1プログラムにつき1プロセスで処理した場合:
| プログラム | デコーダ | サイクル数(百万) | 命令数(百万) | 時間(ms) | MB/s | 高速化 |
|---|---|---|---|---|---|---|
bz2dec-original |
crates.ioのbzip2-rs 0.1.2 | 17,867.0 | 22,191.1 | 4,129 | 51.3 | 1.00× |
bzip2 -dc |
C版bzip2 / libbz2 1.0.8(Ubuntu 24.04のパッケージ) | 21,148.9 | 25,378.5 | 4,884 | 43.4 | 0.84× |
bz2dec-takt |
TAKTで最適化した同じクレート | 5,104.7 | 10,028.5 | 1,204 | 176.0 | 3.50× |
C版bzip2 -dcに対するbz2dec-taktの高速化は、サイクル数で4.14倍、時間で4.06倍です。bz2dec-originalに対しては、時間で3.43倍です。高速化はサイクル数の中央値の比、MB/sは実時間1秒あたりの展開後のメガバイト数(10⁶バイト)です。
ファイルごとに個別のプロセスで処理した場合(ラウンドは同じ。時間はms、高速化はサイクル数による):
| ファイル | 非圧縮サイズ(MB) | オリジナル(ms) | TAKT(ms) | bzip2 -dc(ms) |
オリジナル比 | 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× |
高速化の度合いはデータによって異なり、これらのファイルではオリジナル比で2.96〜4.32倍、bzip2 -dc比で3.43〜4.87倍です。実時間にはプロセスの起動、入力の読み込み、カーネルの処理も含まれ、これらはどのプログラムでも同じです。そのため、時間による比はサイクル数による比よりわずかに低くなります。データやCPUが異なれば、数値も異なります。詳細と全サンプルはmeasurements.jsonをご覧ください。
実行方法
python3 tools/fetch_silesia.py # silesia.zip(68 MB)をダウンロードして検証し、data/raw と data/bz2 を作成
tools/run_bench.sh 7 2 # 出力を全バイト検証した後、コア2で交互実行を7ラウンド
bin/bz2dec-takt -c data/bz2/dickens.bz2 | cmp - data/raw/dickens # バイト単位で一致
sha256sum -c SHA256SUMS
tools/fetch_silesia.pyはPython 3だけで動作し、アーカイブ(sha256)と各ファイル(サイズ、コーパスのページで公開されているMD5、sha256)を検証します。お手元の.bz2入力が、当社が測定したものとバイト単位で同一かどうかも表示します。tools/run_bench.shは、perfが使える環境ではサイクル数も計測します。
使い方:bz2dec -c FILE.bz2 [FILE.bz2 ...] > OUT。終了コード:0 成功、1 使い方の誤り・I/Oエラー・CPUエラー、2 不正なストリーム(デコーダのエラーメッセージをstderrに出力)、3 デコーダの内部エラー。
Linux x86-64(glibc)。両プログラムともx86-64-v3向けにビルドしています:AVX2、BMI1、BMI2、FMA(Intel Haswell以降、AMD Zen以降)。これより古いCPUでは動作しません。
等価性
- Silesiaの12ファイル:
bz2dec-original、bz2dec-takt、bzip2 -dcの出力は、ファイルごとに処理した場合も、12ファイルを1回で処理した場合も、元のファイルとバイト単位で一致します。 - 追加の12,900ストリーム:正常なもの1,200件(コーパスのファイルを無作為に切り出したもの、圧縮レベル1〜9)と、破損したもの11,700件(完全な入力を破損させたもの900件、残りは切り出したデータを破損させたもの。ビット反転、切り詰め、バイト置換、範囲のゼロ埋め、範囲の挿入と削除)。すべてのストリームについて、2つのプログラムのstdout、stderr、終了コードは一致しました(終了コード0:1,360件、終了コード2:11,540件)。不一致は0件です。
python3 tools/compare_corrupted.py bin/bz2dec-original bin/bz2dec-takt data --seed 1で再現できます(シードは1と2を使用。measurements.jsonを参照)。
オリジナルのビルド
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
当社の確認では、この手順でbin/bz2dec-originalがビット単位で同一に再ビルドされました(rustupのRust 1.96.0、別のディレクトリで実施)。bin/bz2dec-taktは、同じsource/src/main.rsをTAKTでビルドしたクレートとリンクしたもので、クレートの公開API、エラー型、メッセージはそのまま保たれています。
収録内容
bin/:bz2dec-originalとbz2dec-taktsource/:bz2dec-originalのビルド元となるドライバとCargoファイルtools/:fetch_silesia.py(コーパスと入力)、run_bench.sh(検証と時間計測)、compare_corrupted.py(正常なストリームと破損したストリーム)measurements.json、SHA256SUMS、LICENSE
TAKTでビルドしたbzip2-rsのソースコードは公開していません。当社が納品するのはビルドです。