What's?
タイトルとおり、xhprofをPHP 7.4に導入したいなと思ったのですが。
xhprofに関する情報は、もうメンテナンスさあれてないよ、forkがあるよ、代替があるよ等いろいろあってよくわからなくなり、最終的にはPECLでインストールするようにしました。
よく見かけた情報は、こちらについてのものですね。
xhprof
xhprofは、PHPのプロファイラーです。
PECLではこちら。
プロファイリングの機能と、Web UIが含まれており、プロファイル結果を確認することができます。
最新バージョンは2.3.5で、現在メンテナンスされているリポジトリはこちらになります。
今回は、こちらを使っていきましょう。
環境
今回は、Amazon Linux 2を使います。
$ cat /etc/os-release
NAME="Amazon Linux"
VERSION="2"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/"
$ uname -srvmpio
Linux 4.14.252-195.483.amzn2.x86_64 #1 SMP Mon Nov 1 20:58:46 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
PHP 7.4は、amazon-linux-extras
でインストールしているものとします。
$ sudo amazon-linux-extras install php7.4
バージョン。
$ php --version
PHP 7.4.21 (cli) (built: Jul 7 2021 17:35:08) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
Apacheは、こちらとします。
$ httpd -V
Server version: Apache/2.4.51 ()
Server built: Oct 8 2021 22:03:47
Server's Module Magic Number: 20120211:118
Server loaded: APR 1.7.0, APR-UTIL 1.6.1
Compiled using: APR 1.7.0, APR-UTIL 1.6.1
Architecture: 64-bit
Server MPM: prefork
threaded: no
forked: yes (variable process count)
Server compiled with....
-D APR_HAS_SENDFILE
-D APR_HAS_MMAP
-D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
-D APR_USE_PROC_PTHREAD_SERIALIZE
-D APR_USE_PTHREAD_SERIALIZE
-D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
-D APR_HAS_OTHER_CHILD
-D AP_HAVE_RELIABLE_PIPED_LOGS
-D DYNAMIC_MODULE_LIMIT=256
-D HTTPD_ROOT="/etc/httpd"
-D SUEXEC_BIN="/usr/sbin/suexec"
-D DEFAULT_PIDLOG="/run/httpd/httpd.pid"
-D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
-D DEFAULT_ERRORLOG="logs/error_log"
-D AP_TYPES_CONFIG_FILE="conf/mime.types"
-D SERVER_CONFIG_FILE="conf/httpd.conf"
xhprofをインストールする
xhprofの要件に関するページはこちらですが、特に前提条件はなさそうです。
UIに関しては以下にforkがあると書かれていますが、
現在のリポジトリにも含まれています…。
今回は、longxinH/xhprof
に含まれている方を使うことにしました。
PECLとPHP開発パッケージ、Graphvizのインストール
まずは、必要なパッケージをインストールします。PECLが必要なのですが、Amazon Linux 2ではxhprofをコンパイルインストールすることになるようなのでphp-devel
もインストールします。
※Remiでは、xhprof自体をyum
でインストールできるみたいです
$ sudo yum install php-pear php-devel
バージョン。
$ pear version
PEAR Version: 1.10.12
PHP Version: 7.4.21
Zend Engine Version: 3.4.0
Running on: Linux localhost 4.14.252-195.483.amzn2.x86_64 #1 SMP Mon Nov 1 20:58:46 UTC 2021 x86_64
$ php-config --version
7.4.21
また、UIで表示する際に可視化ができるようになるのでGraphvizも入れておきます。
$ sudo yum install graphviz
バージョン。
$ dot -V
dot - graphviz version 2.30.1 (20180828.1746)
xhprofのインストール
続いて、xhprofのインストール。
$ sudo pecl install xhprof
コンパイルが終了し、「php_ini
にextension
を追記しなさい」と言われます。
Build process completed successfully
Installing '/usr/lib64/php/modules/xhprof.so'
install ok: channel://pecl.php.net/xhprof-2.3.5
configuration option "php_ini" is not set to php.ini location
You should add "extension=xhprof.so" to php.ini
今回、xhprofの2.3.5がインストールされたみたいです。
xhprofをextensionに追加する
xhprofをPHPに組み込みます。
今回の環境では/etc/php.d
ディレクトリ配下に設定ファイルを置くと良さそうなので/etc/php.d/90-xhprof.ini
というファイルを作成することにします。
内容は、こんな感じで。
extension=xhprof.so
xhprof.output_dir=/tmp
xhprof.output_dir
は、xhprofのプロファイリング結果を出力するディレクトリです。
今回は/tmp
としました。
※今回の環境では注意点があるので、最後に補足します
xhprofを反映するため、PHP-FPMを起動している場合は再起動します(mod_phpの場合はApache)。
$ sudo systemctl restart php-fpm
こんなファイルを作成して
<?php
phpinfo();
ブラウザでアクセスしてみて確認します。
xhprofを認識していますね。
XhprofのUIをインストールする
PECLでインストールするパッケージそのものは、/tmp/pear/download
に.tar.gz
が置かれているのでこちらを使うことにします。
※/tmp
配下なのでそのうち消えると思いますが、その場合はリポジトリから取得で…
$ ll /tmp/pear/download
合計 828
-rw-r--r-- 1 root root 648 12月 7 04:00 channel.xml
-rw-r--r-- 1 root root 842658 12月 7 04:00 xhprof-2.3.5.tgz
この中に、xhprof_html
およびxhprof_lib
というディレクトリが含まれていますが
$ tar tvf /tmp/pear/download/xhprof-2.3.5.tgz | grep -E 'xhprof_(html|lib)'
-rw-r--r-- longxinhui/staff 1610 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/css/xhprof.css
-rw-r--r-- longxinhui/staff 25313 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/docs/index.html
-rw-r--r-- longxinhui/staff 110076 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/docs/sample-callgraph-image.jpg
-rw-r--r-- longxinhui/staff 231801 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/docs/sample-diff-report-flat-view.jpg
-rw-r--r-- longxinhui/staff 184704 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/docs/sample-diff-report-parent-child-view.jpg
-rw-r--r-- longxinhui/staff 214289 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/docs/sample-flat-view.jpg
-rw-r--r-- longxinhui/staff 104056 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/docs/sample-parent-child-view.jpg
-rw-r--r-- longxinhui/staff 1435 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/jquery/indicator.gif
-rw-r--r-- longxinhui/staff 100171 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/jquery/jquery-1.2.6.js
-rw-r--r-- longxinhui/staff 1102 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/jquery/jquery.autocomplete.css
-rw-r--r-- longxinhui/staff 19824 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/jquery/jquery.autocomplete.js
-rw-r--r-- longxinhui/staff 533 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/jquery/jquery.tooltip.css
-rw-r--r-- longxinhui/staff 8086 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/jquery/jquery.tooltip.js
-rw-r--r-- longxinhui/staff 5713 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/js/xhprof_report.js
-rw-r--r-- longxinhui/staff 3172 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/callgraph.php
-rw-r--r-- longxinhui/staff 2814 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/index.php
-rw-r--r-- longxinhui/staff 1085 2021-09-05 05:31 xhprof-2.3.5/xhprof_html/typeahead.php
-rw-r--r-- longxinhui/staff 2518 2021-09-05 05:31 xhprof-2.3.5/xhprof_lib/display/typeahead_common.php
-rw-r--r-- longxinhui/staff 44826 2021-09-05 05:31 xhprof-2.3.5/xhprof_lib/display/xhprof.php
-rw-r--r-- longxinhui/staff 17105 2021-09-05 05:31 xhprof-2.3.5/xhprof_lib/utils/callgraph_utils.php
-rw-r--r-- longxinhui/staff 26748 2021-09-05 05:31 xhprof-2.3.5/xhprof_lib/utils/xhprof_lib.php
-rw-r--r-- longxinhui/staff 4856 2021-09-05 05:31 xhprof-2.3.5/xhprof_lib/utils/xhprof_runs.php
これを取り出して、DocumentRoot(デフォルトでは/var/www/html
)に配置します。
$ cd /var/www/html
$ sudo tar zxvf /tmp/pear/download/xhprof-2.3.5.tgz xhprof-2.3.5/xhprof_html xhprof-2.3.5/xhprof_lib
$ sudo mv xhprof-2.3.5/xhprof* ./.
$ sudo rmdir xhprof-2.3.5
この配置だと、UIにアクセスする時はhttp://[ホスト名]/xhprof_html
というURLになります。
※xhprof_lib
は直接参照しません
xhprofを使う
では、xhprofを使ってみましょう。
使用する関数は、こちらにリファレンスがありますが
サンプルを見るのがよい気がします。
プロファイル対象は、先ほどのphpinfo
のコードを変更しましょう。
<?php
require_once '/var/www/html/xhprof_lib/utils/xhprof_lib.php';
require_once '/var/www/html/xhprof_lib/utils/xhprof_runs.php';
xhprof_enable(); // プロファイル開始
// プロファイル対象のコードを実行
phpinfo();
$xhprof_data = xhprof_disable(); // プロファイル終了
// 結果保存
$xhprof_runs = new XHProfRuns_Default();
$xhprof_runs->save_run($xhprof_data, "app");
この状態で、ブラウザからphpinfo.php
にアクセスすると、プロファイル結果がxhprof.output_dir
で指定したディレクトリに保存されます。
インストールしたUIのページ(http://[ホスト名]/xhprof_html
)にアクセスすると、保存されたプロファイル結果を確認できます。
この数は、保存した分だけ増えていきます。
ファイルのリンクを選択すると、詳細が表示されます。
処理のツリーもたどれますし
Graphvizをインストールしているとコールグラフも見ることができます。
使いかたは、こんな感じですね。
というわけで、準備ができたのでLet's Profiling!!
補足: systemd環境下で /tmp
を選んだ場合の注意
今回の環境は、systemdでPHP-FPMを管理しています。この環境下でxhprof.output_dir
に/tmp
配下の値を指定した場合、systemdが管理しているtmp
ディレクトリ配下に割り当てられます。
※/tmp
と指定した時点で対象になります
こんな感じのディレクトリになります。
/tmp/systemd-private-xxxxx-php-fpm.service-xxxxx/tmp
PHP-FPMのsystemdの設定である、PrivateTmp
が効きます。
...
[Unit]
...
[Service]
...
PrivateTmp=true
注意点としてはディレクトリのパスもそうですが、PHP-FPMを再起動するとディレクトリの中身がクリアされることですね。