← ショーケースに戻る

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では動作しません。

等価性

オリジナルのビルド

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、エラー型、メッセージはそのまま保たれています。

収録内容

TAKTでビルドしたbzip2-rsのソースコードは公開していません。当社が納品するのはビルドです。

ソースファイル: README.ja.md

Telegram