php调试利器Xhprof的安装与使用

一、安装xhprof

1
2
3
4
5
6
7
8
9
wget http://pecl.php.net/get/xhprof-0.9.4.tgz
tar -zxvf xhprof-0.9.4.tgz
cd xhprof-0.9.4/extension/
phpize
./configure && make && make install
 
or
 
pecl install xhprof-beta

 二、配置PHP.ini

1
2
3
4
5
6
7
8
[xhprof]
extension=xhprof.so;
; directory used by default implementation of the iXHProfRuns
; interface (namely, the XHProfRuns_Default class) for storing
; XHProf runs.
;
;xhprof.output_dir=<directory_for_storing_xhprof_runs>
xhprof.output_dir=/tmp/xhprof

三、测试

1
2
3
server php-fpm restart
yum install -y graphviz
cp examples xhprof_html xhprof_lib  /data/www/xhprof/ -R

如果查看[View Full Callgraph]的时候,却提示如下:Error: either we can not find profile data for run_id 4d7f0bd99a12f or the threshold 0.01 is too small or you do not have ‘dot’ image generation utility installed

1、可能是PNG类库没有安装好,下载地址http://sourceforge.net/projects/libpng/files/

2、可能是PHP安全配置,比如开启了安全模式,执行系统的命令的函数给禁用了

测试代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
 
function bar($x) {
  if ($x > 0) {
    bar($x - 1);
  }
}
 
function foo() {
  for ($idx = 0; $idx < 5; $idx++) {
    bar($idx);
    $x = strlen("abc");
  }
}
 
// start profiling
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
 
// run program
foo();
 
// stop profiler
$xhprof_data = xhprof_disable();
 
// display raw xhprof data for the profiler run
print_r($xhprof_data);
 
 
$XHPROF_ROOT = realpath(dirname(__FILE__) .'/..');
include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php";
include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php";
 
// save raw data for this profiler run using default
// implementation of iXHProfRuns.
$xhprof_runs = new XHProfRuns_Default();
 
// save the run under a namespace "xhprof_foo"
$run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_foo");
 
echo "---------------\n".
     "Assuming you have set up the http based UI for \n".
     "XHProf at some address, you can view run at \n".
     "http://<xhprof-ui-address>/index.php?run=$run_id&source=xhprof_foo\n".
     "---------------\n";

运行结果

参数说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Inclusive Time (or Subtree Time): Includes time spent in the function as well as in descendant functions called from a given function.
Exclusive Time/Self Time: Measures time spent in the function itself. Does not include time in descendant functions.
Wall Time: a.k.a. Elapsed time or wall clock time.
CPU Time: CPU time in user space + CPU time in kernel space
 
 
主要指标:
Inclusive Time (或子树时间):包括子函数所有执行时间。
Exclusive Time/Self Time:函数执行本身花费的时间,不包括子树执行时间。
Wall时间:花去了的时间或挂钟时间。
CPU时间:用户耗的时间+内核耗的时间
 
# 如果xhprof_enable函数写作:xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY)可以输出更多指标。
Function Name 函数名
Calls 调用次数
Calls% 调用百分比
 
# 消耗时间
Incl. Wall Time (microsec) 调用的包括子函数所有花费时间 以微秒算(一百万分之一秒)
IWall% 调用的包括子函数所有花费时间的百分比
Excl. Wall Time (microsec) 函数执行本身花费的时间,不包括子树执行时间,以微秒算(一百万分之一秒)
EWall% 函数执行本身花费的时间的百分比,不包括子树执行时间
 
# 消耗CPU
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整合到任何我们已有的项目中去了,目前大部分MVC框架都有唯一的入口文件,只需要在入口文件的开始处注入xhprof的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
//启动xhprof
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
 
register_shutdown_function(function() {
    $xhprof_data        = xhprof_disable();
 
    //让数据收集程序在后台运行
    if (function_exists('fastcgi_finish_request')) {
        fastcgi_finish_request();
    }
 
    $XHPROF_ROOT = realpath(dirname(__FILE__) );
    include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php";
    include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php";
 
    //保存统计数据,生成统计ID和source名称
    $xhprof_runs = new XHProfRuns_Default();
    $run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_foo"); //source名称是xhprof_foo
 
    file_put_contents("/data/www/x.test.com/2.txt","http://x.test.com:8081/xhprof/xhprof_html/index.php?run=" . $run_id . "&source=xhprof_foo\n",FILE_APPEND);
 
});

但是这样免不了要修改项目的源代码,其实php本身就提供了更好的注入方式,比如将上述逻辑保存为/opt/inject.php,然后修改php fpm配置文件

1
2
//修改auto_prepend_file配置
auto_prepend_file = /opt/inject.php

或者修改php-fpm配置

1
php_admin_value[auto_prepend_file] = /opt/inject.php

或者修改nginx配置

1
fastcgi_param PHP_VALUE "auto_prepend_file=/opt/inject.php";

更好的分析工具

xhprof.io还是xhpgui,注入代码后我们还需要实现保存xhprof数据以及展示数据的UI,听起来似乎又是一大堆工作,有现成的轮子可以用吗?经过搜索和比较,貌似比较好的选择有xhprof.io以及xhpgui

xhprof.io配置

1
2
3
4
git clone https://github.com/gajus/xhprof.io
cd xhprof.io/
composer install
cp xhprof/includes/config.inc.sample.php xhprof/includes/config.inc.php

修改xhprof/includes/config.inc.php

1
2
3
4
5
6
//在MySQL中建立xhprof.io数据库,假设数据库名为xhprof,然后导入xhprof/setup/database.sql
//配置文件config.inc.php中需要调整
 
'url_base' => 'http://x.test.com:8081/xhprof.io/', 这是xhprof.io界面所在路径
'pdo' => new PDO('mysql:dbname=xhprof;host=localhost;charset=utf8', 'root', 'password'), 根据MySQL实际情况调整配置
//enable 这是一个匿名函数,当匿名函数返回true时启用xhprof数据收集

测试地址:https://dev.anuary.com/8d50658e-f8e0-5832-9e82-6b9e8aa940ac/?xhprof[template]=request&xhprof[query][request_id]=108151

 五、框架测试

1、ThinkPHP原生框架

调用关系图

2、加载程序的TP框架

调用关系图

3、CI原生框架

调用关系图

4、YII原生框架

调用关系图

具体哪个函数很慢,都是可以看的很清楚

参考文章

http://pecl.php.net/package/xhprof
http://mirror.facebook.net/facebook/xhprof/doc.html
https://github.com/facebook/xhprof


 
分类: PHP
标签: php, xhprof
0
0
 
 
 
« 上一篇: 深入了解PHP闭包的使用以及实现
» 下一篇: 单向链表的逆序操作
posted @ 2022-06-29 10:19  快乐的在一起  阅读(277)  评论(0编辑  收藏  举报