本文主要介绍:
XHProf是一个轻量级的 PHP 性能分析工具,提供了图形化的界面展示性能参数和过程。
#获取源码包
wget http://pecl.php.net/get/xhprof-2.3.8.tgz
tar xvf xhprof-2.3.8.tgz
cd xhprof/extension
#编译安装
/opt/remi/php74/root/usr/bin/phpize
./configure --with-php-config=/opt/remi/php74/root/usr/bin/php-config
make && make install
#配置 xhprof 的扩展及运行数据路径
vim /etc/opt/remi/php74/php.d/20-xhprof.ini
; Enable xhprof extension module
extension=xhprof.so
#储存 XHProf 运行数据的默认目录,默认值是 /tmp
xhprof.output_dir=/tmp/xhprof
#重启 php-fpm
systemctl restart php74-php-fpm
#检查是否安装成功
php -m | grep xhprof
# 将源码包中的lib和html文件夹复制到项目路径下
cp -r /root/xhprof-2.3.8/xhprof_html /wwwroot/xhprof/
cp -r /root/xhprof-2.3.8/xhprof_lib /wwwroot/xhprof/
#配置Nginx
server {
listen 1025;
server_name your_ip_or_domain;
root /wwwroot/xhprof/xhprof_html;
index index.php index.html index.htm;
access_log /var/log/nginx/xhprof_access.log;
error_log /var/log/nginx/xhprof_error.log;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi.conf;
}
}
#重新加载nginx配置
nginx -s reload
#访问你的IP或域名
#安装libpng
wget https://sourceforge.net/projects/libpng/files/libpng16/1.6.28/libpng-1.6.28.tar.gz/download
mv download libpng-1.6.28.tar.gz
tar -zxvf libpng-1.6.28.tar.gz
cd libpng-1.6.28
./configure
make && make install
#安装Graphviz
wget http://www.graphviz.org/pub/graphviz/stable/SOURCES/graphviz-2.24.0.tar.gz
tar -zxvf graphviz-2.24.0.tar.gz
cd graphviz-2.24.0
./configure
make && make install
#重启php-fpm
#确认配置目录 xhprof.output_dir 的权限,并且存在数据文件
chown -R www:www /tmp/xhprof
#开启xhprof
xhprof_enable(XHPROF_FLAGS_NO_BUILTINS | XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY, []);
#停止性能分析,并返回此次运行的 xhprof 数据
$xhprof_data = xhprof_disable();
#将数据写入文件中
file_put_contents('/tmp/xhprof/' . uniqid() . '.xhprof', serialize($data));
Incl. 表示Including(包含)的缩写
Excl. 表示Excluding(不包含)的缩写
Function Name: 函数名
Calls: 调用次数
Calls%: 调用次数的百分比
Incl. Wall Time: 包含子函数执行的所有花费时间。单位:微秒(下同)
Excl. Wall Time: 函数本身执行所花费的时间。
Incl. CPU: 包含子函数执行的所花费的CPU时间。
Excl. CPU: 函数本身执行所花费的CPU时间。
Incl.MemUse: 包含子函数执行的所占用的内存。单位:字节(下同)
Excl.MemUse: 函数本身执行所占用的内存。
Incl.PeakMemUse: 包含子函数执行,所占用内存的峰值。
Excl.PeakMemUse: 函数本身执行所占用内存的峰值。
即:
select * from table_name
这样的查询语句,改成获取具体的字段,也可以用Redis,ES等手段去优化。加载流程:
扩展会提供一个 get_module(void) 的方法拿到扩展的 zend_module_entry 结构体的定义 扩展被编译成so文件后,在php.ini文件中配置 xxx.so, 表示加载扩展 php 启动的时候会读取 php.ini 文件,并做解析 在 Linux 下 通过 dlopen() 打开扩展的 xxx.so 库文件 通过系统的 dlsym() 获取动态库中 get_module() 函数的地址,执行每个扩展的 get_module 方法拿到 zend_module_entry 结构体 把zend_module_entry 结构体注册到php的 extension_lists 扩展列表中。extension_lists是一个链表,保存着根据php.ini中定义的extension=xxx.so取到的全部扩展名称,其中engine是zend扩展,functions为php扩展在 php 的生命周期中执行各个扩展定义的 PHP_MINIT
起始外部扩展就是相当于内核一个模块,都是 zend_module_entry 结构体。
收集性能数据的原理,就是在模块初始化的时候代理了这个,代理了这个编译和执行OPCODE 的函数,覆盖了一层,加了自己的处理,自己的处理就是C代码的执行时间和PHP申请堆内存的计算。
收集数据的过程其实针对函数嵌套调用递归收集的过程。在调用xhprof_enable方法时,会把默认的方法替换为xhprof的方法。
static void hp_begin(long level, long xhprof_flags)
{
if (!hp_globals.enabled)
{
int hp_profile_flag = 1;
hp_globals.enabled = 1;
hp_globals.xhprof_flags = (uint32) xhprof_flags;
/* Replace zend_compile with our proxy */
/* 处理加载PHP文件 */
/* 先把zend引擎默认处理方法保存到_zend_compile_file变量中。*/
_zend_compile_file = zend_compile_file;
/* 在把xhprof相对应的方法赋值给zend_compile_file。
这样,每次加载PHP文件时,就会执行xhprof相应的方法。*/
zend_compile_file = hp_compile_file;
/* Replace zend_compile_string with our proxy */
/* 处理eval代码的执行 */
_zend_compile_string = zend_compile_string;
zend_compile_string = hp_compile_string;
/*init the execute pointer*/
/* 处理 函数方法的执行 */
_zend_execute_ex = zend_execute_ex;
zend_execute_ex = hp_execute_ex;
// .........
}
}
/*那我们看下,hp_compile_file方法,又是如何实现的*/
ZEND_DLEXPORT zend_op_array* hp_compile_file(zend_file_handle *file_handle, int type)
{
const char *filename;
char *func;
int len;
zend_op_array *ret;
int hp_profile_flag = 1;
filename = hp_get_base_filename(file_handle->filename);
len = sizeof("load") - 1 + strlen(filename) + 3;
func = (char *) emalloc(len);
snprintf(func, len, "load::%s", filename);
//方法执行前记录当前各项性能如数,如cpu 内存等
BEGIN_PROFILING(&hp_globals.entries, func, hp_profile_flag);
//开始zend引擎相应的方法,加载文件
ret = _zend_compile_file(file_handle, type);
if (hp_globals.entries)
{
//加载文件完毕后,再次记录当前各项性能数据。以便以后计算差值。
END_PROFILING(&hp_globals.entries, hp_profile_flag);
}
efree(func);
return ret;
xhprof_enable开启的这一行解析成 OPCODE,然后执行之前代理的 hp_execute_ex 函数,初始化main节点,来存当前调用PHP函数的性能数据 ct wt mu pmu等数据。
在xhprof_enable 和 xhprof_disable 之前的PHP代码,每一行都会被翻译成OPCODE,都会执行hp_execute_ex 函数。
$xhprof_data = xhprof_disable();
结束收集数据,返回已经收集到的数据。
数据格式在内核里面是一个二级HASHTABLE,对应PHP是一个二维数组
这个结束过程是对应这之前xhprof_enable的执行过程,是对main虚拟的节点做回源处理。
xhprof_enable提供了三个常量,用于设置你是否需要统计PHP内置函数,都统计那些指标。
三个常量如下:
XHPROF_FLAGS_NO_BUILTINS
设置这个常量后,将不统计PHP内置函数。毕竟PHP的内置函数性能一般都不错。没必要再消耗性能去统计。所以,建议设置。
XHPROF_FLAGS_CPU
设置这个常量后,会统计进程占用CPU时间。由于CPU时间是通过调用系统调用getrusage获取,导致性能比较差。开启这个选项后,大概性能下降一半。因此,如果对cpu耗时不是特别敏感的情况下,建议不要启用这个选项。
XHPROF_FLAGS_MEMORY
设置这个常量后,将会统计内存占用情况。由于获取内存情况,使用的是zend_memory_usage和zend_memory_peak_usage,并不是系统调用。因此,对性能影响不大。如果需要对内存使用情况进行分析的情况下,可以开启。
xhprof_lib/utils/xhprof_lib.php文件包含额外的库函数,可用于维护、汇总XHProf运行结果。
例如:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。