最简单的方法来分析一个PHP脚本

什么是最简单的方法来分析一个PHP脚本?

我喜欢加上一些东西,显示了所有函数调用的转储和他们花了多长时间,但我也可以把特定的function放在一起。

我尝试了microtime函数的实验:

$then = microtime(); myFunc(); $now = microtime(); echo sprintf("Elapsed: %f", $now-$then); 

但有时会给我带来负面的结果。 另外,在我的代码上撒上很多麻烦。

PECL APD扩展使用如下:

 <?php apd_set_pprof_trace(); //rest of the script ?> 

之后,使用pprofpparsing生成的文件。

示例输出:

 Trace for /home/dan/testapd.php Total Elapsed Time = 0.00 Total System Time = 0.00 Total User Time = 0.00 Real User System secs/ cumm %Time (excl/cumm) (excl/cumm) (excl/cumm) Calls call s/call Memory Usage Name -------------------------------------------------------------------------------------- 100.0 0.00 0.00 0.00 0.00 0.00 0.00 1 0.0000 0.0009 0 main 56.9 0.00 0.00 0.00 0.00 0.00 0.00 1 0.0005 0.0005 0 apd_set_pprof_trace 28.0 0.00 0.00 0.00 0.00 0.00 0.00 10 0.0000 0.0000 0 preg_replace 14.3 0.00 0.00 0.00 0.00 0.00 0.00 10 0.0000 0.0000 0 str_replace 

你想要xdebug我想。 在服务器上安装它,打开它,通过kcachegrind (对于linux)或wincachegrind (对于windows)输出输出,它会显示一些漂亮的图表,详细的确切时间,计数和内存使用情况(但你会需要另一个扩展)。

它认真地说:D

不需要扩展,只需使用这两个函数进行简单的性能分析即可。

 // Call this at each point of interest, passing a descriptive string function prof_flag($str) { global $prof_timing, $prof_names; $prof_timing[] = microtime(true); $prof_names[] = $str; } // Call this when you're done and want to see the results function prof_print() { global $prof_timing, $prof_names; $size = count($prof_timing); for($i=0;$i<$size - 1; $i++) { echo "<b>{$prof_names[$i]}</b><br>"; echo sprintf("&nbsp;&nbsp;&nbsp;%f<br>", $prof_timing[$i+1]-$prof_timing[$i]); } echo "<b>{$prof_names[$size-1]}</b><br>"; } 

下面是一个例子,在每个检查点调用prof_flag(),并在末尾调用prof_print():

 prof_flag("Start"); include '../lib/database.php'; include '../lib/helper_func.php'; prof_flag("Connect to DB"); connect_to_db(); prof_flag("Perform query"); // Get all the data $select_query = "SELECT * FROM data_table"; $result = mysql_query($select_query); prof_flag("Retrieve data"); $rows = array(); $found_data=false; while($r = mysql_fetch_assoc($result)) { $found_data=true; $rows[] = $r; } prof_flag("Close DB"); mysql_close(); //close database connection prof_flag("Done"); prof_print(); 

输出如下所示:

开始
0.004303
连接到数据库
0.003518
执行查询
0.000308
检索数据
0.000009
closures数据库
0.000049
完成

如果减去microtimes给你消极的结果,尝试使用参数truemicrotime(true) )的函数。 使用true ,函数将返回一个float而不是一个string(就像它在没有参数的情况下调用一样)。

老实说,我会争辩说,使用NewRelic进行分析是最好的。

这是一个PHP扩展,它似乎并没有减慢运行时间,他们为你做了监测,允许体面的钻取。 在昂贵的版本,他们允许沉重的钻取(但我们负担不起他们的定价模式)。

尽pipe如此,即使是免费/标准的计划,大部分低挂果实也是显而易见的。 我也喜欢它可以给你一个关于数据库交互的想法。

分析时其中一个接口的屏幕截图

PECL XHPROF看起来也是交织在一起的。 它有可点击的HTML界面查看报告和非常简单的文档 。 我还没有testing它。

我喜欢用phpDebug进行分析。 http://phpdebug.sourceforge.net/www/index.html

它输出所有使用的SQL以及所有包含文件的所有时间/内存使用情况。 显然,它最好在抽象的代码上工作。

对于函数和类分析,我只需要使用microtime() + get_memory_usage() + get_peak_memory_usage()

我会挑战BlackFire的尝试。

有这个虚拟框我已经放在一起使用的是puphpet ,来testing不同的PHP框架与BlackFire的COM,请随意叉和/或分发,如果需要的话:)

https://github.com/webit4me/PHPFrameworks

穷人的分析,不需要扩展。 支持嵌套的configuration文件和总数的百分比:

 function p_open($flag) { global $p_times; if (null === $p_times) $p_times = []; if (! array_key_exists($flag, $p_times)) $p_times[$flag] = [ 'total' => 0, 'open' => 0 ]; $p_times[$flag]['open'] = microtime(true); } function p_close($flag) { global $p_times; if (isset($p_times[$flag]['open'])) { $p_times[$flag]['total'] += (microtime(true) - $p_times[$flag]['open']); unset($p_times[$flag]['open']); } } function p_dump() { global $p_times; $dump = []; $sum = 0; foreach ($p_times as $flag => $info) { $dump[$flag]['elapsed'] = $info['total']; $sum += $info['total']; } foreach ($dump as $flag => $info) { $dump[$flag]['percent'] = $dump[$flag]['elapsed']/$sum; } return $dump; } 

例:

 <?php p_open('foo'); sleep(1); p_open('bar'); sleep(2); p_open('baz'); sleep(3); p_close('baz'); sleep(2); p_close('bar'); sleep(1); p_close('foo'); var_dump(p_dump()); 

产量:

 array:3 [ "foo" => array:2 [ "elapsed" => 9.000766992569 "percent" => 0.4736904954747 ] "bar" => array:2 [ "elapsed" => 7.0004580020905 "percent" => 0.36841864946596 ] "baz" => array:2 [ "elapsed" => 3.0001420974731 "percent" => 0.15789085505934 ] ] 

从SO文档testing版中下载我的参考文档。

用XDebug进行分析

一个名为Xdebug的PHP扩展可以帮助分析PHP应用程序以及运行时debugging。 运行分析器时,输出将以二进制格式(称为“cachegrind”)写入文件。 应用程序可在每个平台上分析这些文件。 节点应用程序代码更改是执行此分析所必需的。

要启用性能分析,请安装扩展并调整php.ini设置。 一些Linux发行版带有标准软件包(例如Ubuntu的php-xdebug软件包)。 在我们的例子中,我们将根据请求参数select性地运行configuration文件。 这使我们能够保持静态设置,并根据需要打开分析器。

 // Set to 1 to turn it on for every request xdebug.profiler_enable = 0 // Let's use a GET/POST parameter to turn on the profiler xdebug.profiler_enable_trigger = 1 // The GET/POST value we will pass; empty for any value xdebug.profiler_enable_trigger_value = "" // Output cachegrind files to /tmp so our system cleans them up later xdebug.profiler_output_dir = "/tmp" xdebug.profiler_output_name = "cachegrind.out.%p" 

接下来,使用Web客户端向您的应用程序的URL进行请求,例如

 http://example.com/article/1?XDEBUG_PROFILE=1 

在页面处理过程中,它将写入一个名称类似于的文件

 /tmp/cachegrind.out.12345 

默认情况下,文件名中的数字是写入它的进程ID。 这可以使用xdebug.profiler_output_name设置进行configuration。

请注意,它将为每个执行的PHP请求/进程写入一个文件。 所以,例如,如果你想分析一个表单发布,一个configuration文件将被写入GET请求来显示HTML表单。 XDEBUG_PROFILE参数将需要传递到后续的POST请求来分析处理表单的第二个请求。 因此,在分析时有时更容易直接运行curl来POST表单。

一旦写入configuration文件caching可以被诸如KCachegrind的应用程序读取。

KCachegrind

这将显示信息包括:

  • 执行的function
  • 调用时间,包括它本身和后续的函数调用
  • 每个函数被调用的次数
  • 调用图表
  • 链接到源代码

很显然,性能调优对每个应用程序的用例都是非常具体的。 一般而言,寻找以下内容是很好的:

  • 重复调用您不希望看到的相同function。 对于处理和查询数据的函数,这些可能是您的应用程序caching的主要机会。
  • 运行缓慢的function。 应用程序在哪里花费大部分时间? 性能调优的最佳收益是关注那些消耗最多时间的应用程序部分。

注意 :Xdebug,特别是它的性能分析function,是非常耗费资源的,并且会降低PHP的执行速度。 build议不要在生产服务器环境中运行这些。

对于基准testing,就像你的例子一样,我使用梨基准软件包。 您设置测量标记。 该类还提供了一些演示助手,或者您可以按照您认为合适的方式处理数据。

我实际上用__destruct方法把它包装在另一个类中。 当脚本退出时,输出会通过log4phplogging到syslog中,所以我有很多性能数据可以使用。

XDebug不稳定,并不总是可用于特定的PHP版本。 例如,在一些服务器上,我仍然运行php-5.1.6,这是RedHat RHEL5的function(并且btw仍然接收所有重要问题的更新),最近的XDebug甚至没有用这个php编译。 所以我最终切换到DBGdebugging器它的PHP基准testing提供了时序function,方法,模块甚至线路。