Total Pageviews

Sunday, 19 February 2012

facebook开源出来的php代码的debug工具-xhprof 的安装和使用

xhprof是facebook开源出来的php代码的debug工具,很容易看到php 代码效率的瓶颈在哪里。在ubuntu 10.04 上的安装脚本:
sudo apt-get install php-pear php5-dev
mkdir -p /opt/src/
cd /opt/src/
wget http://pecl.php.net/get/xhprof-0.9.2.tgz
tar -xvf xhprof-0.9.2.tgz

cd xhprof-0.9.2/extension
phpize
./configure
su
make && make install
make test

编辑php.ini (/etc/php5/apache/php.ini) 加入xhprof扩展配置:
[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=/opt/xhprof
然后重启apache,就可以生效了。
配置里面是可以指定xhprof输出目录,但是我还没有用到它自带的输出信息。因为我的目的只是找到慢语句。xhprof默认是不对profile结果按时间排序的,我们自己排:
15 xhprof_enable(0,
 16             array('ignored_functions' =>  array('call_user_func',
 17                                                 'call_user_func_array')));
     ... (需要做profile的代码段)
 38 $xhprof_data = xhprof_disable();
 39 uasort($xhprof_data, create_function('$a,$b',
 40             'return $a["wt"]<$b["wt"];'));
 41 file_put_contents("/tmp/bbs.goapk.com.xhprof.info", var_export($xhprof_data, true));
执行结束之后再看看输出文件。找到问题出在哪,后面就好办了。
--------------------------------------------------------------------
Debugging PHP with xhprof

调试自己不熟悉的代码比较费力。如果代码是自己写的,发现问题后,看错误提示,看程序写的日志文件,看php_error.log,基本都能找到问题。discuz 代码结构挺复杂,功能繁杂到变态,我也懒得学,一般有问题直接调。
我一般用 xhprof调试dz. 本来 xhprof 项目本意做php 的 profiler, 大概就是根据统计函数执行时间(准确而言是函数a调用函数b的次数以及总时间),找出项目的性能瓶颈。但是面对一套自己不熟悉的代码,要找个问题,我也只 能用 xhprof(呃,其它工具比如 xdebug 我也没用过)。调试的关键在于,你要找到程序出错的位置。发现有人在stackoverflow 上问了一个很蛋疼的问题:怎么最快地判断PHP脚本退出的位置(http://stackoverflow.com/questions/216963/fastest-way-to-determine-where-php-script-exits)。 因为最近论坛从dz7.2 升级到x1.5,之前给外部产品用的用户注册、登录api失效了。重新改的时候,出现因为缺少宏定义造成 access deny,然后直接退出… 然后我也很想知道程序究竟在哪个地方 access deny… 然后用关键词 “register_shutdown_function debug_backtrace” google到了这个问题:想法很简单,希望在退出之前看一看函数调用栈。但是看了帖子讨论就知道,一步到位方法目前并不存在,因为 register_shutdown_function 所定义的回调函数,在被调用时,函数栈已经清空了,而且也没有替代的方式可以在清站之前做些回调之类的。
看看下面这段代码:
 46 if (function_exists(“xhprof_enable”)) {
 47     xhprof_enable(0,
 48             array(‘ignored_functions’ =>  array(‘call_user_func’,
 49                     ‘call_user_func_array’)));
 50     function xhprof_write_tmp_file($name=”") {
 51         $xhprof_data = xhprof_disable();
 52 #uasort($xhprof_data, create_function(‘$a,$b’, ‘return $a["wt"]<$b["wt"];’));
 53         file_put_contents(“/tmp/x15.goapk.com.$name”, var_export($xhprof_data, true));
 54     }
 55     register_shutdown_function(“xhprof_write_tmp_file”, “exit”);
 56 }
  … (需要做profile的代码段)
 2012 xhprof_write_tmp_file(“end”);
跟上篇文章贴的代码段不同之处在于,这里注册了脚本退出时的回调函数。如果程序是正常执行完,会在/tmp 目录下生成 .end 文件;如果中间退出,则是 .exit。用这套代码,最开始的目的是查找一个在论坛的注册时,CGI超时的问题。因为是超时,脚本不能正常退出,xhprof_disable 写在代码尾部也打不出log,所以想到用这种方式。这种方式的确很高效,很容易追踪的超时的函数 (后来找到原因是 dz 给新注册用户发送通知邮件时超时导致的)。如果是出错调试,也可以用这种方式跟踪代码,看走到什么地方,没有按照预期继续往下走,然后在出问题的位置输出 调试信息。相对而言,这种方式比自己瞎猜要快得多。回到上面“怎么最快地判断PHP脚本退出的位置”的问题,我认为这种方式是一个不错的方案;而另外一些 时候,程序出错也会走不同的程序分支,可以在xhprof 数据中体现出来。总而言之,我们可以根据 xhprof生成的函数调用信息,判断出代码执行过程(如果有类似shell 里面的 sh -x 执行方式就更好了- -,但是如果有循环,这种方式也会产生大量输出,同样需要花些时间分析日志),从而定位问题。所以,我认为 xhprof 是个挺高效的php 调试工具。
上次为了修复注册、登录 api 搭上了几乎一整天时间。最后连蒙带猜搞定了,泪流满面… 我实在是不想看uccenter 的bullshit api… 如果这玩意当初就是用uccenter 的 api 写的,倒也不用改代码了,上uccenter 改个设置就行。
 from http://liruqi.wordpress.com/2011/01/01/debug-php-with-xhprof/
-----------------------------------------------------------------------------------
 xhprof——给你的PHP程序做个Profiler

xhprof是Fackbook开源的一个PHP代码“跟踪”程序,可以生成php程序的“函数”调用关系图,以及各个“函数”调用的次数及花费的时间。
当下,xhprof已经入住PHP的PECL库,可以能过pecl install xhprof安装(可能会提示你需要使用带版本号的名字,比如pecl install xhprof-0.9.2)。
也可以下载源代码编译安装(其实与使得pecl安装效果是一样的)。
当使用php 5.4时,安装xhprof可能会遇到麻烦,详情见这个bug公告:https://bugs.php.net/bug.php?id=61674,为xhprof-0.9.2打上补丁即可编译通过:https://github.com/facebook/xhprof/commit/a6bae51236.diff
下面说xhprof怎么使用。
配置xhprof:
在原php的配置文件加入
[xhprof]
extension=xhprof.so
xhprof.output_dir=’/var/tmp’
/var/tmp目录需要apache运行账号可写。
安装绘图工具graphviz,这个是xhprof调用用来绘图的。
RHEL6上可以使用yum直接安装:yum install graphviz。或者自己编译安装。
为xhprof配置个专用的web访问路径:
比如在/etc/http/conf.d/下建一个xhprof.conf配置文件,内容如下:
Alias /xhprof/ /usr/share/pear/xhprof_html/
<Directory /usr/share/pear/xhprof_html/>
Options -indexes
Order allow,deny
Allow from all
</Directory>
使用xhprof:
// 放在程序开始第一行
xhprof_enable();
// 原程序开始
// 原程序结束
// 放在结尾
$xhprof_data = xhprof_disable();
$XHPROF_ROOT = ‘/usr/share/pear/’;
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();
$run_id = $xhprof_runs->save_run($xhprof_data, “xhprof_foo”);



参考:
http://hi.baidu.com/thinkinginlamp/blog/item/f4bd08fa1a03ba9e59ee90fd.html
https://bugs.php.net/bug.php?id=61674