libwebp のバージョンをあげると速くなる

# きっかけ

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"> libwebp, 昔よりだいぶ処理速度早くなった気がする。</p>&mdash; Ryo Suzuki (@Reputeless) <a href="https://twitter.com/Reputeless/status/1089166491663065088">2019年1月26日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

こちらの呟きを見て気になったので雑にエンコード速度を計測してみました。(多分、この呟きはデコードを意図してそうですが、今回はエンコードが対象)
結論としては 0.5.0 より前からバージョンアップすると速くなります。なお、デコードは速すぎて測るのが面倒で調べてません。

# 測定環境

- MacBook Pro 2018 15inch 安い方のモデル
  - 2.2GHz Intel Core i7
  - メモリ32GB 2400MHz DDR4

- macOS Mojave (10.14.3)
  - cc: Apple LLVM version 10.0.0 (clang-1000.10.44.4)
  - libwebp: 0.2.0 〜 1.0.2　(0.4.4 はコンパイルエラーが出たので除外)
  - libpng: 1.6.36

# 利用ツール

libwebp 付属の cwebp コマンドは PNG から WebP に変換するので、WebP のエンコードの時間がだいたいわかります。(PNG のデコードはめっちゃ速いと仮定)

dwebp で WebP のデコード時間も計測できれば良いのですが、PNG エンコードの時間が支配的なので諦めました。

# 対象画像

```shell:
% identify IMG_0982.png
IMG_0982.png PNG 4032x3024 4032x3024+0+0 16-bit sRGB 18.0796MiB 0.000u 0:00.000
```
Qiita はこのサイズの画像をアップロード出来ないようで、縮小版で失礼します。

![IMG_0982-640.png](https://qiita-image-store.s3.amazonaws.com/0/1798/ff16ddc9-b965-5f4d-c044-5d64b411821c.png)


# テスト作業

## libwebp ビルド

tarball はここから取ってきました。

- https://github.com/webmproject/libwebp/releases (v0.6.1 〜 v1.0.2)
- https://chromium.googlesource.com/webm/libwebp (v0.2.0 〜 )

```shell
~/src/graphics/libwebp% ls
libwebp-0.2.0.tar.gz	libwebp-0.4.3.tar.gz	libwebp-0.6.0.tar.gz
libwebp-0.3.0.tar.gz	libwebp-0.4.4.tar.gz	libwebp-0.6.1.tar.gz
libwebp-0.4.0.tar.gz	libwebp-0.5.0.tar.gz	libwebp-1.0.0.tar.gz
libwebp-0.4.1.tar.gz	libwebp-0.5.1.tar.gz	libwebp-1.0.1.tar.gz
libwebp-0.4.2.tar.gz	libwebp-0.5.2.tar.gz	libwebp-1.0.2.tar.gz
```

- 展開

```shell:
~/src/graphics/libwebp% ls
libwebp-0.2.0	libwebp-0.4.1	libwebp-0.4.4	libwebp-0.5.2	libwebp-1.0.0
libwebp-0.3.0	libwebp-0.4.2	libwebp-0.5.0	libwebp-0.6.0	libwebp-1.0.1
libwebp-0.4.0	libwebp-0.4.3	libwebp-0.5.1	libwebp-0.6.1	libwebp-1.0.2
```

- まとめてビルド&インストール

```shell:
for d in libwebp-?.?.?;
  do v=${d#libwebp-} ; echo $v 
  ( cd $d ; ./autogen.sh ; ./configure --prefix=$HOME/libwebp/$v ; make install ) ;
  done
```

```shell:
~/libwebp% ls
0.2.0	0.4.0	0.4.2	0.4.4	0.5.1	0.6.0	1.0.0	1.0.2
0.3.0	0.4.1	0.4.3	0.5.0	0.5.2	0.6.1	1.0.1
~/libwebp% ls 1.0.1/
bin	include	lib	share
~/libwebp% ls 1.0.1/bin/
cwebp	dwebp
```

## 実行

- まとめて実行して計測

```shell:
for n in `seq 1 100` ;
  do for v in ?.?.? ;
    do echo -n $v ; time $v/bin/cwebp IMG_0982.png -o $v.webp >& log ;
  done ; done >& log1-100.txt
```

## 集計

異常値を除外する為に、100回計測した値のうち、大きい方から25個、小さい方から25個削って、中央値付近の50個を残して平均をとりました。いわゆる trimmed mean です。

```php
foreach ($timeTable as $version => $arr) {
    $arr = $timeTable[$version];
    sort($arr);
    $timeTable[$version] = array_slice($arr, 25, 50);  // trimming
}

$meanTable = [];
foreach ($timeTable as $version => $arr) {
    $total = 0;
    foreach ($arr as $v) {
        $total += 60.0 / $v;  // per minutes.
    }
    $meanTable[] = $total / count($arr);  // mean
}
```

# グラフ

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1798/2920b7dc-f5e8-e9d1-32b3-f4e994361765.png)

ファイル入出力や PNG デコードの時間が混ざって嵩上げされるので、純粋な WebPエンコードの速度はグラフの見た目よりも違いが大きい可能性もあります。あと、本来は Error Bar をつけるべきですが今回は手抜きです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/1798/83552168-4a8e-3a19-cc1d-e3ea81691865.png)

# 備考

色々手抜きしてる点。

- cwebp を使って PNG Decode と WebP Encode をごっちゃに測ってる
- cwebp のデフォルトの設定なので、画質や利用シーンに応じた設定をした場合は多分話が別
- 処理毎に cwebp を起動し直してるので runtime 立ち上げコストも混ざってる
- ストリーミング処理するならレイテンシーが大事だけど。それが分からない
- コンパイルする時にオプション次第でまた結果が変わると思います。特に最適化の指定もしてませんし

# グラフの様子

- 0.2.0 はめっちゃ遅い
- 0.3.0 で大分速くなってる ↑
- 0.4.0 で少し遅くなってる　↓
- 0.5 でもう一段階速くなってる ↑

# 結論

古いバージョン使ってる場合は、最新のを試すと良いのではないでしょうか。

# その他

libwebp-6.0.0 で色劣化が減るオプションの追加があるので、それを理由にバージョンを上げるのも良いかもしれません。

- WebP の色劣化問題の改善
   - https://qiita.com/yoya/items/f5ef9b66b556eda9e6bf