Chienomi

Zerofillデータの圧縮メソッドのベストチョイスは何か

Live With Linux::practical

unix-likeシステムにはgzipをはじめ様々な圧縮メソッドが存在する。

一般的なそれぞれの特徴、例えばgzipはオーソドックス、lz4は高速、bzip2やxzは低速でメモリ消費が大きいなどは知られた話だが、これがzerofillデータになるとどうだろうか?

zerofillデータは、それが前提になっているのであれば、サイズだけ記録されていれば復元可能なデータだ。 あまりにも単純で、極めて圧縮が効きやすいが、それ故に圧縮メソッド側で力を入れて想定するようなものでもない。 このことから、一般的な特徴とは大きく異なる結果が出る可能性がある。

zerofillデータの圧縮が特に重要になるのは、購入したばかりのPCのリカバリーイメージを作成するときだ。 汚れていないディスクは大部分がzerofillされている。2TBのディスクのうち、データが書かれているのは4GB、なんてことがあるわけだ。

しかも、1TBとか2TBとかサイズがあるので、なるべく高速に処理したい。 速度を重視しつつ、非常に小さいサイズに抑えられるのが理想。

一覧表

Ryzen5 5600X (6C12T)のSchedutilsで計測した。 メモリはDDR4-3200で32GB。

ソースは1GiBのzerofillされたファイル。

command options time size ratio
gzip -1 -c 2.313 4583762 0.004476
bzip2 -1 -c 4.645 6533 0.000006
xz -0 -c 5.101 156316 0.000153
xz -0 -c -T0 0.582 263200 0.000257
lz4 -1 -c 0.630 4214543 0.004116
zstd -c --zstd=strategy=1 0.380 33679 0.000033
zstd -c -T0 --zstd=strategy=1 0.379 33679 0.000033
zstd -c --format=lz4 1.699 4423696 0.004320
zstd -c -T0 --format=lz4 1.697 4423696 0.004320

コメント

gzip/lz4はでかい

無難そうなgzipやlz4は、サイズが突出して大きい。

gzipは速くもない。

bzip2は小さいが遅い

bzip2は突出して小さい。

だが、かなり遅く、時間をかけて丁寧に圧縮している感じ。 それでもシングルスレッドxzよりは速く、xzより小さい。

xzは-T0なら速いが、サイズは大きくなる

-T0した場合、ほとんどスレッド数に比例して高速化できる。 もっとコア数の多いCPUなら最速だろう。

しかし、かなりサイズは増えている。 スレッド間でソースの情報を共有していないためだろう。

ただ、同じ割合だとすると、1TBに対して260MBほど。十分小さいため、速度重視ならxz -0 -T0はアリかもしれない。

zstdの-Tは無意味?

zstdの場合、-T0しても速度的にもサイズ的にも変化がない。

効いてないのかとも思ったが、ソースを見てワーカーにオフロードするため、zerofill部分は並列にならないのかもしれない。

この結果ではzstdのstrategy=1が最速だが、CPUコア数が増えればxz -T0が逆転しそう。

zstdのlz4はいいとこなし

遅い上に大きい。

zstdはzstdのために使うのが良さそうだが、並列化が効くなら話は少し変わってくる可能性もある。 ただ、それでも--zstd=strategy=1のほうが速そうなので、あまり他の選択肢は候補にはならないように思える。

実際にやってみた所感

そもそもこのテストをするに至った動機でもあるが、新しいラップトップが手元に届いたので、「Windows 11 Homeがプリインストールされた、まっさらな状態の512GB SSD」を圧縮保存してみた。

zstd -c --zstd-strategy=1はCore i7-1360P (Raptor Lake-P)のモバイルラップトップでも100%なんてとても届かない使用率だったため、生で転送してデスクトップ側で圧縮するよりも、ラップトップ側で圧縮してデスクトップ側は保存するだけのほうが転送量が減少して高速であった。

ただ、ファイルサイズは期待ほど小さくならず、最終的には31078190650バイトとなった。 だいたい1/16で、あまり満足のいく結果ではない。

試しに

unzstd -c < file.img.zst | bzip2 -1 -c > file.img.bz2

してみたところ、最終的なサイズは31889672357バイトとむしろ増加してしまった。

zstdの場合はコンスタントに容量が増加し続けていたのに対し、bzip2では容量がほとんど増加しない時間があったため、zerofill部分の圧縮に関しては先の実験の通りの結果が得られているように思う。 しかし、データ圧縮に関してはzstdのほうが優れているのか、この再圧縮は報われなかった。

なお、所要時間は1:51:20であり、結構長い。

Windows 10 Homeの入っていたIdeaPad Slim 360 (17)のxz -eの結果が8797336184バイト、Windows 10 Professionalが入っていたThinkPad X1 Carbon Gen6の結果が7791701089バイトであることを考えると随分大きい。 これは、Windows 11が大幅に膨張したのかもしれないし、Dynabookだから色々余計なものが入っていてデータサイズが大きいのかもしれない。

データサイズ削減を主眼において

unzstd -c < file.img.zst | xz -e -c -T0 > file.img.bz2

も試してみたところ、非常に多くのCPUリソースを費やしたが、28996113836と削減幅は2GB程度だった。

このDynabook特有の事情がある可能性もあるが、所要時間を飲んでzstd→bzip2に変更する価値はなさそうだ。

結論

zerofillデータの圧縮そのものはbzipが容量面では優れている。 速度ではコア数が多い環境なら最速はおそらくxz -0 -T0だが、サイズも加味して考えるならzstd --zstd=strategy=1がベストっぽい。

初期ディスクのダンプしいう観点では、転送元(新品ラップトップ)側でzstdで圧縮して転送するのが一番早そうだ。

実際はデータも絡むため、zerofill圧縮率に優れたbzip2に圧縮し直すのは微妙。 というよりも、zstdが結構優秀で、互換性の問題を除けばbzip2を使う理由はなさそう。

XZを採用するかという意味では、-eオプションまでつければ多少データサイズの節約にはなるが、得られるものは小さいので、本当に少しでもサイズを小さくしたいという場合のみか。