PHP8 で JIT が使えるようになるそうなので、ワクワクが止まりません。手軽に触れるイメージが Docker ないものか。
- 2020/06/23 に PHP8-alpha1 がリリースされたので、いよいよリリース間近になりました。楽しみです。
TL; DR
PHP のソースコードの master
からコンパイルして JIT を有効にした Docker イメージを作ってみました。Mac に標準インストールされている PHP7.1 と比較して 2〜5 倍近く速いです。
信じられないかもしれませんが、macOS に標準インストールされている PHP v7.3.11 をローカルで動かすより、ラズパイ3 の Docker 上で動かした方が JIT が有効になっていなくても速いんです。(詳しくは TS; DR)
🐒 2021/03/21 追記: 公式の PHP8 の Docker イメージもラズパイ(ARM 系 CPU)でも動くようになりました。しかし、当イメージおよび公式も、残念ながらラズパイ上では JIT を有効にできません。ARM 系 CPU 用の JIT の PHP モジュールがまだ完成していないためです。それでも PHP 7 系より速いですが。
docker pull keinos/php8-jit:latest
-
このイメージは、Mac や Windows の Intel/AMD の x86_64 系以外にも、ラズパイ3、ラズパイZero の Docker でも動くようにしています。
- 動作確認 OS とハード:
- macOS Mojave (MacBookPro Early 2015, x86_64)
- Raspbian Stretch (RaspberryPi 3, ARMv7l)
- Raspbian Buster (RaspberryPi ZeroW, ARMv6l)
- いずれも Docker v19.03.2
- 動作確認 OS とハード:
-
このイメージは、
JIT
を有効にしていますが、ARM 系 CPU の場合、無効になってしまいます。 -
このイメージは、
mbstring
を有効、language
をjapanese
、タイムゾーンをAsia/Tokyo
に設定してあります。 -
Docker イメージ: https://hub.docker.com/r/keinos/php8-jit @ Docker Hub
-
Dockerfile: https://github.com/KEINOS/Dockerfile-of-PHP8-JIT @ GitHub
-
拡張モジュール:
-
拡張モジュールのインストール:
"sockets"モジュールをインストールする例docker-php-ext-install sockets
-
PHP Info:
-
Reference:
- PHP GR8 | Musings, ninja ones @ Joe Watkins' Blog
- 下記記事とイメージが大変参考になりました。
- Compiling PHP 8 from source with JIT support @ arkadiuszkondas.com
- How to run PHP 8 with JIT support using Docker @ arkadiuszkondas.com
簡易速度テスト
Test | v5.6.40 | v7.0.33 | v7.1.33 | v7.2.31 | v7.3.18 | v7.4.6 | 8.0.0-dev (JIT Off) |
8.0.0-dev (JIT On) |
---|---|---|---|---|---|---|---|---|
Fibonacci(32) | 1.521 | 0.665 | 0.598 | 0.269 | 0.239 | 0.194 | 0.261 | 0.107 |
Zundoko-Kiyoshi Looping | 2.485 | 1.462 | 1.413 | 0.701 | 0.646 | 0.636 | 0.672 | 0.416 |
-- Zend Bench -- | ||||||||
simple | 0.178 | 0.100 | 0.101 | 0.064 | 0.051 | 0.041 | 0.054 | 0.002 |
simplecall | 0.186 | 0.027 | 0.027 | 0.010 | 0.010 | 0.007 | 0.010 | 0.001 |
simpleucall | 0.210 | 0.071 | 0.080 | 0.023 | 0.018 | 0.025 | 0.022 | 0.001 |
simpleudcall | 0.226 | 0.076 | 0.088 | 0.028 | 0.021 | 0.021 | 0.024 | 0.001 |
mandel | 0.491 | 0.320 | 0.329 | 0.189 | 0.190 | 0.175 | 0.189 | 0.007 |
mandel2 | 0.643 | 0.360 | 0.358 | 0.167 | 0.167 | 0.184 | 0.170 | 0.008 |
ackermann(7) | 0.187 | 0.061 | 0.067 | 0.032 | 0.031 | 0.031 | 0.033 | 0.015 |
ary(50000) | 0.031 | 0.008 | 0.007 | 0.007 | 0.008 | 0.007 | 0.007 | 0.007 |
ary2(50000) | 0.025 | 0.006 | 0.005 | 0.006 | 0.007 | 0.006 | 0.006 | 0.006 |
ary3(2000) | 0.298 | 0.142 | 0.124 | 0.059 | 0.047 | 0.044 | 0.049 | 0.015 |
fibo(30) | 0.594 | 0.230 | 0.228 | 0.106 | 0.091 | 0.081 | 0.093 | 0.042 |
hash1(50000) | 0.049 | 0.024 | 0.024 | 0.016 | 0.015 | 0.015 | 0.015 | 0.016 |
hash2(500) | 0.053 | 0.022 | 0.023 | 0.013 | 0.008 | 0.008 | 0.008 | 0.011 |
heapsort(20000) | 0.145 | 0.073 | 0.069 | 0.037 | 0.036 | 0.036 | 0.037 | 0.014 |
matrix(20) | 0.130 | 0.067 | 0.062 | 0.034 | 0.035 | 0.030 | 0.030 | 0.014 |
nestedloop(12) | 0.301 | 0.145 | 0.143 | 0.088 | 0.091 | 0.072 | 0.091 | 0.013 |
sieve(30) | 0.151 | 0.041 | 0.053 | 0.021 | 0.018 | 0.014 | 0.017 | 0.005 |
strcat(200000) | 0.027 | 0.014 | 0.015 | 0.011 | 0.011 | 0.011 | 0.010 | 0.010 |
--------------- | ------- | ------- | ------- | ------- | ------- | ------ | ----- | ----- |
Total | 3.923 | 1.787 | 1.804 | 0.911 | 0.855 | 0.805 | 0.867 | 0.187 |
使い方
`docker run --rm -it keinos/php8-jit:latest`
基本構文
docker run --rm -it keinos/php8-jit:latest [コマンド] [引数]
docker run --rm -it keinos/php8-jit:latest php -a
-
docker run
で「コンテナの起動」 -
--rm
で「終了後にコンテナを破棄(remove
)」(ロングオプションなので--
です) -
-it
でシェル操作をコンテナとつなげる。-
-i -t
もしくはロングオプションの--interactive --tty
と同じ意味です。つまり、コンテナの標準入出力とローカルの標準入出力を tty 経由でつなげ、コンテナのシェル操作をローカルのシェルから行えるようになります。これを忘れると、実行コマンド終了後に入力待ちにならず処理が終わりコンテナがシャットダウンしてしまいます。
-
-
keinos/php8-jit:latest
で「コンテナの元となるイメージを指定」 -
php
でランタイムを指定 -
-a
で
対話モードで実行
$ # コマンドや引数の指定がない場合は対話モードで起動します(デフォルトの動作)
$ docker run --rm -it keinos/php8-jit:latest
Interactive shell
php > echo phpversion();
8.0.0-dev
php > exit
$
$ # コマンドが php -a の場合と同じ動作です。
$ docker run --rm -it keinos/php8-jit:latest php -a
Interactive shell
php > echo phpversion();
8.0.0-dev
php > exit
$
PHP コマンドの直接実行
$ # php --version の実行
$ docker run --rm -it keinos/php8-jit:latest php --version
PHP 8.0.0-dev (cli) (built: Jul 19 2019 07:09:36) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.0-dev, Copyright (c) Zend Technologies
with Zend OPcache v8.0.0-dev, Copyright (c), by Zend Technologies
$
$ # php -r で `echo "hoge", PHP_EOL;` のスクリプトを実行
$ docker run --rm -it keinos/php8-jit:latest php -r 'echo "hoge", PHP_EOL;'
hoge
$
コンテナ内から PHP を実行
$ # /bin/sh でコンテナ内の Bourne Shell(sh)シェルを起動
$ docker run --rm -it keinos/php8-jit:latest /bin/sh
/ $ # コンテナ内の sh シェルから php -v を実行
/ $ php -v
PHP 8.0.0-dev (cli) (built: Jul 19 2019 07:09:36) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.0-dev, Copyright (c) Zend Technologies
with Zend OPcache v8.0.0-dev, Copyright (c), by Zend Technologies
/ $
/ $ # コンテナ内の sh シェルから`echo "hoge", PHP_EOL;` のスクリプトを php -r で実行
/ $ php -r 'echo "hoge", PHP_EOL;'
hoge
/ $ # シェルを抜けてコンテナを終了
/ $ exit
$
コンテナにファイルをマウントして実行
$ # ローカルのファイルを用意
$ ls
test.php
$ cat test.php
<?php
echo 'Hello World!', PHP_EOL;
$ # test.php をマウントして実行
$ docker run --rm \
> -v $(pwd)/test.php:/app/test.php \
> keinos/php8-jit:latest \
> php /app/test.php
Hello World!
$
コンテナにディレクトリをマウントして実行
$ # ローカルのディレクトリを確認
$ ls
src
$ ls src
index.php functions.inc.php
$ # src ディレクトリをマウントして実行
$ docker run --rm \
> -v $(pwd)/src:/app \
> -w /app \
> keinos/php8-jit:latest \
> php index.php
Hello World! from a function.
$
ビルド
Docker Hub から Pull せずにイメージをビルドしたい場合は、リポジトリを clone
してビルドしてください。
$ # 適当な作業ディレクトリに移動
$ cd ~/
$ # リポジトリを clone
$ git clone https://github.com/KEINOS/Dockerfile-of-PHP8-JIT.git php8
$ # リポジトリに移動
$ cd $_
$ # Docker イメージのビルド
$ docker build --no-cache -t php8-jit .
...
TS;DR(リリースまで JIT 我慢できない)
- 【PHP8】PHPでJITが使えるようになる @ Qiita
上記の Qiita 記事を読んでワクワクが止まらず、触ってみたい欲にかられました。
非公式ながらも PHP 8.0.0 Dev 版の Docker イメージはあるのですが、残念ながらデフォルトで JIT が有効になっておらず、mb_string
なども一緒にコンパイルされていません。
また、PHP 8.0.0 とは言っても最新の master
ブランチを使っているので一番 PHP8 に近いバージョンというだけのようですが、それでも一応 master
は PHP8 用として進められているようです。
JIT の正式採用は PHP8 からと決定されたので、この Docker イメージは「いちはやく JIT の挙動をみるための目的で作成された」とのこと。どうやら JIT を有効にした場合に PHP のコンパイルに難があるようで、それらの注意点をまとめた記事をベースに作られたそうです。
- Compiling PHP 8 from source with JIT support @ Arkadius Zkondas' Blog
測定
そこで、上記記事を参考に JIT および mb_string
を有効にした PHP8 の Dockerfile を作ってみたので、測定してみました。自分でコンパイルしてみたいかたは、リポジトリを clone
して、docker build
してみてください。
測定は「フィボナッチ数」の算出と「ズンドコキヨシ」ループです。リポジトリには Zend の ベンチマークも置いてあります。
テストコード
比較用スクリプト
実行結果
- 同じ PHP8 同士でも JIT を有効にするだけで 2〜3 倍近く速なった。
- Docker で PHP を使うなら 7.3.6 がバランス的(速度・安定的に)にベストと思われる。
PHPバージョン | 実行環境 | 実測値(フィボナッチ数) |
---|---|---|
PHP 5.6.40 | Docker | 1.4402780532837 |
PHP 7.1.23 | ローカル実行 | 0.3146538734436 |
PHP 7.1.23 | Docker | 0.57761478424072 |
PHP 7.3.6 | Docker | 0.23189496994019 |
PHP 8.0.0-dev | Docker (JIT=off) |
0.24225091934204 |
PHP 8.0.0-dev | Docker (JIT=on) |
0.093664884567261 |
| PHPバージョン | 実行環境 | 実測値(ズンドコキヨシ) |
| :--- | :--: |:--- | :--- |
| php 5.6.40 | Docker | 2.3430778980255 |
| PHP 7.1.23 | ローカル実行 | 0.75591492652893 |
| php 7.1.23 | Docker | 1.3070819377899 |
| php 7.3.6 | Docker | 0.60567092895508 |
| php 8.0.0-dev | Docker
(JIT=off)| 0.6335301399231 |
| php 8.0.0-dev | Docker
(JIT=on)| 0.39926886558533 |
- 検証結果
- macOS のデフォルト PHP 7.1.23 のローカル実行と比較しても 2〜3 倍速い。
- JIT を有効にしない場合は PHP8 on Docker がローカル実行の PHP7.1.23 よりやや速いくらい。
- v7.1.23 と v7.3.6 では、v7.3.6 の方がローカルより速い。
- 検証環境
- マシン: MacBook Pro, 2.7 GHz IntelCore, 13inch Early 2015
- OS: macOS Mojave (OSX 10.14.5)
- Docker: 19.03.2