はじめに
先日PHPカンファレンス福岡 2019で聞いた「PHPの関数実行とその計測」というセッションに出てきた、tideways_xhprofというプロファイラが面白そうだったので触ってみました。
PHPプロファイラって何
PHPの性能解析ツールです。
先述の記事の解説がわかりやすいので目を通しておくといいと思います。
tideways_xhprofって何
いい感じにPHPのプロファイリングができるOSSです。これも上記のリンクを見ましょう。
導入
環境をDockerで作っているのであれば、tidewaysについても別途コンテナを建てると使いやすそうです。
概観
こんな感じのdocker-compose.ymlになります。
version: "3"
volumes:
xhprof:
services:
web:
build: ./web/
volumes:
- ./web-data/:/var/www/html/
- xhprof:/tmp/xhprof/
ports:
- 8080:80
xhprof:
build: ./xhprof/
volumes:
- xhprof:/tmp/xhprof/
ports:
- 8081:80
web:
webコンテナにはアプリケーションが格納されます。適宜下記設定を自分の環境に落とし込んでください。
xhprofボリュームをつくる
tideways_xhprofでは出力としてシリアライズされたデータファイルを作成し、それとは別に可視化ツールを利用してビジュアライズするのが一般的なようです。今回はxhprofボリュームでデータファイルを永続化し、webコンテナからビジュアライズ用のxhprofコンテナと共有するイメージで構成しています。
tideways_xhprof拡張をインストールする
tideways_xhprofを使うには、tideways_xhproftというPHP拡張をインストールしてやる必要があります。yumとかaptも用意されているようなのですが、うまくいかなかったので自力makeしました。Dockerfileに落とし込んでるので参考にしてください。
FROM php:7.3-apache
RUN apt -y update
RUN apt install -y \
git
WORKDIR /root/
RUN git clone https://github.com/tideways/php-profiler-extension.git
WORKDIR /root/php-profiler-extension
RUN phpize
RUN ./configure
RUN make
RUN make install
RUN echo 'extension=tideways_xhprof.so' >> /usr/local/etc/php/conf.d/tideways.ini
RUN echo 'tideways.auto_prepend_library=0' >> /usr/local/etc/php/conf.d/tideways.ini
RUN mkdir /tmp/xhprof
RUN chmod 777 /tmp/xhprof/
WORKDIR /var/www/html/
今回、出力ファイルの格納ディレクトリとして/tmp/xhprof/を使用します。そのままやるとapacheユーザーに書き込み権限が付与されないため、Dockerfileであらかじめmkdirしたうえで、chmodでパーミッションを変更しておきます。
xhprof:
webコンテナが出力したデータファイルを同期し、ビューアで閲覧するためのコンテナです。今回は設定が簡単そうなxhprof-htmlを使用しました。
FROM php:7.3-apache
RUN apt -y update
RUN apt install -y \
git \
graphviz
WORKDIR /var/www/html/
RUN git clone https://github.com/sters/xhprof-html.git .
RUN sed -i "81c\$xhprof_runs_impl = new XHProfRuns_Default('\/tmp\/xhprof');" callgraph.php
xhprof-htmlを導入するためのDockerfileです。このまま使えると思います。
- xhprof-html側では、データファイルのパスを特定するために、php設定ファイルの
xhprof.output_dirもしくはsys_get_temp_dir()の値を使用します。xhprof.output_dirの設定を変えて対応しようかと思ったのですがうまくいかなかったので、sedコマンドでむりやり書き換えました。ひどいやり方です。 - xhprof-htmlでは結果に基づいてコールグラフを生成してくれますが、この処理に
graphvizが必要になるのでaptでインストールしておきます
アプリケーション側の処理書き換え
書き換えといっても簡単です。tidewaysが提供するtideways_xhprof_enable()とtideways_xhprof_disable()という関数で、計測したい処理を挟んでやります。
tideways_xhprof_enable(); hoge(); $data = tideways_xhprof_disable(); $filename = '/tmp/xhprof/' . intval(microtime(true)) . mt_rand(1,10000) . '.xhprof.xhprof'; file_put_contents($filename, serialize($data));
$filenameのところはデータファイルを置きたいパスにより調整しましょう。諸般の事情により、ファイルのサフィックスは.xhprof.xhprofになるようです。
Laravelなどのwebフレームワークであればpublic/index.phpのはじめとおわりにぶち込んであげると一通りのプロファイルができますが、一通り出力するとなるとそれはそれでフレームワークのコアにあたる処理がノイズだったりします。
見方

xhprof-htmlの画面はこんな感じです。
- FunctionName
- コールされた関数名
- Calls
- コールされた回数
- Calls%
- 全体のコール回数に対する割合
- Incl. Wall Time
- その関数全体の処理時間
- IWall%
- 全体の実行時間に対する割合
- Excl. Wall Time
- その関数から呼ばれた関数の実行時間を除外した、関数の純粋な処理時間
- Excl. Wall TimeをCallsで割ると1回あたりの処理時間になる
- EWall%
- Incl WallTimeに対する割合
詳しくは下記記事がわかりやすいです。
おわりに
これで快適なプロファイリングライフが送れるはずです。ありがとうございました。