xhprof安装使用
安装:
到pecl官网下载xhprof的最新版:http://pecl.php.net/package/xhprof
wget http://pecl.php.net/get/xhprof-0.9.4.tgz tar zxvf xhprof-0.9.4.tgz cd xhprof-0.9.4 #拷贝这两个目录到一个可访问的host下
cp -r xhprof_html xhprof_lib /var/www/xhprof
cd extension which php-config #记录下php-config的路径,接下来要用。 phpize ./configure --with-php-config=/usr/bin/php-config #此处的地址就是上面你记录下来php-config的地址 make make install
修改php.ini
[xhprof] extension=xhprof.so ; ;xhprof生成的文件存放路径。 ;记得目录有可写权限,否则文件无法生成,xhprof也不报错,这个问题我犯了错误了。 ;另外,这个目录不是要配置host访问的目录,host的目录还是xhprof_html,往下看就明白了 ;xhprof.output_dir=<directory_for_storing_xhprof_runs>
;
xhprof.output_dir=/tmp
重启php-fpm就OK了,不过为了显示效果更炫,最好继续安装Graphviz。
安装Graphviz的目的是为了xhprof图形化web工具查看profiling log文件。
wget http://www.graphviz.org/pub/graphviz/stable/SOURCES/graphviz-2.24.0.tar.gz
tar zxf graphviz-2.24.0.tar.gz
cd graphviz-2.24.0
./configure
make
make install
使用:
// start profiling
xhprof_enable();
// run program
// stop profiler
$xhprof_data = xhprof_disable();
// Saving the XHProf run
// using the default implementation of iXHProfRuns.
//
$XHPROF_ROOT = "/var/www/xhprof";//需要include下边的两个文件,路径就是上边cp时写的路径
include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php";
include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php";
$xhprof_runs = new XHProfRuns_Default();
// 保存运行结果在xhprof_foo下,类似命名空间
// **NOTE**:
//save_run返回一个唯一的run_id,也可以通过参数自己指定id.
$run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_foo");
//输出连接到页面,点击页面中的连接访问
echo "http://<xhprof-ui-address>/xhprof_html/index.php?run=$run_id&source=xhprof_foo\n".
如此一来,会在上面设定的xhprof.output_dir目录里生成名字类似49bafaa3a3f66.xhprof_foo的数据文件。
可以很方便的通过Web方式浏览效果:
http://www.v.com/xhprof_html/index.php?run=49bafaa3a3f66&source=xhprof_foo
分析:
$xhprof_data
中记录了程序单步运行过程中所有的函数调用时间及CPU内存消耗等,具体记录哪些指标可以通过xhprof_enable
的入口参数控制,之后的处理已经与xhprof扩展无关,大致是编写了一个存储类XHProfRuns_Default
,将$xhprof_data
序列化并保存到某个目录,可以通过XHProfRuns_Default(__DIR__)
将结果输出到当前目录,如果不指定则会读取php.ini配置文件中的xhprof.output_dir
,仍然没有指定则会输出到/tmp
。
xhprof_html/index.php
将记录的结果整理并可视化,默认的UI里列出了:
主要的:
Inclusive Time (或子树时间):包括子函数所有执行时间。
Exclusive Time/Self Time:函数执行本身花费的时间,不包括子树执行时间。
Wall时间:花去了的时间或挂钟时间。
CPU时间:用户耗的时间+内核耗的时间。
表格中的:
Function Name 函数名
Calls 调用次数
Calls% 调用百分比
Incl. Wall Time (microsec) 调用的包括子函数所有花费时间 以微秒算(一百万分之一秒)
IWall% 调用的包括子函数所有花费时间的百分比
Excl. Wall Time (microsec) 函数执行本身花费的时间,不包括子树执行时间,以微秒算(一百万分之一秒)
EWall% 函数执行本身花费的时间的百分比,不包括子树执行时间
Incl. CPU(microsecs) 调用的包括子函数所有花费的cpu时间。减Incl. Wall Time即为等待cpu的时间
ICpu% Incl. CPU(microsecs)的百分比
Excl. CPU(microsec) 函数执行本身花费的cpu时间,不包括子树执行时间,以微秒算(一百万分之一秒)。
ECPU% Excl. CPU(microsec)的百分比
Incl.MemUse(bytes) 包括子函数执行使用的内存。
IMemUse% Incl.MemUse(bytes)的百分比
Excl.MemUse(bytes) 函数执行本身内存,以字节算
EMemUse% Excl.MemUse(bytes)的百分比
Incl.PeakMemUse(bytes) Incl.MemUse的峰值
IPeakMemUse% Incl.PeakMemUse(bytes) 的峰值百分比
Excl.PeakMemUse(bytes) Excl.MemUse的峰值
EPeakMemUse% EMemUse% 峰值百分比
在xhprof_html/index.php
中还可以看到[View Full Callgraph]
链接,点击后可以绘制出一张可视化的性能分析图,如果点击后报错的话,可能是缺少依赖graphviz
。
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
同时在分析时去掉内置函数:
xhprof_enable(XHPROF_FLAGS_NO_BUILTINS | XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY);
忽略指定的函数( 0.9.2或更高版本支持):
xhprof_enable(
0,
array('ignored_functions' => array('call_user_func',
'call_user_func_array')));
同时记录内存:
xhprof_enable( XHPROF_FLAGS_MEMORY, array('ignored_functions' =>array(
'call_user_func', 'call_user_func_array')
));
查看不同的XHProf用户界面:
PHP源码目录结构XHProf的用户界面的由PHP实现。代码存放在两个子目录中: xhprof_html/和xhprof_lib/ 。xhprof_html目录包含了3个顶级PHP页面。
index.php :查看一个单一运行或差异报告。
callgraph.php :以图片的形式查看一次XHProf运行的调用关系图。
typeahead.php :在XHProf的报告中被后台调用来进行函数的自动补全。
查看diff报告:
要查看命名空间<namespace>下runid分别是< run_id1>和<run_id2>的两个报告,访问URL:
http://<xhprof-ui-address>/index.php?run1=<run_id1>&run2=<run_id2>&source=<namespace>
汇总报告:
您也可以指定一组run id来汇总得到您想要的报告视图。
如果你有三个XHProf运行,都在"benchmark‘命名空间下,run id分别是1,2,3。要查看这些运行的汇总报告:
http://<xhprof-ui-address>/index.php?run=1,2,3&source=benchmark
加权汇总 :
进一步假设,上述3个运特分别对应三种程序,p1.php,p2.php和p3.php ,通常以20%,30%,50%概率混合:要查看汇总报告所对应的加权平均数这些运行使用:
http://<xhprof-ui-address>/index.php?run=1,2,3&wts=20,30,50&source=benchmark
取样分析(自己实现和xhprof实现):
不想每个请求都进行分析,自己通过随机数方式取样。
$randKey = mt_rand(1, 10000);
if ($randKey == 1)
{
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
}
// Test Code Start
……
// Test Code End
if ($randKey == 1)
{
$xhprofData = xhprof_disable();
include_once "/data/zivn.me/xhprof_lib/utils/xhprof_lib.php";
include_once "/data/zivn.me/xhprof_lib/utils/xhprof_runs.php";
$xhprofRuns = new XHProfRuns_Default();
$xhprofRuns->save_run($xhprofData, "xhprof");
}
Xhprof扩展还提供了一个轻量级采样模式 。采样间隔为0.1秒。采样记录了整个函数调用堆栈。如果想以增加极低的负载作代价来进行性能监控和诊断,采样模式就是你想要的。用xhprof_sample_enable()和xhprof_sample_disable()代替xhprof_enable()和xhprof_disable() 即可。
更好的注入方式:
理解了上边的配置和使用后,其实就已经可以将xhprof整合到任何我们已有的项目中去了。目前大部分MVC框架都有唯一的入口文件,只需要在入口文件的开始处注入xhprof的逻辑:
//开启xhprof
xhprof_enable(XHPROF_FLAGS_MEMORY | XHPROF_FLAGS_CPU);
//在程序结束后收集数据
register_shutdown_function(function() {
$xhprof_data = xhprof_disable();
//让数据收集程序在后台运行
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
}
//保存xhprof数据
...
});
但是这样免不了要修改项目的源代码,其实php本身就提供了更好的注入方式,比如将上述逻辑保存为/opt/inject.php
,然后修改php fpm配置文件
vi /etc/php5/fpm/php.ini
修改auto_prepend_file
配置:
auto_prepend_file = /opt/inject.php
这样所有的php-fpm请求的php文件前都会自动注入/opt/inject.php
文件
如果使用Nginx的话,还可以通过Nginx的配置文件设置,这样侵入性更小,并且可以实现基于站点的注入。
fastcgi_param PHP_VALUE "auto_prepend_file=/opt/inject.php";
更好的分析工具:xhprof.io还是xhpgui:
注入代码后我们还需要实现保存xhprof数据以及展示数据的UI,听起来似乎又是一大堆工作,有现成的轮子可以用吗?
查看这个博客的介绍:http://avnpc.com/pages/profiler-php-performance-online-by-xhprof