分析 PHP 应用程序以查找、诊断和加速运行缓慢的代码(Xdebug+KCacheGrind)
2014-05-14 14:28
691 查看
利用Xdebug+KCacheGrind来调试
原文地址:http://www.ibm.com/developerworks/cn/opensource/os-php-fastapps2/index.html
PHP 的一个较流行的分析器是 Xdebug,它还为交互地调试 PHP 应用程序提供了服务器挂钩(hook)。(参见“调试的更好方法”以了解更多信息。该系列的另一部分将探讨高级交互式调试。) Xdebug 很容易从源代码构建,将其作为 Zend 扩展进行安装也非常简单。(现在已有针对某些平台的二进制文件。)当就绪后,对基于 PHP 页面的每个请求都将生成可在
如果具备了 PHP 实用工具
php.ini 配置文件的访问权,那么安装和设置 Xdebug 只需几分钟的时间。下面给出的指导说明针对 Linux®,不过在 Mac OS X 上的安装步骤实际上与此类似。(您可以从 Xdebug Web 站点找到针对 Microsoft® Windows® 的 Xdebug 预编译版本。)
Xdebug 的最新版本为 V2.0.0RC3(最终版本 V2.0.0 在您阅读此文时也许已经可用)。下载并解包 tarball,然后切换到源代码的子目录。确保
shell 的 PATH,准备使用
清单 1. 设置 Xdebug
—— 名为配置 —— 它对余下的构建过程进行配置。要构建 Xdebug,在
清单 2. 构建 Xdebug
Xdebug 扩展,xdebug.so。剩下的工作就是使用
注: 如果在终端窗口中运行最后一个命令,请选择并复制最后一步中发出的目录。在下一个步骤中将会用到它。
最后,要使配置数据可视化,必须使用
K Desktop Environment (KDE)的 Linux 发行版很可能已经含有了
Linux 的那些版本也不难找到。Debian 用户可以使用 Advanced Packaging Tool (APT) 快速安装
清单 3. 安装 KCacheGrind
如果没有将 KDE 安装到系统中,
90 MB 的磁盘空间。
回页首
安装了 Xdebug 扩展后,就可以准备启用和配置该扩展了。在文本编辑器中打开 php.ini,并添加以下代码行。
清单 4. 启用和配置该扩展
第一行
Xdebug 扩展。第二行命名放置分析器输出的目录。如果需要的话,创建命名的目标并更改其模式以允许用户对 Web 服务器进行写访问。
第三行禁用了分析器。然而,第四行将在设置 HTTP
添加这几行代码并验证了输出目录是可写的,然后重新启动 Web 服务器。对于其他 PHP 扩展,要验证 Xdebug 是否安装并可用,可以创建一个简单的骨架 PHP 程序来调用
1 所示的内容。(为简便起见,省略了完整输出的部分内容。)
图 1. Phpinfo 指明 Xdebug 是否已安装
您还可以向下滚动到 Zend 徽标。如果正确安装并配置了 Xdebug,它将显示在徽标的旁边。
回页首
要分析代码,只需将浏览器指向 PHP 应用程序即可。如果您将分析器设置为对每个触发逐个解决的方式,将
URL 中,或者,像下面一样,将参数嵌入到表单中。
作为一个示例,我们来分析一下这个简单的 ACME Fibonacci Maker,fibonacci.php,如清单 5 所示。为方便起见,将
Xdebug,呈现这个变量将不会造成什么损失。)
清单 5. Fibonacci.php
将浏览器指向 http://localhost/fibonacci.php(或者合适的 URL)并输入数字 —— 比如,16。其结果 —— Fibonacci 系列的第 16 个元素 —— 如图 2 所示。
图 2. 示例 Fibonacci 应用程序
如果将分析器输出目录中的内容(名为 php.ini)列出来的话,应该能看到类似 cachegrind.out.951917687 这样名称的文件。cachegrind.out. 前缀是固定的。默认情况下,数值后缀是目录路径到 fibonacci.php 文件的 CRC32 散列。因此,如果每一个应用程序都位于自己的目录,那么每个程序的输出将根据文件名而被分隔。(如果您更喜欢将输出与时间相关联,将下面这行代码:
添加到 php.ini。)
从终端窗口启动
cachegrind.out.951917687。将立即打开一个类似于图 3 的新窗口。
图 3. KCacheGrind 应用程序
单击 Callees 选项卡,双击源代码中突出显示的行,并从 Grouping 列表选择 Source
File 。所看到的视图应变为类似图 4 所示的内容。
图 4. 查看结果
正如您预期的一样,实际上全部的处理时间(70,989 毫秒的 99.87%)都花费在 3193 次对
Fibonacci 序列,程序会随之变慢),应该避免重新计算 Fibonacci 数字这样代价高昂的重复工作。事实上,ACME Fibonacci Maker 能够很好地进行计算重用。
下面展示了
5 展示了分析结果:与上次的 3192 次函数调用相比,这里仅需要 30 次调用(并且只有一半的调用需要计算结果),而时间则减少为只有 20 毫秒。
清单 6. 更新了的 fib() 函数
图 5. 加快了的 Fibonacci 函数
虽然单次运行应用程序能够指出一些问题(可以试试上面原始的应用程序中的 Fibonacci 序列的第 50 个元素 ),通常,还是需要通过几次调用收集统计信息以及查看模式。
如果保留默认的 “crc32” 命名模式,每次运行 fibonacci.php 时,将重写数据文件。然而,可以通过在 php.ini 中设置
图 6 显示了三次运行 Fibonacci Maker 之后数据合计的示例。总时间稍大于两秒;其中 99.97% 的时间花费在了
6 显示了 Call Graph 选项卡,它由
图 6. 合计分析数据
除了分析 PHP 应用程序,还可以在发生错误并进行交互式调试时,配置 Xdebug 扩展(如其名字暗示的一样)来提供详细的栈跟踪和错误消息。栈跟踪和错误消息可以指出错误的原因,而交互式调试允许每次逐步调试代码中的一条指令,查看程序变量的类型和值,并检查所有的 PHP 超全局变量,包括进来的请求参数。
本系列的下一篇文章将具体介绍交互式调试。同时,您可以启用几个 Xdebug 特性来说明应用程序在发生错误时的状态:
无论何时只要应用程序出现错误,设置
Xdebug,那么只要进行代码开发就启用这个特性。
还可以设置
可以在 Xdebug Web 站点找到更多信息。
回页首
如果没有具体的代码,那么很难演示具有意义的分析,下面这个示例是十分典型的代码,展示了从中所能获得的信息。清单 7 显示了一个装配玩具火箭的应用程序(人为设计)。这种玩具火箭由几个部分组成,生产每一个部分都需要一定的时间。在 PHP 中,使用类代表每个组成部分,使用实例方法表示每个部分的构造时间。您可以将这个玩具看作是一个应用程序,并把每个部分看作是该应用程序的功能。
清单 7. 模拟玩具装配的一组 PHP 类
运行这些代码将生成一个新的数据文件。同样,将数据加载到
Graph 选项卡,将看到类似图 7 所示的视图。
图 7. 太空船应用程序的配置文件
Flat Profile 窗格(左面)显示了应用程序调用的所有函数(方法)。最左面的列展示了近似的累计总数,第二列展示了每种方法的单独测试,第三列列出了调用该方法的次数。在调用图表中使用有颜色的方块反映图表内容,这非常方便,能够很容易地将事件序列与其花费的时间关联起来。
很明显,构建阶段所使用的时间代价最昂贵。构建每一部分所需的系统开销(使用
PHP 自身的
最后,还可以查看内存的使用情况。从靠近顶部的下拉菜单中选择 Memory 和 Class,然后切换到顶部以及底部的 Types 和 Caller
Map 选项卡。您看到的屏幕应该类似图 8。
图 8. 太空船应用程序的内存使用情况
回页首
和其他众多 PHP 扩展一样,Xdebug 容易构建、安装快捷且易于配置 —— 所有这些工作 10 分钟内即可完成。如果您已经优化了 Apache 安装并且对应用程序进行了缓存,但是性能仍然很差,那么可以考虑一下代码的运行。算法是否有效?代码是否过于复杂?是否重复实现了 PHP 已提供的函数?
当然,如果不能判断出应用程序的瓶颈所在,那么就必须进行查找并加以修复。不要只凭猜测 —— 要进行分析!您可能会惊讶于宝贵的计算周期是如何被轻意耗费掉的。
并且永远不要忘记:要在生产服务器中禁用 Xdebug,因为启用它总会增加系统开销。
原文地址:http://www.ibm.com/developerworks/cn/opensource/os-php-fastapps2/index.html
PHP 的一个较流行的分析器是 Xdebug,它还为交互地调试 PHP 应用程序提供了服务器挂钩(hook)。(参见“调试的更好方法”以了解更多信息。该系列的另一部分将探讨高级交互式调试。) Xdebug 很容易从源代码构建,将其作为 Zend 扩展进行安装也非常简单。(现在已有针对某些平台的二进制文件。)当就绪后,对基于 PHP 页面的每个请求都将生成可在
KCacheGrind中查看的数据集。
构建并安装 Xdebug
如果具备了 PHP 实用工具 phpize和
php-config,而且具有对系统的
php.ini 配置文件的访问权,那么安装和设置 Xdebug 只需几分钟的时间。下面给出的指导说明针对 Linux®,不过在 Mac OS X 上的安装步骤实际上与此类似。(您可以从 Xdebug Web 站点找到针对 Microsoft® Windows® 的 Xdebug 预编译版本。)
Xdebug 的最新版本为 V2.0.0RC3(最终版本 V2.0.0 在您阅读此文时也许已经可用)。下载并解包 tarball,然后切换到源代码的子目录。确保
phpize和
php-config位于
shell 的 PATH,准备使用
phpize进行构建。
清单 1. 设置 Xdebug
$ wget http://www.xdebug.org/files/xdebug-2.0.0RC3.tgz $ tar xzf xdebug-2.0.0RC3.tgz $ cd xdebug-2.0.0RC3/xdebug-2.0.0RC3 $ phpize Configuring for: PHP Api Version: 20020918 Zend Module Api No: 20020429 Zend Extension Api No: 20050606
phpize的产品是一个脚本
—— 名为配置 —— 它对余下的构建过程进行配置。要构建 Xdebug,在
make后紧接着输入
./configure即可。
清单 2. 构建 Xdebug
$ ./configure checking build system type... i686-apple-darwin8.8.1 checking host system type... i686-apple-darwin8.8.1 checking for egrep... grep -E ... $ make ... Build complete. (It is safe to ignore warnings about tempnam and tmpnam).
make命令生成
Xdebug 扩展,xdebug.so。剩下的工作就是使用
sudo make install进行安装。
$ sudo make install Installing shared extensions: /usr/lib/php/extensions/no-debug-non-zts-20020429/
注: 如果在终端窗口中运行最后一个命令,请选择并复制最后一步中发出的目录。在下一个步骤中将会用到它。
最后,要使配置数据可视化,必须使用
KCacheGrind和
GraphViz。包含
K Desktop Environment (KDE)的 Linux 发行版很可能已经含有了
KCacheGrind和
GraphViz。如果没有包含,适合您所使用的
Linux 的那些版本也不难找到。Debian 用户可以使用 Advanced Packaging Tool (APT) 快速安装
KCacheGrind和
GraphViz以及所有包的依赖关系。
清单 3. 安装 KCacheGrind
$ apt-cache search kcachegrind valgrind-callgrind - call-graph skin for valgrind kcachegrind - visualisation tool for valgrind profiling output kcachegrind-converters - format converters for KCachegrind profiling visualisation tool $ apt-cache search graphviz graphviz - rich set of graph drawing tools graphviz-dev - graphviz Libs and Headers against which to build applications graphviz-doc - additional documentation for graphviz libdeps-renderer-dot-perl - DEPS renderer plugin using GraphViz/dot ... $ sudo apt-get install kcachegrind graphviz ...
如果没有将 KDE 安装到系统中,
KCacheGrind、
GraphViz以及所有必要的内容将占用大约
90 MB 的磁盘空间。
回页首
配置 Xdebug
安装了 Xdebug 扩展后,就可以准备启用和配置该扩展了。在文本编辑器中打开 php.ini,并添加以下代码行。清单 4. 启用和配置该扩展
zend_extension = /usr/lib/php/extensions/no-debug-non-zts-20020429/xdebug.so xdebug.profiler_output_dir = "/tmp/xdebug/" xdebug.profiler_enable = Off xdebug.profiler_enable_trigger = 1
第一行
zend_extension加载
Xdebug 扩展。第二行命名放置分析器输出的目录。如果需要的话,创建命名的目标并更改其模式以允许用户对 Web 服务器进行写访问。
第三行禁用了分析器。然而,第四行将在设置 HTTP
GET或
POST参数
XDEBUG_PROFILE时启用分析器。(如果您希望一直使用分析器,在第三行代码中将
Off更改为
On。)
添加这几行代码并验证了输出目录是可写的,然后重新启动 Web 服务器。对于其他 PHP 扩展,要验证 Xdebug 是否安装并可用,可以创建一个简单的骨架 PHP 程序来调用
phpinfo()并查看结果。应该能够看到类似于图
1 所示的内容。(为简便起见,省略了完整输出的部分内容。)
图 1. Phpinfo 指明 Xdebug 是否已安装
您还可以向下滚动到 Zend 徽标。如果正确安装并配置了 Xdebug,它将显示在徽标的旁边。
回页首
使用分析器
要分析代码,只需将浏览器指向 PHP 应用程序即可。如果您将分析器设置为对每个触发逐个解决的方式,将 XDEBUG_PROFILE=1追加到
URL 中,或者,像下面一样,将参数嵌入到表单中。
作为一个示例,我们来分析一下这个简单的 ACME Fibonacci Maker,fibonacci.php,如清单 5 所示。为方便起见,将
XDEBUG_PROFILE参数设置在表单的隐藏变量内。(当代码投入生产时,很可能将禁用
Xdebug,呈现这个变量将不会造成什么损失。)
清单 5. Fibonacci.php
<?php function fib($nth = 1) { if ( $nth < 2 ) { return( $nth ); } return( fib( $nth - 1) + fib( $nth - 2 ) ); } ?> <html> <head> <title>ACME Fibonacci Maker</title> </head> <body> <h2>Try the ACME Fibonacci Maker!</h2> <form action="fibonacci.php" method="POST"> <input type="hidden" name="XDEBUG_PROFILE" value="1" /> Enter a number: <input type="text" name="n"></input> </form> <hr /> <?php if ( ! empty( $_REQUEST['n'] ) ) { $n = $_REQUEST['n'] % 10; $suffix = array( 1 => "st", 2 => "nd", 3 => "rd" ); if ( $_REQUEST['n'] < 4 || $_REQUEST['n'] > 20 ) { $suffix = $suffix[$n]; } else { $suffix = 'th'; } echo '<p>The ' . $_REQUEST['n'] . $suffix .' Fibonacci number is '; echo fib( $_REQUEST['n'] ) . '</p>'; } ?> </body> </html>
将浏览器指向 http://localhost/fibonacci.php(或者合适的 URL)并输入数字 —— 比如,16。其结果 —— Fibonacci 系列的第 16 个元素 —— 如图 2 所示。
图 2. 示例 Fibonacci 应用程序
如果将分析器输出目录中的内容(名为 php.ini)列出来的话,应该能看到类似 cachegrind.out.951917687 这样名称的文件。cachegrind.out. 前缀是固定的。默认情况下,数值后缀是目录路径到 fibonacci.php 文件的 CRC32 散列。因此,如果每一个应用程序都位于自己的目录,那么每个程序的输出将根据文件名而被分隔。(如果您更喜欢将输出与时间相关联,将下面这行代码:
xdebug.profiler_output_name = timestamp
添加到 php.ini。)
从终端窗口启动
KCacheGrind并打开
cachegrind.out.951917687。将立即打开一个类似于图 3 的新窗口。
图 3. KCacheGrind 应用程序
单击 Callees 选项卡,双击源代码中突出显示的行,并从 Grouping 列表选择 Source
File 。所看到的视图应变为类似图 4 所示的内容。
图 4. 查看结果
正如您预期的一样,实际上全部的处理时间(70,989 毫秒的 99.87%)都花费在 3193 次对
fib()函数的调用上了。要加快该应用程序(随着进一步执行
Fibonacci 序列,程序会随之变慢),应该避免重新计算 Fibonacci 数字这样代价高昂的重复工作。事实上,ACME Fibonacci Maker 能够很好地进行计算重用。
下面展示了
fib()函数的优化版本。新的版本用内存换来了时间上的节省,因为它保留了中间的计算以便以后使用。图
5 展示了分析结果:与上次的 3192 次函数调用相比,这里仅需要 30 次调用(并且只有一半的调用需要计算结果),而时间则减少为只有 20 毫秒。
清单 6. 更新了的 fib() 函数
function fib($nth = 1) { static $fibs = array(); if ( ! empty ($fibs[$nth] ) ) { return( $fibs[$nth] ); } if ( $nth < 2 ) { $fibs[$nth] = $nth; } else { $fibs[$nth - 1] = fib( $nth - 1 ); $fibs[$nth - 2] = fib( $nth - 2 ); $fibs[$nth] = $fibs[$nth - 1] + $fibs[$nth -2]; } return( $fibs[$nth] ); } ?>
图 5. 加快了的 Fibonacci 函数
虽然单次运行应用程序能够指出一些问题(可以试试上面原始的应用程序中的 Fibonacci 序列的第 50 个元素 ),通常,还是需要通过几次调用收集统计信息以及查看模式。
如果保留默认的 “crc32” 命名模式,每次运行 fibonacci.php 时,将重写数据文件。然而,可以通过在 php.ini 中设置
xdebug.profiler_append = 1改变这种行为并将后续运行追加到相同的文件。更改之后重新启动 Web 服务器。
图 6 显示了三次运行 Fibonacci Maker 之后数据合计的示例。总时间稍大于两秒;其中 99.97% 的时间花费在了
fib()上。图
6 显示了 Call Graph 选项卡,它由
GraphViz的
dot工具生成。关于
KCacheGrind的具体用法不在本文讨论的范围之内,但是可以从网上获得其完整的文档。
KCacheGrind可以以很多种方法对数据进行交叉分析,根据您希望解决的问题选择合适的方法。
图 6. 合计分析数据
调试的更好方法
除了分析 PHP 应用程序,还可以在发生错误并进行交互式调试时,配置 Xdebug 扩展(如其名字暗示的一样)来提供详细的栈跟踪和错误消息。栈跟踪和错误消息可以指出错误的原因,而交互式调试允许每次逐步调试代码中的一条指令,查看程序变量的类型和值,并检查所有的 PHP 超全局变量,包括进来的请求参数。本系列的下一篇文章将具体介绍交互式调试。同时,您可以启用几个 Xdebug 特性来说明应用程序在发生错误时的状态:
无论何时只要应用程序出现错误,设置
xdebug.default_enable=On显示栈跟踪。如果您已经花费时间安装了
Xdebug,那么只要进行代码开发就启用这个特性。
还可以设置
xdebug.show_local_vars=1来进一步显示最顶部范围内的所有变量。
xdebug.var_display_max_children、
xdebug.var_display_max_data和
xdebug.var_display_max_depth>是相关的三个设置,分别用来控制因
xdebug.show_local_vars的使用而显示的变量的属性数、字符串长度和嵌套深度。
可以在 Xdebug Web 站点找到更多信息。
回页首
分析类
如果没有具体的代码,那么很难演示具有意义的分析,下面这个示例是十分典型的代码,展示了从中所能获得的信息。清单 7 显示了一个装配玩具火箭的应用程序(人为设计)。这种玩具火箭由几个部分组成,生产每一个部分都需要一定的时间。在 PHP 中,使用类代表每个组成部分,使用实例方法表示每个部分的构造时间。您可以将这个玩具看作是一个应用程序,并把每个部分看作是该应用程序的功能。清单 7. 模拟玩具装配的一组 PHP 类
<?php define( 'BOOSTER', 5 ); define( 'CAPSULE', 2 ); define( 'MINUTE', 60 ); define( 'STAGE', 3 ); define( 'PRODUCTION', 1000 ); class Part { function Part() { $this->build( MINUTE ); } function build( $delay = 0 ) { if ( $delay <= 0 ) return; while ( $delay-- > 0 ) { } } } class Capsule extends Part { function Capsule() { parent::Part(); $this->build( CAPSULE * MINUTE ); } } class Booster extends Part { function Booster() { parent::Part(); $this->build( BOOSTER * MINUTE ); } } class Stage extends Part { function Stage() { parent::Part(); $this->build( STAGE * MINUTE ); } } class SpaceShip { var $booster; var $capsule; var $stages; function SpaceShip( $numberStages = 3 ) { $this->booster = new Booster(); $this->capsule = new Capsule(); $this->stages = array(); while ( $numberStages-- >= 0 ) { $stages[$numberStages] = new Stage(); } } } $toys = array(); $count = PRODUCTION; while ( $count-- >= 0 ) { $toys[] = new SpaceShip( 2 ); } ?> <html> <head> <title> Toy Factory Output </title> </head> <body> <h1>Toy Production</h1> <p>Built <? echo PRODUCTION . ' toys' ?></p> </body> </html>
运行这些代码将生成一个新的数据文件。同样,将数据加载到
KCacheGrind。如果切换到 Source 和 Call
Graph 选项卡,将看到类似图 7 所示的视图。
图 7. 太空船应用程序的配置文件
Flat Profile 窗格(左面)显示了应用程序调用的所有函数(方法)。最左面的列展示了近似的累计总数,第二列展示了每种方法的单独测试,第三列列出了调用该方法的次数。在调用图表中使用有颜色的方块反映图表内容,这非常方便,能够很容易地将事件序列与其花费的时间关联起来。
很明显,构建阶段所使用的时间代价最昂贵。构建每一部分所需的系统开销(使用
Part的构造器表示)次之。再看一下
PHP 自身的
define()函数,它只花费了很少的开销。
最后,还可以查看内存的使用情况。从靠近顶部的下拉菜单中选择 Memory 和 Class,然后切换到顶部以及底部的 Types 和 Caller
Map 选项卡。您看到的屏幕应该类似图 8。
图 8. 太空船应用程序的内存使用情况
回页首
找回周期
和其他众多 PHP 扩展一样,Xdebug 容易构建、安装快捷且易于配置 —— 所有这些工作 10 分钟内即可完成。如果您已经优化了 Apache 安装并且对应用程序进行了缓存,但是性能仍然很差,那么可以考虑一下代码的运行。算法是否有效?代码是否过于复杂?是否重复实现了 PHP 已提供的函数?当然,如果不能判断出应用程序的瓶颈所在,那么就必须进行查找并加以修复。不要只凭猜测 —— 要进行分析!您可能会惊讶于宝贵的计算周期是如何被轻意耗费掉的。
并且永远不要忘记:要在生产服务器中禁用 Xdebug,因为启用它总会增加系统开销。
相关文章推荐
- [转]为 PHP 应用提速、提速、再提速!,第 2 部分: 分析 PHP 应用程序以查找、诊断和加速运行缓慢的代码
- 为 PHP 应用提速、提速、再提速!,第 2 部分: 分析 PHP 应用程序以查找、诊断和加速运行缓慢的代码
- PHP 应用提速 - 第 2 部分: 分析 PHP 应用程序以查找、诊断和加速运行缓慢的代码
- [转]为 PHP 应用提速、提速、再提速!,第 2 部分: 分析 PHP 应用程序以查找、诊断和加速运行缓慢的代码
- 分析PHP应用程序以查找、诊断和加速运行缓慢的代码
- PHP应用系列之二:查找、诊断和加速运行缓慢的代码
- centos安装php扩展xdebug安装以及用kcachegrind系统分析
- php页面运行慢原因查找与监测分析代码
- 使用PhpStorm和Xdebug分析PHP应用程序
- WinCacheGrind配合XDebug分析PHP程序性能
- php扩展xdebug安装以及用kcachegrind系统分析
- WinCacheGrind配合XDebug分析PHP程序性能
- WinCacheGrind配合XDebug分析PHP程序性能
- 利用xdebug对php代码进行性能分析
- XDebug分析php代码性能
- php代码优化方法,加速运行速度的技巧总结
- PHP开发程序加速运行探索之慢代码优化方法
- PHP性能调整的好工具:xdebug+kcachegrind
- PHP性能调整的好工具:xdebug+kcachegrind
- WinCacheGrind配合XDebug分析PHP程序性能