PHP8系へのJITコンパイラ導入方法&処理速度を検証(小話52)


アイキャッチ画像

PHP8.0からJITがPHP言語機能として実装され、理論上大幅な速度向上を達成したとの事なので超今更ですが実際にコードを書いて実際に検証してみました。

※実装・速度検証をすぐご覧になりたければ↓目次からどうぞ

[temp id=6]

JITを導入しよう

OPcache・JITコンパイラとは

ほんの少しだけ用語解説。QiitaやZenn・DEVとかに詳しい解説があるので是非ご覧あれ。

PHPは本来インタプリタ型言語としてopcodeに変換して処理されますが、OPcacheを使うことでメモリ内に保存されて次リクエスト時に変換を不要にして高速化を図るというものです。(「キャッシュ」という語が含まれている通り)
※opcodeは.NET Frameworkの中間言語「IL」的なポジション

JITは”Just In Time”の略でJITコンパイラを使えば、ネイティブコード(機械語)まで一気に変換したものをメモリ内に保存して再利用する事ができます。
JITコンパイラというワードはJVM(Java Virtual Machine)で有名です。Javaの場合、JVMを通じで機械語に翻訳されます。

「JITコンパイラを使えば1.5~2倍高速になるよ」と正式発表しています。

公式より

OPchache+JITを設定

PHPのコントリビューターの方々のおかげで非常に簡単にJITを有効にすることができます。(えげつないcommitが行われたそうです)

$ php -v
PHP 8.0.14 (cli)

1. まずはOPCacheを有効にしていない場合は有効にしましょう。以下の部分をコメントアウトします。
※vimの場合、/で検索

[opcache]
opcache.enable_cli=1

2. JITコンパイラ機能を有効にしましょう。同様に以下の部分をコメントアウトします。

opcache.jit=on
opcache.jit_buffer_size=32MB
# デフォルトは32MB。適宜変更

# 関数単位でJITを有効にする場合以下に変更
opcache.jit=function

3. 有効になったことを確認しましょう
※grepコマンドで確認可能

$ php  -i | grep opcache.enable_cl
opcache.enable_cli => On => On

$ php -i | grep opcache.jit*
# 省略

※phpinfoでも確認可能です

速度向上したのか検証

基本的にはBanch.phpなどを実行すれば良いでしょうが、自分で書いたコードだとどうなんだ?という点を検証してみました。

今回はすべてデフォルト設定でWSL環境上で実行しました。すべてのデータは以下に掲載しております。掲載データは有効数字3桁です。(以下URLに生の数値があります)

行列演算が倍速に!

まずはPHP-MLを使った逆行列(inverse)の計算100万回を4回実行した平均時間を計測してみました。※while文使ったが速いのですが今回は汎用性も考慮してforで繰り返しています

逆行列演算(100万) 標準設定 OPcache+JIT
1 11.859 6.526
2 12.024 6.599
3 12.062 5.911
平均(s) 11.982 6.346
短縮率(%) 47.039

短縮率は47%で実行速度はおよそ2倍であることが分かりました。OPCacheやJITの特性を考えると、繰り返す回数が多ければ多いほど効果が現れます。

四則演算はあまり変化無し

次に3次地域メッシュコード300万回を計算してみました。計算結果は以下のとおりです。

地域Mesh演算(300万) 標準設定 OPcache+JIT
1 5.745 5.049
2 5.724 4.974
3 5.772 4.811
平均 5.747 4.944
短縮率(%) 13.968

先程の行列演算では2倍程度の速度向上が見られましたが、単純な四則演算ではそれほど高速化の恩恵は得られなかったです。
それでも13%高速化することができました。

QRコード生成テストでエラー発生

有名な2次元QRコード生成ライブラリ「Endroid/QrCode」を用いてランダムな256バイトのQRコードを100枚生成してみました。

QRコード生成(100) 標準設定 OPcache+JIT
1 4.646 Err
2 4.711 Err
3 4.699 Err
平均 4.685 Err

結果はまさかのエラー。
これはJITを有効にした事によって起こったものではなく、OPcacheのみ有効にした場合でもエラーが発生しました。

エラーメッセージを見た限りだと画像処理のGD extention系の問題であると推定され、このようなエラーが起きないとは限らない事が分かりました。

実際に恩恵はさほど得られない?

行列計算で使ったライブラリ「PHP-ML」はほぼ100%の純度でPHPコードでした。例えばPythonをexec()でぶん投げるだけのコードだと速度向上は期待出来ません。

それに加えてファイル入出力やAPIリクエストと言ったOSやディスク速度のような外的要因に依存しない処理の場合、非常に期待して良いのではないでしょうか。
ですので、Webアプリケーションのような実際に使うとなると2倍高速!超高速!のような事はあまり期待しないほうが良いでしょう。

必ず事前にライブラリ等がエラーを吐かないのかチェックして導入することをお勧めします。それさえクリアすれば非常に簡単に高速化できる手段として有用であることがわかりました。