关于性能:如何对PHP脚本的效率进行基准测试

How to benchmark efficiency of PHP script

我想知道什么是测试PHP脚本的最佳方法。不管是cron作业、网页还是Web服务。

我知道我可以使用微时间,但它真的给了我一个PHP脚本的实时性吗?

我想在PHP中测试和测试执行相同操作的不同函数。例如,preg_matchvs strposdomdocumentvs preg_match或preg替换vs str替换`

网页示例:

1
2
3
4
5
6
7
8
9
10
11
<?php
// login.php

$start_time = microtime(TRUE);

session_start();
// do all my logic etc...

$end_time = microtime(TRUE);

echo $end_time - $start_time;

这将输出:0.0146126717(随时间变化-但这是我最后得到的结果)。这意味着执行PHP脚本需要0.015左右的时间。

有更好的方法吗?


如果您真的想要对现实世界的代码进行基准测试,那么可以使用xdebug和xhprof等工具。

xdebug非常适合在dev/staging中工作,xhprof是一个很好的生产工具,在那里运行它是安全的(只要您阅读了说明)。任何一个单页加载的结果都不会像在服务器遭受重击而做上百万件其他事情和资源变得稀缺时看到代码如何执行那样重要。这又提出了另一个问题:您是否在CPU上遇到瓶颈?猛撞?输入输出?

除了脚本中运行的代码外,您还需要了解脚本/页面的服务方式。您使用的是什么Web服务器?例如,我可以让nginx+php-fpm认真地执行mod_php+apache,而mod_php+apache又会因为使用好的cdn服务静态内容而受到困扰。

接下来要考虑的是你正在努力优化的目标是什么?

  • 页面在用户浏览器中呈现的速度第一优先权?
  • 正在尽快将每个发送到服务器的请求抛出尽可能以最小的CPU消耗为目标?

前者可以通过执行诸如gzipping所有发送到浏览器的资源之类的操作得到帮助,但是这样做(在某些情况下)会使您进一步远离实现后者。

希望以上所有这些都能有助于证明,仔细隔离的"实验室"测试不会反映出生产过程中会遇到的变量和问题,并且您必须先确定您的高水平目标是什么,然后才能做些什么来达到目标,然后再沿着微观/过早的优化路线走下地狱。


为了测试整个脚本在服务器上运行的速度,您可以使用很多工具。首先确保您的脚本(例如preg_match和strpos)必须输出相同的结果才能使测试合格。

你可以使用:

  • 性能测试
  • ApacheBench工具(参见示例)
  • 德泰尔
  • HTTP负载
  • 卷曲装载机
  • HTTPF
  • 围攻
  • 贝吉塔
  • 你使用的代码也很好,但是有一个更大的循环(比如1000000)


您将要了解xdebug,更具体地说,xdebug的分析功能。

基本上,启用profiler,每次加载网页时,它都会创建一个cachegrind文件,可以使用wincachegrind或kcachegrind读取该文件。

xdebug的配置可能有点困难,因此这里是我的php.ini的相关部分,供参考:

1
2
3
4
5
6
[XDebug]
zend_extension = h:\xampp\php\ext\php_xdebug-2.1.1-5.3-vc6.dll
xdebug.remote_enable=true
xdebug.profiler_enable_trigger=1
xdebug.profiler_output_dir=h:\xampp\cachegrind
xdebug.profiler_output_name=callgrind.%t_%R.out

以下是WincacheGrind中一个.out文件的截图:

enter image description here

这应该提供关于您的PHP脚本有多有效的详细信息。你想把花费时间最多的事情作为目标。例如,您可以将一个函数优化为花费一半的时间,但是您的工作会更好地优化一个在页面加载期间调用几十次(如果不是数百次)的函数。

如果你好奇的话,这只是我为自己写的CMS的旧版本。


尝试https://github.com/fotuzlab/appgati

它允许在代码中定义步骤,并在两个步骤之间报告时间、内存使用情况、服务器负载等。

类似:

1
2
3
4
5
6
7
8
    $appgati->Step('1');

    // Do some code ...

    $appgati->Step('2');

    $report = $appgati->Report('1', '2');
    print_r($report);

示例输出数组:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Array
(
    [Clock time in seconds] => 1.9502429962158
    [Time taken in User Mode in seconds] => 0.632039
    [Time taken in System Mode in seconds] => 0.024001
    [Total time taken in Kernel in seconds] => 0.65604
    [Memory limit in MB] => 128
    [Memory usage in MB] => 18.237907409668
    [Peak memory usage in MB] => 19.579357147217
    [Average server load in last minute] => 0.47
    [Maximum resident shared size in KB] => 44900
    [Integral shared memory size] => 0
    [Integral unshared data size] => 0
    [Integral unshared stack size] =>
    [Number of page reclaims] => 12102
    [Number of page faults] => 6
    [Number of block input operations] => 192
    [Number of block output operations] =>
    [Number of messages sent] => 0
    [Number of messages received] => 0
    [Number of signals received] => 0
    [Number of voluntary context switches] => 606
    [Number of involuntary context switches] => 99
)


我会研究xhprof。无论是在cli上运行还是通过另一个sapi(如fpm或fcgi,甚至是apache模块)运行,这都无关紧要。

关于xhprof,最好的部分是它甚至适合在生产中运行。与xdebug(上次我检查过)不一样的东西。xdebug对性能有影响,xhprof(我不会说没有)管理得更好。

我们经常使用xhprof收集真实流量的样本,然后从中分析代码。

从时间和其他方面来说,它并不是一个真正的基准,尽管它也能做到这一点。它使分析生产流量变得非常容易,然后深入到收集到的调用图中的PHP函数级别。

编译并加载扩展后,就可以开始在代码中使用以下代码进行分析:

1
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);

停止:

1
$xhprof_data = xhprof_disable();

然后将数据保存到一个文件或数据库中——无论什么都可以浮在您的船上,并且不会中断正常的运行时间。我们异步地将其推到S3以集中数据(以便能够看到所有服务器上的所有运行)。

GitHub上的代码包含一个xhprof_HTML文件夹,您可以将该文件夹转储到服务器上,并以最少的配置显示所收集的数据,然后开始向下钻取。

嗯!


把它放到一个for循环中,每做一件事1000000次,得到一个更实际的数字。并且只在您想要基准测试的代码之前启动计时器,然后在之后记录结束时间(即不要在session_start()之前启动计时器)。

此外,还要确保要基准测试的每个函数的代码都是相同的,除了要计时的函数。

脚本的执行方式(cronjob、来自命令行的php、apache等)不应该有什么不同,因为您只是在计时不同函数速度之间的相对差异。所以这个比例应该保持不变。

如果运行基准测试的计算机有许多其他事情正在进行,那么如果在运行基准测试时,另一个应用程序的CPU或内存使用率突然增加,这可能会影响基准测试的结果。但只要你有足够的资源在电脑上,我认为这不会是一个问题。


一个好的开始是使用xdebugs profilerhttp://xdebug.org/docs/profiler

也许这不是最容易设置和使用的东西,但是一旦你得到了它,数据的绝对量和易于查看是不可替代的。


注意PHP代码并与此链接进行交叉检查也很好,以确保您的代码本身不会潜在地干扰应用程序的性能。


埃里克,

你问自己的问题不对。如果脚本在15毫秒内执行,那么它的时间在很大程度上是不相关的。如果在共享服务上运行,则php映像激活将需要大约100毫秒,如果完全缓存在服务器上,则在脚本文件中读取大约30-50毫秒,如果从后端NAS场加载,则可能需要1秒或更长的时间。加载页面设备时的网络延迟会增加很多秒。

这里的主要问题是用户对加载时间的感知:在单击链接和获得完全呈现的页面之间,他或她需要等待多长时间。请看一下Google的页面速度(可以用作FF或Chrome扩展),以及page speed文档(可以深入讨论如何获得良好的页面性能)。遵循这些指导原则,努力让你的页面得分超过90/100。(谷歌主页的得分是99/100,我的博客也是如此)。这是获得良好用户感知性能的最佳方法。