🗜️
圧縮ツールの比較: gzip, bzip2, lzop, lz4, xz, zstd
Linux環境でよく使われている圧縮ツールの性能を知っておきたかったので、圧縮率や処理時の負荷などを評価した。
評価の目的は、データを圧縮して保存したりそれを伸長して使ったりする際に、どれが有用なのかということ。
評価対象
評価対象のツールは下記の6種類とした。バージョンはいずれもDebian 12 (bookworm) for AMD64で標準のもの。
名前 | バージョン |
---|---|
GNU Gzip | 1.12 |
bzip2 | 1.0.8 |
LZO | 1.04 |
LZ4 | 1.9.4 |
XZ Utils | 5.4.1 |
Zstandard (zstd) | 1.5.4 |
- XZ Utilsのリンク先は、記事作成時点ではバックドア対応のため工事中
評価条件
- 圧縮対象のデータ: テキストデータとバイナリデータをそれぞれ1つずつ
- テキストデータ: Linuxカーネルのソースコード
- linux-5.15.153.tar.xz を伸長したもの
- サイズは 1,087.1 MiB
- バイナリデータ: Ubuntuのdebパッケージ
- Ubuntu 22.04 LTS for AMD64 の linux-modules-extra-5.15.0-101-generic_5.15.0-101.111_amd64.deb のデータ部分を伸長したもの
- サイズは 336.5 MiB
- 補足
- 追試しやすいよう、再入手が容易なものとした
- 保存用途での評価をしたかったので、ある程度大きなデータを選んだ
- テキストデータ: Linuxカーネルのソースコード
- 実行環境
- プロセッサ: Intel Core i7-5600U (最大動作周波数 3.2 GHz)
- メモリ: 8 MB
- OS: Debian 12 (bookworm) for AMD64
評価結果
テキストデータ
Linuxカーネルのソースコード linux-5.15.153.tar (約1GiB) での測定結果。
コマンド名 | 圧縮率 [%] | 圧縮時間 [sec] | 圧縮時スループット [MiB/sec] | 圧縮時メモリ [KiB] | 伸長時間 [sec] | 伸長時スループット [MiB/sec] | 伸長時メモリ [KiB] |
---|---|---|---|---|---|---|---|
gzip | 17.44 | 30.72 | 6.17 | 1,968 | 5.31 | 204.73 | 1,652 |
bzip2 | 13.11 | 85.79 | 1.66 | 8,584 | 23.66 | 45.95 | 4,904 |
lzop | 29.71 | 2.41 | 134.04 | 2,144 | 2.19 | 496.41 | 1,788 |
lz4 | 28.67 | 2.44 | 127.73 | 8,728 | 0.94 | 1,156.52 | 9,284 |
xz | 11.10 | 387.46 | 0.31 | 97,588 | 8.66 | 125.53 | 10,288 |
zstd | 16.19 | 5.58 | 31.54 | 44,836 | 1.45 | 749.74 | 5,460 |
- 圧縮率の良さならxzがよい
- 圧縮時間の短さならlzop・lz4がよい
- 圧縮時スループットの高さならlzop・lz4がよい
- 伸長時間の短さならlz4・zstdがよい
- 伸長時スループットの高さならlz4・zstdがよい
- 圧縮・伸長時の最大メモリ使用量は、PCやサーバであれば、どれでも十分に小さいため大した負荷にならないと思われる
- 圧縮率・圧縮時間・伸長時間すべてにおいて、gzipよりもzstdのほうがよい
データを圧縮して保存する用途には、圧縮率を良くしたいならxzが、圧縮率は程々でいいので時間を短く済ませたいならzstdがよさそう。
各測定値の補足
- 各コマンドでの圧縮や伸長はデフォルトのまま実施
- 圧縮率: 非圧縮データサイズに対する圧縮データサイズの比率
- 圧縮時間: 非圧縮データを圧縮したときの所要時間
- 圧縮時スループット: 圧縮時の単位時間あたりの圧縮後サイズ
- 圧縮時メモリ: 非圧縮データを圧縮したときの最大メモリ使用量
- 伸長時間: 圧縮データを伸長したときの所要時間
- 伸長時スループット: 伸長時の単位時間あたりの伸長後サイズ
- 伸長時メモリ: 圧縮データを伸長したときの最大メモリ使用量
バイナリデータ
Ubuntu 22.04 LTSのlinux-modules-extraパッケージの伸長後のデータ部分(約340MiB)での測定結果。
コマンド名 | 圧縮率 [%] | 圧縮時間 [sec] | 圧縮時スループット [MiB/sec] | 圧縮時メモリ [KiB] | 伸長時間 [sec] | 伸長時スループット [MiB/sec] | 伸長時メモリ [KiB] |
---|---|---|---|---|---|---|---|
gzip | 27.85 | 15.88 | 5.90 | 1,892 | 2.14 | 63.37 | 1,708 |
bzip2 | 22.55 | 19.60 | 3.87 | 8,596 | 8.92 | 14.22 | 4,972 |
lzop | 40.35 | 0.86 | 157.85 | 2,144 | 0.69 | 153.64 | 1,780 |
lz4 | 40.39 | 0.78 | 174.22 | 8,720 | 0.31 | 357.95 | 8,984 |
xz | 16.22 | 151.72 | 0.36 | 97,524 | 4.22 | 38.85 | 10,348 |
zstd | 23.10 | 1.99 | 39.05 | 45,904 | 0.54 | 232.05 | 5,508 |
- 傾向はテキストデータの場合とほぼ同一
- 今回使用したデータでは、テキストデータのほうがバイナリデータよりも圧縮率が良く伸長時スループットが高い
- 圧縮・伸長時の最大メモリ使用量はテキストデータの場合とほぼ同一値 (データの種別やサイズによらないと捉えてよさそう)
測定に関する補足
- 最大メモリ使用量を測定するために、シェルのビルトインの
time
ではなく/usr/bin/time
コマンドを使用した - ストレージ入出力による速度低下を避けるため、実行はtmpfs上で行った
使用したスクリプトは下記のとおり。コマンドライン引数に非圧縮ファイル名を並べて実行する。
使用したスクリプト
#! /bin/sh
if [ $# -eq 0 ]; then
echo 'No files specified' 1>&2
exit 1
fi
trap '
exit_status="$?"
test -f compressed && rm compressed
exit "$exit_status"
' EXIT
trap 'exit 1' HUP INT TERM
for file in $*; do
data_original_size=`stat --format='%s' $file`
for cmd_set in \
'gzip:zcat' \
'bzip2:bzcat' \
'lzop:lzop -d' \
'lz4:lz4cat' \
'xz:xzcat' \
'zstd:zstdcat' \
; do
cmd_compress=`echo $cmd_set | cut -d: -f1`
cmd_decompress=`echo $cmd_set | cut -d: -f2`
$cmd_compress < $file > compressed
data_compressed_size=`stat --format='%s' compressed`
data_compress_ratio=`echo "${data_compressed_size} / ${data_original_size}" | bc -l`
data_tmp=`/usr/bin/time --format '%U,%M' $cmd_compress < $file 2>&1 >/dev/null`
data_compress_time=`echo $data_tmp | cut -d, -f1`
data_compress_rss=`echo $data_tmp | cut -d, -f2`
data_compress_throughput=`echo "${data_compressed_size} / (1024 * 1024) / ${data_compress_time}" | bc -l`
data_tmp=`/usr/bin/time --format '%U,%M' $cmd_decompress < compressed 2>&1 >/dev/null`
data_decompress_time=`echo $data_tmp | cut -d, -f1`
data_decompress_rss=`echo $data_tmp | cut -d, -f2`
data_decompress_throughput=`echo "${data_original_size} / (1024 * 1024) / ${data_decompress_time}" | bc -l`
rm -f compressed
echo "${file},${cmd_compress},${data_compress_ratio},${data_compress_time},${data_compress_throughput},${data_compress_rss},${data_decompress_time},${data_decompress_throughput},${data_decompress_rss}"
done
done
Discussion