比較グラフはこのページの一番下。
このテストは P6 用だが、基本的に Z80 RAM to RAM 汎用のつもり。
unpackbench_20191201.zip
ソース付きテストコード
不特定の圧縮バイナリを展開する目的ではなくベンチマークが目的なので、このソースを流用する前に必ずオリジナルを参照すること。
気が向いたら新しめのアルゴリムを追記するかも。独自の実装で良い成果が出たらテストコードも追記 or 差し替える予定。
P6 で圧縮を必要とするのは、おおむね「無駄にでかい VRAM」のデータだと思うので、以下の画像をサンプルとして使用する。
左が 160x200 サイズに縮小、右が P6 向け 16(15) 色にそれを減色したもの。
アルゴリズムによって向き不向きがあるだろうから一概にこれで測れるとは思わないが、結果がわかりやすいので。
データは格納方法によって4種類のバイナリに分別した。
1)16色=4bpp を L プレーンと H プレーンに分割する。2bpp * 2 プレーンの、どノーマルなやりかた。
2)2ドットを 1byte の上下に格納する 4bpp データ。展開がめんどい。
3)1)の縦方向の格納。
4)2)の縦方向の格納。
縦方向格納はとくにデータが画像であるという性質に依存するが、ものは試しということで。
縦スキャン(プロット)方向については上から下へ行った後、下から上へ蛇行するような感じでやったほうが多少オトクかもしれないが、今回はパス。
圧縮とは関係ないが、普通にフルスクリーン描画する場合でも、横x縦で描画するより縦x横の方が速い。40x200 と 200x40 の差が出る。
2〜4についてはは圧縮率を見るのが主目的。
たいていの処理は、展開時に「前回バラしたデータを参照してコピーする」という処理が挟まる関係で、展開したデータを L, H プレーンに分けたり
縦→横方向に加工したりすると参照がかなり面倒になる。なので今回はバッファを用意している。現実問題 P6 でこれはコストが高い。
また、2〜4のプロットは筆者の PSET ルーチンのやる気次第なのもあって速度はあまり参考にならない。
実際、P6 では展開の速度がどうという話よりもディスク等からのロード時間(と入れ替え)が問題の大半であろうから、圧縮率を重視する意味はある。
テストした圧縮アルゴリズムは、なるべく大元のオリジナルを使用しているが、派生・改良版があるものがある。
筆者が独自に実装した exo3 なども、それら改良版の方が性能がいいものがあるので、差し替えると結果が変わってくるだろう。
uniabis 氏によるこちらのページ
(URL: https://uniabis.net/pico/msx/z80packer/) と
(GitHub) を参考に。
各個別アルゴリズムの「+GIF 画像」をクリックすると GIF アニメ再生。これは method.1 の展開速度を見るものである。
Raw | original | compressed | percentage |
method.1 | 8000 8000 |
8000 8000 | 100% 100% |
method.2 | 16000 |
1600 | 100% |
method.3 | 8000 8000 |
8000 8000 | 100% 100% |
method.4 | 16000 |
16000 | 100% |
GIF 画像1
raw(生)データ。無圧縮で展開方向が違うだけなのでサイズは全て 16000byte である。
GIF 画像ではバッファを用いずにディスクから直接 VRAM にロードしている。
他のものとの比較するならバッファにロードしたあと、LDIR の速度で見ないといけないのだが、P6 において生データをバッファリングする人は居ない(断言)ので。
なお、このページの最後の比較グラフは LDIR で計測してある。
Exomizer3 | original | compressed | percentage |
method.1 | 8000 8000 |
4819 5854 | 60.2% 73.1% |
method.2 | 16000 |
8000 | 50.0% |
method.3 | 8000 8000 |
4445 5611 | 55.5% 70.1% |
method.4 | 16000 |
7530 | 47.0% |
GIF 画像1
Exomizer3 (URL:
https://github.com/antoniovillena/deexo)
バージョンが 2 から 3 になってビットストリームフォーマットやオプション類が変わってしまっている。
現状、ソースコードには 2 系と 3 系が含まれていて "opt" が付くものが 3 系である(が、現状 github の 3 系デコーダはバグがある模様)。
"b" は "backward" のことで、最後尾から先頭に向かって圧縮(展開)する。
圧縮バイナリと展開先がオーバーラップしてしまう場合に、圧縮バイナリを上書きしながら展開するために使う。
圧縮率は良好。ソースは筆者の独自実装だが展開速度がいまひとつでサイズも大きめなので差し替えた方が良いかも。
Exomizer は 2 系 3 系ともに 156byte のテーブル用ワークを必要とする。
こんな感じで圧縮。raw オプションを付けると -P7 -T0 が暗黙で指定されるらしい。
> exomizer raw hoge.bin -o hoge.exo
|
Exomizer2 | original | compressed | percentage |
method.1 | 8000 8000 |
4820 5854 | 60.2% 73.1% |
method.2 | 16000 |
8001 | 50.0% |
method.3 | 8000 8000 |
4445 5611 | 55.5% 70.1% |
method.4 | 16000 |
7531 | 47.0% |
GIF 画像1
Exomizer2。Exo3 との比較用として。
見て分かるとおり、圧縮率には差が無い。
simple 版を使用。圧縮オプションは以下の通り。simple 版でない方は -c が不要。-P0 を付けるのを忘れずに。
これに限った話ではないけれど、256byte 境界のワークを必要とするものは地味に取り回しがキツいかも。
> exomizer raw -P0 -c hoge.bin -o hoge.exo
|
LZ4 | original | compressed | percentage |
method.1 | 8000 8000 |
6626 7417 | 82.8% 92.7% |
method.2 | 16000 |
11154 | 69.7% |
method.3 | 8000 8000 |
6016 7083 | 75.2% 88.5% |
method.4 | 16000 |
10381 | 64.8% |
GIF 画像1
LZ4。(URL:
https://lz4.github.io/lz4/)
幅広く使われている。Z80 だけでなく 8088、6502、65c816、68k などなど様々な実装がある。拙作 GBZ80 版も。
圧縮率はたいしたことないが展開速度がやたら速いのが特徴。
圧縮が効くかどうかは対象にもよるが、あまり期待しない方が良い。
LZ4 は拙作ストリームローダーもあるが今回は未使用 →
R&D ページ。
これは自己書き換えを使ったものだが、無くてもなんとかなる。
メモリ空間に余裕の無い 8bit マシンでは、展開速度は多少落ちるものの、ストリームローダーがあれば使わない理由はないのであった方が嬉しい。
圧縮は以下の通り。-9 は少しでも圧縮率を高めるためのオプション。普通に lz4.exe にドラッグ&ドロップでも良い。
LZ48 | original | compressed | percentage |
method.1 | 8000 8000 |
6435 7249 | 80.4% 90.6% |
method.2 | 16000 |
11829 | 73.9% |
method.3 | 8000 8000 |
5823 6902 | 72.7% 86.2% |
method.4 | 16000 |
10931 | 68.3% |
GIF 画像1
LZ48。(URL:
http://www.cpcwiki.eu/forum/programming/lz48-cruncherdecruncher/)
名前から分かるとおり LZ48/LZ49 は LZ4 の派生版である。
8bit マシンで使うには冗長と思われる部分を弄ってチューニングしたもの。コピーオフセットに 2byte も要らんやろ、とかそういう発想。
LZ4 と比べてもさらに速い。速度特化なら lz4 のリプレースになり得る。
が、圧縮率 80%〜90% の場合は、ほぼ ldir の速度なのであまり参考にならないかも。
オリジナルの lz4 と違ってドラッグ&ドロップで圧縮できない。
> lz48 -i input.bin -o output.lz48
|
LZ49 | original | compressed | percentage |
method.1 | 8000 8000 |
6314 7155 | 78.9% 89.4% |
method.2 | 16000 |
10830 | 67.6% |
method.3 | 8000 8000 |
5668 6790 | 70.8% 84.8% |
method.4 | 16000 |
10018 | 62.6% |
GIF 画像1
LZ49。(URL:
http://www.cpcwiki.eu/forum/programming/lz48-cruncherdecruncher/)
別に LZ48 より LZ49 の方が良いわけではなく、上に書いた「コピーオフセットに 2byte も要らんやろ → いや 9bit くらいは要る」という違い。
LZ4 含め、三種ともに圧縮率に大きな違いは無い。
解凍ルーチンは整形以外にオリジナルから微妙に弄ってある。
LZ48/LZ49 は Z80 用の圧縮ルーチンも提供されている。
ZX7 | original | compressed | percentage |
method.1 | 8000 8000 |
5436 6364 | 67.9% 79.5% |
method.2 | 16000 |
9123 | 57.0% |
method.3 | 8000 8000 |
4840 6013 | 60.5% 75.1% |
method.4 | 16000 |
8311 | 51.9% |
GIF 画像1
ZX7。(URL:
http://www.cpcwiki.eu/forum/programming/zx7-cruncher-(from-spectrum-world)/)
バランスが取れている。Exomizer より圧縮率は低いが展開速度は速い。
展開に際してテーブルやワークエリアが必要ないのは有利な点だと思う。
解凍ルーチンはサイズ・速度別に 3 種提供されている。今回は mega 版を使用。サイズは大きいが一番速い。
サイズが小さい方がいい場合は 69byte の standard 版で。
ZX7 は ZX7b という派生版もある。(URL:
https://github.com/antoniovillena/zx7b)
PMA(pm2) | original | compressed | percentage |
method.1 | 8000 8000 |
5248 6144 | 65.6% 76.8% |
method.2 | 16000 |
8576 | 53.6% |
method.3 | 8000 8000 |
4608 5760 | 57.6% 72.0% |
method.4 | 16000 |
7936 | 49.6% |
GIF 画像1
pma。(URL:
http://www.asahi-net.or.jp/~am9y-mn/fswlist.htm)
MSX や CP/M でよく使われた形式。
書庫機能なども備えているが、単体ファイルのメモリへの解凍という部分だけに限っても他のアルゴリズムよりサイズがかなり大きい。
いち圧縮フォーマットとして見た場合、様々な観点から別の形式を使った方がいいと思う。
用途が違うのでそもそも比較するのが無意味なのだが。
ファイルヘッダは lharc などの level0 と同じようだ。
pma と lh5 についてはテスト用実行バイナリのみとする。ほぼ丸パクリなので。
現状、PMA ファイルを作るなら CP/M エミュレータで作るのが一番速いと思う。
> cpm.exe pmarc2.com hoge.pma hoge.bin
|
LZH(lh5) | original | compressed | percentage |
method.1 | 8000 8000 |
5132 5988 | 64.1% 74.8% |
method.2 | 16000 |
8578 | 53.6% |
method.3 | 8000 8000 |
4628 5631 | 57.8% 70.3% |
method.4 | 16000 |
7912 | 49.4% |
GIF 画像1
lzh(lh5)。
pma よりも更にコードサイズが大きく必要なワークエリアサイズも多い。
圧縮は LHA255.EXE を使用。
> msdos lha.exe a hoge.lzh hoge.bin
|
hrust | original | compressed | percentage |
method.1 | 8000 8000 |
5218 6162 | 65.2% 77.0% |
method.2 | 16000 |
8741 | 54.6% |
method.3 | 8000 8000 |
4621 5722 | 57.7% 71.5% |
method.4 | 16000 |
8018 | 50.1% |
GIF 画像1
hrust。(URL:
https://code.google.com/archive/p/mhmt/source/default/source)
ZX-Spectrum 方面のツールらしい。Z80 用には MegaLZ と Hrust の解凍ルーチンが提供されており、それを使用した。
ヘッダなし(-zxh なし)、かつ SP レジスタを使わないものを選んだが、これは少しばかり遅いらしい。そのかわり割り込み耐性がある。
プログラムを見ると、フェッチが ld r,(ix+0) なのが確かに残念な感じではある。
圧縮率は ZX7 より少し良い。速度も遅くてこれなら十分だと思う。ワークを使わずレジスタだけで完結するのも○。
> mhmt-base -hst hoge.bin
|
MegaLZ | original | compressed | percentage |
method.1 | 8000 8000 |
5210 6212 | 65.1% 77.6% |
method.2 | 16000 |
8865 | 55.4% |
method.3 | 8000 8000 |
4652 5818 | 58.1% 72.7% |
method.4 | 16000 |
8099 | 50.6% |
GIF 画像1
MegaLZ。
hrust と同じツールを使用。
-hst の部分を -mlz にするだけで良い。
hrst より展開ルーチンサイズが小さい。
> mhmt-base -mlz hoge.bin
|
LZE | original | compressed | percentage |
method.1 | 8000 8000 |
5632 6671 | 70.4% 83.3% |
method.2 | 16000 |
9544 | 59.6% |
method.3 | 8000 8000 |
5057 6269 | 63.2% 78.3% |
method.4 | 16000 |
8663 | 54.1% |
GIF 画像1
LZE。(URL:
http://gorry.haun.org/pw/?lze)
ダウンロードリンクが切れているかも。
全体の中でも中段グループの真ん中に位置しているバランス型。比較対象は LZSA2 になるか。
改良版が存在する→
https://github.com/uniabis/lzee
こちらは圧縮フォーマット自体を見直しているようで、エンコーダから別になっている。
LZSA1 | original | compressed | percentage |
method.1 | 8000 8000 |
6205 7148 | 77.5% 89.3% |
method.2 | 16000 |
10514 | 65.7% |
method.3 | 8000 8000 |
5495 6686 | 68.6% 83.5% |
method.4 | 16000 |
9547 | 59.6% |
GIF 画像1
LZSA1。(URL:
https://github.com/emmanuel-marty/lzsa)
LZSA1 は LZ4 のリプレースを狙ったもので、圧縮率・速度ともによりよい結果を出している。
自己書き換えも無いし、後ろ向き展開も出来る。6502/8088 版も提供されている。拙作 GBZ80 版も。
速度優先なら LZSA1、圧縮率優先なら LZSA2 と使い分けするといいかもしれない。
> lzsa.exe -f1 -r hoge.bin hoge.lzsa1
|
LZSA2 | original | compressed | percentage |
method.1 | 8000 8000 |
5660 6654 | 70.7% 83.1% |
method.2 | 16000 |
9258 | 57.8% |
method.3 | 8000 8000 |
4966 6187 | 62.0% 77.3% |
method.4 | 16000 |
8360 | 52.2% |
GIF 画像1
LZSA2。URL などは同じ。これも 6502/8088 版の他、拙作 GBZ80 版がある。
こちらは ZX7 のリプレースを目指したもので圧縮率を向上しながら ZX7 以上の速度を謳っている。
全体の中でも中段グループの真ん中に位置しているバランス型。
LZSA は比較的新しいのもあって活動が活発である。もしかしたら今後 LZSA3... となっていくのかもしれない。
エンコードは -f1 オプションを -f2 にするだけである。
> lzsa.exe -f2 -r hoge.bin hoge.lzsa2
|
Pletter | original | compressed | percentage |
method.1 | 8000 8000 |
5405 6333 | 67.5% 79.1% |
method.2 | 16000 |
9114 | 56.9% |
method.3 | 8000 8000 |
4842 6016 | 60.5% 75.2% |
method.4 | 16000 |
8313 | 51.9% |
GIF 画像1
Pletter。(URL:
http://www.xl2s.tk/)
MSX 関連らしい。全く未知だった。
バイナリの途中から長さを指定して圧縮する機能があるなどユニークである。
圧縮率はそこそこ。ワークも使わない。
展開ルーチン自体も小さいが、サイズを犠牲にすればもう少し速くなりそうな気もする。
Shrinkler | original | compressed | percentage |
method.1 | 8000 8000 |
4872 5776 | 60.9% 72.2% |
method.2 | 16000 |
8152 | 50.9% |
method.3 | 8000 8000 |
3976 5052 | 49.7% 63.1% |
method.4 | 16000 |
6856 | 42.8% |
GIF 画像1
Shrinkler。(URL:
https://github.com/askeksa/Shrinkler)
元は AMIGA 環境のツールらしい。Z80 版は 68k アセンブラからの移植のようだ。
(URL:
https://cpcrulez.fr/applications_tools_cruncher_shrinkler_Z80.htm)
圧縮率が高い。4 を 7-Zip の LZMA2 最高圧縮で処理すると 7273byte(45.4%) なのでいかに高圧縮か分かる。
そしてこの遅さである。256byte 境界の大型ワーク 3072byte・裏レジスタ・未公開命令・自己書き換えまで駆使してこれ。
16bit*16bit=32bit の乗算などが特に重そうな印象。オリジナルと 64KB 環境のスケール感の違いが色々と見受けられる。
しかし解凍ルーチン自体はそこそこコンパクトなので用途次第といったところか。8bit 特化版とかあれば・・・。
ZX7b のページに shr8k という別実装版(?)がある。(URL:
https://github.com/antoniovillena/zx7b)
差し替え用にソースは入れてあるが、速度の差はあまり無い。
オプションには生バイナリデータとして扱うために -d をつける。
圧縮時に表示がうるさいので -p も付けると吉。
> shrinkler -d -p hoge.bin hoge.shr
|
BitBuster | original | compressed | percentage |
method.1 | 8000 8000 |
5503 6421 | 68.7% 80.2% |
method.2 | 16000 |
9307 | 58.1% |
method.3 | 8000 8000 |
4919 6079 | 61.4% 75.9% |
method.4 | 16000 |
8512 | 53.2% |
GIF 画像1
BitBuster Extreme。(URL:
https://cpcrulez.fr/applications_tools_cruncher_bitbuster_extreme_Z80.htm)
CPC 方面で知った。MSX でも使われていたとか。
元々 BitBuster 1.2 というものがあり、Extreme はそのバリアントである模様。
改変箇所は先頭 4byte にあった元のファイルサイズを削ったものらしい。
この記事で取り上げるものは、出来るだけ元の版に準拠したいのだが、どうにも探しきれなかったので・・・。
自己書き換えなし・ワーク不要だが裏レジスタを使っているのが競合より不利かもしれない。
あと、圧縮が若干遅い気がする。
aPLib | original | compressed | percentage |
method.1 | 8000 8000 |
5417 6368 | 67.7% 79.6% |
method.2 | 16000 |
9115 | 56.9% |
method.3 | 8000 8000 |
4810 5969 | 60.1% 74.6% |
method.4 | 16000 |
8294 | 51.8% |
GIF 画像1
aPLib。基本的には最近(?)の CPU や高級言語で動くものらしい。
オリジナル版と圧縮ツールは(URL:
http://www.ibsensoftware.com/products_aPLib.html)にある。
Z80 版解凍ルーチンは(URL:
http://cngsoft.livejournal.com/268202.html)
古いツールを使えばヘッダがつかないバイナリが出力できたのだけど、新しめの v1.1.1 だと 24byte(?) のヘッダが付くようになっている。
TI 電卓などへの移植例もあったようだ。
フラグで逆方向展開もできるようになっている。未公開命令使用・自己書き換えなし・ワーク不要。
フェッチが ld r,(ix+0) なのが地味に痛い。
> appack c hoge.bin hoge.apk
|
Pucrunch | original | compressed | percentage |
method.1 | 8000 8000 |
5293 6266 | 66.1% 78.3% |
method.2 | 16000 |
8933 | 55.8% |
method.3 | 8000 8000 |
4852 6004 | 60.6% 75.0% |
method.4 | 16000 |
8281 | 51.7% |
GIF 画像1
Pucrunch。(URL:
https://github.com/mist64/pucrunch)
元は C64 のツールらしい。6502 版のソースがオリジナル。
URL で示したサイトが本家だと思う(自信ない)。ここに含まれる Z80 版ソースは GB 用なので注意。
圧縮ツールと Z80 版解凍ルーチンは (URL:
https://cpcrulez.fr/applications_tools_cruncher_PUCrunch_Z80.htm)で入手した。
GB 関係の重鎮が前世紀に GBZ80 向けに移植を行っていたようだ。流石。
Z80 版はその再移植になっていて、それゆえコードサイズと速度に少し難がある。
SMS 版への移植もあり。(URL:
http://www.smspower.org/maxim/SMSSoftware/Compressors)
GB/SMS はコードが ROM にあることが前提になっているので自己書き換えできない。RAM 領域にワークを設定するようになっている。
-h でオプション一覧が出る。
圧縮はちょっとわかりにくいので注意。以下の通り。
> pucrunch -d -c0 hoge.bin hoge.puc
|
以上。
やはり注目株は EXO, ZX7, LZSA あたりだろうか。海外のフォーラムでもよく話題に上っているようだった。
LZ4 は速度の目安として一つのスタンダードになっているようだ。
ほかに比較的新しめのフォーマットでいうと、以下のようなものがある(が Z80 版は今のところ無さそう)
LZF
https://github.com/ning/compress
LZ5(Lizardに改名)
https://github.com/inikep/lizard
LZO
http://www.oberhumer.com/opensource/lzo/
話題性や開発の活発さというのも一つの指標になるし、それ以外にもコードベースが ROM か RAM か、裏レジスタや未公開命令は使うのか、
ワークサイズはどれくらいか、自己書き換えはありか、ライセンスは、などなど圧縮率などの数字だけ見ていては分からない部分が多々あるので、
どれが良いというのは一概には言えない。
圧縮効率と速度のグラフ。method.4 を基準に計測。raw は純粋な 16000bytes の ldir の速度。shrinkler がぶっちぎりで遅いので見づらい。
右上に近いものほどバランスが良い。