"); //-->
$ 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
$ ./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).
$ sudo make install Installing shared extensions: /usr/lib/php/extensions/no-debug-non-zts-20020429/
$ 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 ...
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 徽标。如果正确安装并配置了 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>
如果将分析器输出目录中的内容(名为 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. 合计分析数据
如果没有具体的代码,那么很难演示具有意义的分析,下面这个示例是十分典型的代码,展示了从中所能获得的信息。清单 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>
Flat Profile 窗格(左面)显示了应用程序调用的所有函数(方法)。最左面的列展示了近似的累计总数,第二列展示了每种方法的单独测试,第三列列出了调用该方法的次数。在调用图表中使用有颜色的方块反映图表内容,这非常方便,能够很容易地将事件序列与其花费的时间关联起来。
很明显,构建阶段所使用的时间代价最昂贵。构建每一部分所需的系统开销(使用 Part 的构造器表示)次之。再看一下 PHP 自身的 define() 函数,它只花费了很少的开销。
最后,还可以查看内存的使用情况。从靠近顶部的下拉菜单中选择 Memory 和 Class,然后切换到顶部以及底部的 Types 和 Caller Map 选项卡。您看到的屏幕应该类似图 8。
图 8. 太空船应用程序的内存使用情况
找回周期
和其他众多 PHP 扩展一样,Xdebug 容易构建、安装快捷且易于配置 —— 所有这些工作 10 分钟内即可完成。如果您已经优化了 Apache 安装并且对应用程序进行了缓存,但是性能仍然很差,那么可以考虑一下代码的运行。算法是否有效?代码是否过于复杂?是否重复实现了 PHP 已提供的函数?
当然,如果不能判断出应用程序的瓶颈所在,那么就必须进行查找并加以修复。不要只凭猜测 —— 要进行分析!您可能会惊讶于宝贵的计算周期是如何被轻意耗费掉的。
并且永远不要忘记:要在生产服务器中禁用 Xdebug,因为启用它总会增加系统开销。
来源:http://www.qqread.com/php/2008/02/b395140.html
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。