312

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

我很想在上面添加一些东西,向我展示所有函数调用的转储以及它们花费了多长时间,但我也可以在特定函数周围放置一些东西。

我尝试使用microtime功能:

$then = microtime();
myFunc();
$now = microtime();

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

但这有时会给我带来负面的结果。另外,在我的代码中到处乱写是很麻烦的。

4

13 回答 13

275

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

真的很摇滚:D

于 2008-08-21T20:46:41.690 回答
109

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

// 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
关闭数据库
   0.000049
完成

于 2015-03-12T23:43:31.273 回答
107

PECL APD扩展的使用如下:

<?php
apd_set_pprof_trace();

//rest of the script
?>

之后,使用 . 解析生成的文件pprofp

示例输出:

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

警告:APD 的最新版本是 2004 年发布的,扩展不再维护,并且存在各种兼容性问题(请参阅评论)。

于 2008-08-21T21:04:17.157 回答
47

交叉发布我从离线的 SO 文档测试版中的参考。

使用 XDebug 进行分析

一个名为 Xdebug 的 PHP 扩展可用于帮助分析 PHP 应用程序以及运行时调试。运行探查器时,输出以称为“cachegrind”的二进制格式写入文件。每个平台上都有应用程序来分析这些文件。 执行此分析无需更改应用程序代码。

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

# php.ini settings
# 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设置进行配置。

请注意,它将为每个执行的 PHP 请求/进程写入一个文件。因此,例如,如果您希望分析表单帖子,将为 GET 请求编写一个配置文件以显示 HTML 表单。XDEBUG_PROFILE 参数将需要传递到后续的 POST 请求中,以分析处理表单的第二个请求。因此,在进行分析时,有时更容易运行 curl 直接 POST 表单。

分析输出

一旦写入配置文件缓存,就可以被KCachegrindWebgrind等应用程序读取。PHPStorm 是一种流行的 PHP IDE,也可以显示此分析数据

KCachegrind

例如,KCachegrind 将显示以下信息:

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

要找什么

显然,性能调优对每个应用程序的用例都非常具体。一般来说,最好寻找:

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

注意:Xdebug,尤其是它的分析功能,是非常耗费资源的,并且会减慢 PHP 的执行速度。建议不要在生产服务器环境中运行这些。

于 2017-08-04T17:27:50.050 回答
25

如果减去微时间会给您带来负面结果,请尝试使用带有参数true( microtime(true)) 的函数。使用true,该函数返回一个浮点数而不是一个字符串(就像在不带参数的情况下调用它一样)。

于 2012-01-10T16:47:32.997 回答
25

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

这是一个 PHP 扩展,它似乎根本不会减慢运行时的速度,它们会为您进行监控,从而可以进行适当的深入研究。在昂贵的版本中,他们允许大量深入研究(但我们负担不起他们的定价模型)。

尽管如此,即使使用免费/标准计划,大多数低悬的果实在哪里也是显而易见和简单的。我也喜欢它也可以让您了解数据库交互。

分析时其中一个界面的屏幕截图

于 2013-12-19T02:05:48.527 回答
19

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

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
  ]
]
于 2016-09-07T20:36:48.820 回答
14

你们都应该检查这个新的 php profiler。

https://github.com/NoiseByNorthwest/php-spx

它重新定义了 php profilers 收集和呈现结果的方式。PHP-SPX 不仅仅输出特定函数调用的总数和执行它所花费的总时间,而是以一种完全可读的方式呈现请求执行的整个时间线。下面是它提供的 GUI 屏幕。

在此处输入图像描述

于 2020-02-03T09:56:10.457 回答
13

PECL XHPROF看起来也很有趣。它具有可点击的 HTML 界面,用于查看报告和非常简单的文档。我还没有测试它。

于 2011-06-23T11:26:12.677 回答
10

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

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

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

于 2008-08-21T20:45:03.363 回答
8

我会毫不犹豫地尝试一下BlackFire

我使用 puphpet 组合了这个virtualBox,用于测试与 BlackFire 一起使用的不同 php 框架,如果需要,请随时分叉和/或分发:)

https://github.com/webit4me/PHPFrameworks

于 2015-09-29T21:04:20.683 回答
6

对于基准测试,就像在您的示例中一样,我使用pear Benchmark包。您设置测量标记。该类还提供了一些演示助手,或者您可以根据需要处理数据。

我实际上用 __destruct 方法将它包装在另一个类中。当脚本退出时,输出会通过 log4php 记录到 syslog,因此我有很多性能数据可供使用。

于 2008-08-22T15:43:20.133 回答
2

XDebug 不稳定,它并不总是适用于特定的 php 版本。例如,在某些服务器上,我仍然运行 php-5.1.6,——它是 RedHat RHEL5 附带的(顺便说一句,所有重要问题仍会收到更新),最近的 XDebug 甚至无法使用这个 php 编译。所以我最终切换到DBG 调试器 。它的php 基准测试为函数、方法、模块甚至行提供了计时。

于 2013-04-04T07:48:58.543 回答