Profiling Tools For PHP7

このエントリーは [KLab Advent Calender](https://qiita.com/advent-calendar/2017/klab) 13日目の記事です。

# はじめに

みなさんはPHPのプロファイリングでは、普段どのプロファイラを使っていますか？
PHPのプロファイラとして利用できるものはXHProf、Xdebug、blackfire、tidewaysなど様々あります。
それぞれのプロファイラには得意・不得意がありますし、どのように利用したいかによって導入するプロファイラを選定した方が良いでしょう。
ですが、このプロファイラ周りについてネットで調べてみても、PHP5時代のXHProfを導入するといった古い記事が多く、PHP7用の記事が意外と少ないので、改めてPHP7用にプロファイラを紹介したいと思います。

# PHP7でのXHProfについて
PHP7でプロファイリングしようとして困った方が多いのではないでしょうか。
というのも、それまでのPHPのプロファイラで定番だったXHProfが[PHP7未対応だからです](https://github.com/phacility/xhprof/issues/82)。
PHP5を利用しているケースではこれまでのXHProfで問題ないですが、PHP7を利用している場合はXHProfが使えません。
実は有志が開発しているXHProfのフォークがいくつか([その1](https://github.com/RustJason/xhprof/), [その2](https://github.com/longxinH/xhprof), [その3](https://github.com/Yaoguais/phpng-xhprof) , ...etc)あります。
isucon用に使うために、フォークされたものをいくつか実際に使ってみましたが、中にはプロファイル結果で単純に関数名だけでなく、実行したSQLクエリ文も表示してくれるような公式のXHProfにはない機能があるものもあったりします。
ただ、isuconのような場合だとまだ良いかもしれませんが、実際の運用案件だと、非公式・実績が少ない・開発が止まるかもしれないプロファイラの導入には少し抵抗があるかもしれません。
そんな場合におすすめなのがtidewaysです。tidewaysのweb上の高機能なUIを利用しないのであれば、XHProfの代替として無料で利用できます。

## tidewaysをXHProfの代替として利用する
tidewaysのGitHubのページにある通り下記のようにしてインストール可能です。

```bash
git clone https://github.com/tideways/php-profiler-extension.git
cd php-profiler-extension
phpize
./configure
make
sudo make install
```

tideways.ioのwebインターフェイスを利用しない場合は、下記のように設定します。

```
extension=tideways.so
tideways.auto_prepend_library=0
```

以上でtidewaysをXHProfの代替として利用できます。
tidewaysのプロファイル結果のフォーマットはXHProfと同じですので、通常のXHProfのようにXHGuiと組み合わせて使うことも可能です。

# SaaS型プロファイラ
単純なプロファイリングに留まらず、高機能なUI、監視、他サービスとの連携等を１つのソリューションとしてSaaSで提供するサービスも登場しました。代表例では[tideways](https://tideways.io/)や[blackfire](https://blackfire.io)があります。

SaaS型は有料なだけあって非常に高機能です。
例えばblackfireでは[PHPUnitとの統合](https://blackfire.io/docs/integrations/phpunit)が可能で、テストコードという形でblackfireの各種メトリクスを検証することが可能です。
また[テストシナリオで豊富な検証を記述できたり](https://blackfire.io/docs/cookbooks/tests)、様々なトリガーからテストを実行しレポートをダッシュボード上で確認することができます。
これを使えば、GitHubでPRを作った際等に自動的にblackfireのテストを実行して改修した内容のパフォーマンス上の影響を確認する、というような事も出来ます。
このように、プロファイリングを開発フローの一部として取り入れることが出来るような仕組みはXHProfのような従来のプロファイラにはない機能で魅力的です。
開発フローへの統合の仕組みの実例としてtrivagoの[記事](http://tech.trivago.com/2017/10/27/continuous-performance-monitoring-for-php---the-tale-of-blackfire-at-trivago/)が参考になりますので、SaaS型のプロファイラの導入を検討している方は是非参考にしてみてください。

また、blackfireにはプロファイリング結果や2つのプロファイリング結果の比較内容を公開して他の人と共有する機能もあります。
例えばOSSでパフォーマンス改善をするPRを作った際に、その改修によってどの程度パフォーマンスが改善されるのかの1つの指標として提示するのに利用されていたりします([Symfonyの例](https://github.com/symfony/symfony/pull/24872))。


# サンプリング型プロファイラ
## プロファイリングのオーバーヘッド
基本的に、PHPのプロファイラは全ての関数の実行を内部的にフックして、その時の実行時間や使用メモリ量を計測しています(エクステンション側で[zend_exenceute_ex](https://php-lxr.adamharvey.name/source/xref/PHP-7.0/Zend/zend_vm_execute.h#458)を[独自のプロファインリング用のexecute関数に置き換える](https://github.com/phacility/xhprof/blob/master/extension/xhprof.c#L1855-L1861)ことで実現しています)。

このような計測の場合、全ての実行処理を計測できるので正確な情報が得られますが、その分オーバーヘッドは大きくなります。
Xdebugは多機能ですが、その分オーバーヘッドが凄まじく、もともと本番環境で利用するような想定で作られてはいません。
それに対し、XHProfやtidewaysも同様にフック型ですが、Xdebugよりは軽量なプロファイラで本番環境での利用も想定しています。ただし、それでも高負荷なサービス下で利用しようと思うと無視できないほどのオーバーヘッドになってしまいます。
またフックした時点で実際の負荷とは大きく異なってしまいますし、軽い関数が高頻度で呼び出されているような場合、実際の負荷よりもオーバーに評価してしまいXHProfが遅いといっている部分が、実際にはプロファイラを無効にしている本番環境ではボトルネックにはなっていないという事もあり得るのです。
さらにPHP7の場合、PHP5と比較して処理系自体が高速化されていますので、このオーバーヘッドの割合が大きくなってしまいます。このあたりはtidewaysの[記事](https://tideways.io/profiler/blog/profiling-overhead-and-php-7)が参考になりますので興味のある方は読んでみてください。

## PHPにおけるサンプリング型プロファイラ
XHProfのようなフック型プロファイラでは上記のような問題がありますが、 [sample_prof](https://github.com/nikic/sample_prof/)というプロファイラはフック型とは異なり、定期的にサンプリングするタイプでオーバーヘッドが小さいです。またXHProfは関数レベルの解析しか出来ませんが、sample_profでは行レベルの解析が可能です。そして、sample_profはPHP7でも利用可能です。
ただし、サンプリング型プロファイラは十分なサンプル数を得ないと正確なプロファイリング結果にならない場合がありますので、その点は注意が必要です。
またsample_profにはサンプリング結果情報をHTML形式で表示するスクリプトが同梱されていますが、XHGuiのような高機能なUIが存在しないので、プロファイリング結果の継続的な収集や2つの結果の比較などはできません。本格的な解析をしようと思うとその点がネックになります。
ですが、より少ないオーバーヘッドで実際の負荷に近い状態でプロファイリングが出来ますし、行レベルの情報が得られるのは他のPHPのプロファイラにはない特徴です。
ちなみに、XHProfやtidewaysなどのフック型プロファイラ同士は共存できませんが、smaple_profはフック型プロファイラと共存可能です。

# おまけ

おまけとして[spx](https://github.com/NoiseByNorthwest/php-spx)というプロファイラも紹介しておきます。spxはCLIによる操作でリアルタイムにプロファイル内容を表示、PHP内部のZend Engineの情報をメトリクスとして提供、プロファイル結果を複数の形式による出力、等といった他のプロファイラにはないような機能があります。
まだまだ本番環境で使うという感じではないですが、PHP7にも対応しているので興味のある方は使ってみてください。

# さいごに

ざっとですが、PHPのプロファイラについていくつか紹介してみました。
上記のようにプロファイラそれぞれに特徴があります。
単純にPHP7でプロファイリングしたいのであればtideways+XHGui、将来開発フローとの統合も目論んでいる方はblackfireの無料版でまず試してみる、というのもいいかもしれません。
あなたの環境やニーズにマッチするものを選定して、パフォーマンスチューニングに役立ててください。