关于性能:在PHP中跟踪脚本执行时间

Tracking the script execution time in PHP

PHP必须跟踪特定脚本用于强制执行最大执行时间限制的CPU时间量。

有没有办法在脚本内部访问这个?我想在我的测试中包括一些日志记录,测试实际PHP中消耗了多少CPU(当脚本在等待数据库时,时间不会增加)。

我正在使用Linux设备。


如果您所需要的只是墙上的时钟时间,而不是CPU执行时间,那么很容易计算:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//place this before any script you want to calculate time
$time_start = microtime(true);

//sample script
for($i=0; $i<1000; $i++){
 //do anything
}

$time_end = microtime(true);

//dividing with 60 will give the execution time in minutes otherwise seconds
$execution_time = ($time_end - $time_start)/60;

//execution time of the script
echo 'Total Execution Time: '.$execution_time.' Mins';
// if you get weird results, use number_format((float) $execution_time, 10)

请注意,这将包括php在sat上等待外部资源(如磁盘或数据库)的时间,而这些资源不用于最大执行时间。


在unixoid系统上(以及在Windows上的php 7+中),您可以使用getrusage,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Script start
$rustart = getrusage();

// Code ...

// Script end
function rutime($ru, $rus, $index) {
    return ($ru["ru_$index.tv_sec"]*1000 + intval($ru["ru_$index.tv_usec"]/1000))
     -  ($rus["ru_$index.tv_sec"]*1000 + intval($rus["ru_$index.tv_usec"]/1000));
}

$ru = getrusage();
echo"This process used" . rutime($ru, $rustart,"utime") .
   " ms for its computations
"
;
echo"It spent" . rutime($ru, $rustart,"stime") .
   " ms in system calls
"
;

注意,如果要为每个测试生成一个PHP实例,则不需要计算差异。


塔拉尔7860答案的较短版本

1
2
3
4
5
6
<?php
// At start of script
$time_start = microtime(true);

// Anywhere else in the script
echo 'Total execution time in seconds: ' . (microtime(true) - $time_start);

如前所述,这是"WallClock时间",而不是"CPU时间"


最简单的方法:

1
2
3
4
5
6
7
8
9
<?php

$time1 = microtime(true);

//script code
//...

$time2 = microtime(true);
echo 'script execution time: ' . ($time2 - $time1); //value in seconds


1
2
3
4
5
6
7
8
9
10
11
<?php
// Randomize sleeping time
usleep(mt_rand(100, 10000));

// As of PHP 5.4.0, REQUEST_TIME_FLOAT is available in the $_SERVER superglobal array.
// It contains the timestamp of the start of the request with microsecond precision.
$time = microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"];

echo"Did nothing in $time seconds
"
;
?>


我在phihag answer中创建了一个ExecutionTime类,您可以使用现成的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class ExecutionTime
{
     private $startTime;
     private $endTime;

     public function start(){
         $this->startTime = getrusage();
     }

     public function end(){
         $this->endTime = getrusage();
     }

     private function runTime($ru, $rus, $index) {
         return ($ru["ru_$index.tv_sec"]*1000 + intval($ru["ru_$index.tv_usec"]/1000))
     -  ($rus["ru_$index.tv_sec"]*1000 + intval($rus["ru_$index.tv_usec"]/1000));
     }    

     public function __toString(){
         return"This process used" . $this->runTime($this->endTime, $this->startTime,"utime") .
       " ms for its computations
It spent"
. $this->runTime($this->endTime, $this->startTime,"stime") .
       " ms in system calls
"
;
     }
 }

用途:

1
2
3
4
5
$executionTime = new ExecutionTime();
$executionTime->start();
// code
$executionTime->end();
echo $executionTime;

Note: In PHP 5, the getrusage function only works in Unix-oid systems. Since PHP 7, it also works on Windows.


developerfusion.com的gringod给出了一个很好的答案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- put this at the top of the page -->
<?php
   $mtime = microtime();
   $mtime = explode("",$mtime);
   $mtime = $mtime[1] + $mtime[0];
   $starttime = $mtime;
;?>

<!-- put other code and html in here -->


<!-- put this code at the bottom of the page -->
<?php
   $mtime = microtime();
   $mtime = explode("",$mtime);
   $mtime = $mtime[1] + $mtime[0];
   $endtime = $mtime;
   $totaltime = ($endtime - $starttime);
   echo"This page was created in".$totaltime." seconds";
;?>

发件人(http://www.developerfusion.com/code/2058/determine-execution-time-in-php/)


最便宜和最脏的方法就是在代码中您想要基准测试的地方进行microtime()调用。在数据库查询之前和之后都要这样做,从脚本的其余执行时间中删除这些持续时间很简单。

提示:您的PHP执行时间很少会导致脚本超时。如果脚本超时,则几乎总是调用外部资源。

PHP微时间文档:http://us.php.net/microtime/微秒


我想你应该看看xdebug。分析选项将为您提供一个了解许多与流程相关的项目的开端。

网址:http://www.xdebug.org/


如果将秒输出格式设置为:

1
echo"Process took". number_format(microtime(true) - $start, 2)." seconds.";

将打印

1
Process took 6.45 seconds.

这比

1
Process took 6.4518549156189 seconds.

我编写了一个检查剩余执行时间的函数。

警告:Windows和Linux平台上的执行时间计数不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
 * Check if more that `$miliseconds` ms remains
 * to error `PHP Fatal error:  Maximum execution time exceeded`
 *
 * @param int $miliseconds
 * @return bool
 */

function isRemainingMaxExecutionTimeBiggerThan($miliseconds = 5000) {
    $max_execution_time = ini_get('max_execution_time');
    if ($max_execution_time === 0) {
        // No script time limitation
        return true;
    }
    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
        // On Windows: The real time is measured.
        $spendMiliseconds = (microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]) * 1000;
    } else {
        // On Linux: Any time spent on activity that happens outside the execution
        //           of the script such as system calls using system(), stream operations
        //           database queries, etc. is not included.
        //           @see http://php.net/manual/en/function.set-time-limit.php
        $resourceUsages = getrusage();
        $spendMiliseconds = $resourceUsages['ru_utime.tv_sec'] * 1000 + $resourceUsages['ru_utime.tv_usec'] / 1000;
    }
    $remainingMiliseconds = $max_execution_time * 1000 - $spendMiliseconds;
    return ($remainingMiliseconds >= $miliseconds);
}

使用:

1
2
3
4
5
6
7
8
while (true) {
    // so something

    if (!isRemainingMaxExecutionTimeBiggerThan(5000)) {
        // Time to die.
        // Safely close DB and done the iteration.
    }
}


您可能只想知道脚本部分的执行时间。对部分或整个脚本计时最灵活的方法是创建3个简单的函数(这里给出的过程代码,但是您可以通过在其周围放置类计时器并进行一些调整将其转换为类)。此代码有效,只需复制、粘贴并运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$tstart = 0;
$tend = 0;

function timer_starts()
{
global $tstart;

$tstart=microtime(true); ;

}

function timer_ends()
{
global $tend;

$tend=microtime(true); ;

}

function timer_calc()
{
global $tstart,$tend;

return (round($tend - $tstart,2));
}

timer_starts();
file_get_contents('http://google.com');
timer_ends();
print('It took '.timer_calc().' seconds to retrieve the google page');

要显示分钟和秒,可以使用:

1
2
3
4
5
6
    $startTime = microtime(true);
    $endTime = microtime(true);
    $diff = round($endTime - $startTime);
    $minutes = floor($diff / 60); //only minutes
    $seconds = $diff % 60;//remaining seconds, using modulo operator
    echo"script execution time: minutes:$minutes, seconds:$seconds"; //value in seconds

作为一种替代方法,您可以将这行代码放到代码块中,并检查PHP日志,对于非常慢的函数,它非常有用:

1
trigger_error("Task done at". strftime('%H:%m:%S', time()), E_USER_NOTICE);

要认真调试,请使用xdebug+cachegrind,请参阅https://blog.nextess.net/2011/01/29/diagnosing-slow-php-execution-with-xdebug-and-kcachegrind/


进一步扩展了Hamid的答案,我编写了一个助手类,可以反复启动和停止(用于在循环中进行分析)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
   class ExecutionTime
   {
      private $startTime;
      private $endTime;
      private $compTime = 0;
      private $sysTime = 0;

      public function Start(){
         $this->startTime = getrusage();
      }

      public function End(){
         $this->endTime = getrusage();
         $this->compTime += $this->runTime($this->endTime, $this->startTime,"utime");
         $this->systemTime += $this->runTime($this->endTime, $this->startTime,"stime");
      }

      private function runTime($ru, $rus, $index) {
         return ($ru["ru_$index.tv_sec"]*1000 + intval($ru["ru_$index.tv_usec"]/1000))
         -  ($rus["ru_$index.tv_sec"]*1000 + intval($rus["ru_$index.tv_usec"]/1000));
      }

      public function __toString(){
         return"This process used" . $this->compTime ." ms for its computations
"
.
               "It spent" . $this->systemTime ." ms in system calls
"
;
      }
   }

返回microtime(true)-$服务器[请求时间浮动];