tsyama記

プログラミングとそのほか

tideways_xhprofでプロファイル(Docker編)

はじめに

先日PHPカンファレンス福岡 2019で聞いた「PHPの関数実行とその計測」というセッションに出てきた、tideways_xhprofというプロファイラが面白そうだったので触ってみました。

PHPプロファイラって何

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のはじめとおわりにぶち込んであげると一通りのプロファイルができますが、一通り出力するとなるとそれはそれでフレームワークのコアにあたる処理がノイズだったりします。

見方

f:id:tsyama-desu:20190708173429p:plain

xhprof-htmlの画面はこんな感じです。

  • FunctionName
    • コールされた関数名
  • Calls
    • コールされた回数
  • Calls%
    • 全体のコール回数に対する割合
  • Incl. Wall Time
    • その関数全体の処理時間
  • IWall%
    • 全体の実行時間に対する割合
  • Excl. Wall Time
    • その関数から呼ばれた関数の実行時間を除外した、関数の純粋な処理時間
    • Excl. Wall TimeをCallsで割ると1回あたりの処理時間になる
  • EWall%
    • Incl WallTimeに対する割合

詳しくは下記記事がわかりやすいです。

参考: xhprofの読み方 - でつmblr

おわりに

これで快適なプロファイリングライフが送れるはずです。ありがとうございました。

参考: モダンな xhprof = tideways | ごみばこいん Blog