分类目录归档:php

PHP性能分析之xhprof

xdebug讲到了使用xdebug对php程序进行性能分析,这里再介绍另外一个工具:xhprof,facebook出品。xhprof是一个函数级别的分层性能报告工具,包括调用次数,阻塞时间,CPU时间和内存使用情况。
首先,下载并安装xhprof扩展

tar -zxvf xhprof-0.9.4.tgz 
cd xhprof-0.9.4
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make
make install
#拷贝扩展
cp /usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/xhprof.so /usr/local/php/lib/php/extensions/

mkdir -p /tmp/xhprof
chmod 755 /tmp/xhprof
chown www:www /tmp/xhprof

xhprof自带的界面工具比较简单,这里推荐使用另外一个UI:XHProf.io。下载解压到web目录下面,重命名/xhprof/includes/目录下的config.inc.sample.php为/xhprof/includes/config.inc.php,并更改文件:

return array(
	'url_base' => 'http://192.168.84.2:8502/', //本地的XHProf.io站点
	'url_static' => null, // When undefined, it defaults to $config['url_base'] . 'public/'. This should be absolute URL.
	'pdo' => new PDO('mysql:dbname=test;host=192.168.84.3;charset=utf8', 'root', 'root') //本地的数据库配置,只支持PDO
);

在test数据库上运行/xhprof/setup/database.sql,创建性能检测相关的表结构。
由于XHProf会去github上检测版本,国内访问较慢,建议不要检测。更改/xhprof/includes/bootstrap.inc.php如下:

	curl_setopt_array($ch, array(
		CURLOPT_URL => 'http://192.168.84.2:8502/version.json', //本地的XHProf.io站点下面
		CURLOPT_HEADER => FALSE,
		CURLOPT_RETURNTRANSFER => TRUE
	));

然后更改php.ini配置,在最后加上以下内容:

;xhprof
[xhprof]
extension=xhprof.so;
xhprof.output_dir=/tmp/xhprof

; Automatically add files before PHP document.
; XHProf.io站点下的prepend.php
auto_prepend_file = /usr/local/nginx/xhprof/inc/prepend.php

; Automatically add files after PHP document.
; XHProf.io站点下的append.php
auto_append_file = /usr/local/nginx/xhprof/inc/append.php

auto_prepend_file为每次php脚本运行前,自动加载并运行的文件;auto_append_file为每次php脚本运行后,自动加载并运行的文件。这样可以省去每次在需要检测的php文件里面写xhprof_enable/xhprof_disable等调用代码,不必更改原有代码(无侵入)。
注意:如果你访问了php页面却收集不到情况,可能是你的代码里面写了exit/die终止了程序执行,导致auto_append_file未加载执行,去掉exit/die就可以了。另外,如果提示:Unexpected system behaviour,可能是数据库连接不上,PDO、mbstring扩展未安装,响应数据里面带有错误信息的等等。

重启php-fpm:

#重启php-fpm
kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`

xhprof1

访问该服务器上php页面,即可以在http://192.168.84.2:8502/看到检测情况。
xhprof5
xhprof4
xhprof6

参数说明
Inclusive Time 包括子函数所有执行时间。
Exclusive Time/Self Time 函数执行本身花费的时间,不包括子树执行时间。
Wall Time 花去了的时间或挂钟时间。
CPU Time 用户耗的时间+内核耗的时间
Inclusive CPU 包括子函数一起所占用的CPU
Exclusive CPU 函数自身所占用的CPU

参考链接:
给CentOS6.3 + PHP5.3 安装PHP性能测试工具 XHProf-0.9.2
xhprof.io/INSTALL.md
php auto_append_file

PHP性能分析之Xdebug

最近一个PHP程序性能跑的不行,于是又想起来Xdebug这个扩展,并记录一下。
首先去Xdebug官网下载源码包,注意下载对应版本的源码包,我的环境是PHP 5.4.9,安装了最新的Xdebug 2.3.2后,不能使用WinCacheGrindWebGrind进行分析,又重新下载了旧的Xdebug 2.2.0。
然后在Centos下面编译安装

tar -zxvf xdebug-2.2.0.tgz
cd xdebug-2.2.0
/usr/local/php/bin/phpize
./configure --enable-xdebug --with-php-config=/usr/local/php/bin/php-config
make
make install

编译安装完成后是这样子的
xdebug
将xdebug扩展复制到php的扩展目录下,并创建/tmp/xdebug文件。

cp /usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so /usr/local/php/lib/php/extensions/
mkdir -p /tmp/xdebug
chmod 755 /tmp/xdebug
chown www:www /tmp/xdebug

并更改php.ini如下

; XDEBUG Extension

zend_extension = "/usr/local/php/lib/php/extensions/xdebug.so"
[xdebug]
xdebug.profiler_enable = on
xdebug.trace_output_dir="/tmp/xdebug"  
xdebug.profiler_output_dir="/tmp/xdebug" 
xdebug.profiler_output_name = cachegrind.out.%t.%p

然后需要重启php-fpm,使配置生效。

这个环境下并没有php-fpm的pid文件,每次重启需要查找进程pid,于是先生成下。

#查找进程id
ps aux | grep php-fpm  
#结束进程
kill 6369

编辑/usr/local/php/etc/php-fpm.conf如下,去掉注释

[global]
; Pid file
; Note: the default prefix is /usr/local/php/var
; Default Value: none
pid = run/php-fpm.pid

然后启动php-fpm

#启动php-fpm
/usr/local/php/sbin/php-fpm -c /usr/local/php/lib/php.ini -y /usr/local/php/etc/php-fpm.conf

以后就可以方便的重启php-fpm了。

 
#关闭php-fpm
kill -INT `cat /usr/local/php/var/run/php-fpm.pid`
 
#重启php-fpm
kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`

重启完成后,查看phpinfo,Xdebug是否加载成功。
xdebug2
运行php程序就会在/tmp/xdebug目录下,生成对应的profile文件(cachegrind.out.%t.%p),这里可以使用WinCacheGrindWebGrind进行分析。
Windows下面使用WinCacheGrind进行分析,可以查看PHP执行流程,函数调用次数、耗时。双击列表可以进入详细调用情况。
xdebug3
xdebug6
WebGrind程序部署在安装Xdebug的服务器上即可,会显示已经生成的profile文件,下拉选择进行分析。也可以查看PHP执行流程,函数调用次数、耗时。点击小三角会展开调用栈,后面跟着源码位置,可直接定位查看代码。
xdebug4

参考链接:
前端开发中的性能那点事(一)巧用xdebug
利用Xdebug分析PHP程序,找出性能瓶颈[原创]
php-fpm – 启动参数及重要配置详解

PHP unserialize出错

最近碰到一个问题,在使用PHP的unserialize函数反序列化服务端传递过来的参数时报错了:unserialize() [function.unserialize]: Error at offset 180 of 181 bytes。最后在Stackoverflow上找到了一个非常好的答案:这是由于序列化时字符串长度算错了导致的。作者还写了个校正长度的正则表达式,提供了一个用于计算序列化是否出错了的函数。导致序列化出错的原因通常是因为内容使用了双引号(”)而不是单引号(’),php与mysql编码不一致(UTF8),内容包括冒号(:)和引号(;)也会导致反序列化出错。
解决的方法是在serialize上加上base64函数,对数据做base64编码和解码:

$toDatabse = base64_encode(serialize($data));
$fromDatabase = unserialize(base64_decode($data)); 

当然更建议使用json_encode和json_decode的来处理数据的序列化和反序列化会更快,但有一些局限性(这里)继续阅读

开启Firephp时Nginx PHP-FPM下502错误解决

在自己的电脑上调试的好好的,部署到Linux Nginx环境的时候却发现有些PHP页面在Firefox下面会返回502,在IE下面却是正常的,甚至在chrome下面也会出现502。顺着Nginx,Firefox这两个关键字,终于找到原因:原来是开启Firephp(chrome装了webug)时,Firephp的调试信息会写入的请求头里面,导致Nginx的FastCGI缓冲区超出,从而返回502。在自己的电脑上之所以不会是因为使用的是Apache。
于是顺着其他人的解答修改了nginx.conf中fastcig相关的参数:

fastcgi_buffer_size 1024k;
fastcgi_buffers 8 512k;
fastcgi_busy_buffers_size 1024k;
fastcgi_temp_file_write_size 1024k;

一开始这些参数是256,后来改成了512还是有部分页面会出现502,再改成1024终于好了。 继续阅读

PHP 和 Mysql 日期问题

最近在php 和 mysql上碰到了一个计算日期Bug:在mysql中使用date_add计算日期,比如date_add(now(),interval 30 year),然后保存进去的值就变成了’0000-00-00 00:00:00’;在php 中使用strtotime计算日期,比如(‘2143-08-22 15:23:56 -100 year’),然后格式化后就变成了’1970-01-01 ‘。后来google了下,发现这是著名的2038年问题
这个问题是因为在32位操作系统上日期类型是一个有正负号的32位整数,2147483647 是能表示的最大32为正整数,对应2038-01-19 03:14:07,超出了就“绕回”,所以不能正常处理。 继续阅读