为了强制执行max_execution_time限制,PHP必须跟踪特定脚本所使用的CPU时间。
是否有一种方法可以在脚本中访问它?我希望在测试中包含一些关于实际PHP中消耗了多少CPU的日志记录(当脚本等待数据库时,时间不会增加)。
我用的是Linux机顶盒。
为了强制执行max_execution_time限制,PHP必须跟踪特定脚本所使用的CPU时间。
是否有一种方法可以在脚本中访问它?我希望在测试中包含一些关于实际PHP中消耗了多少CPU的日志记录(当脚本等待数据库时,时间不会增加)。
我用的是Linux机顶盒。
当前回答
我创建了一个ExecutionTime类的phihag答案,你可以使用开箱即用:
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\nIt spent " . $this->runTime($this->endTime, $this->startTime, "stime") .
" ms in system calls\n";
}
}
用法:
$executionTime = new ExecutionTime();
$executionTime->start();
// code
$executionTime->end();
echo $executionTime;
注意:在PHP 5中,getrusage函数只适用于类unix系统。从PHP 7开始,它也可以在Windows上工作。
其他回答
developerfusion.com的Gringod给出了一个很好的答案:
<!-- 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/)
进一步扩展Hamid的回答,我写了一个可以重复启动和停止的helper类(用于在循环中进行分析)。
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\n" .
"It spent " . $this->systemTime . " ms in system calls\n";
}
}
我想说的是:
如果测量目标是不同php文件中的两点A和B,会发生什么? 如果我们需要不同的度量,比如基于时间、代码执行持续时间、外部资源访问持续时间,该怎么办? 如果我们需要将我们的度量组织成不同的类别,每个类别都有不同的起点,那该怎么办呢?
正如你怀疑的那样,我们需要一些全局变量来被类对象或静态方法访问:我选择第二种方法,它是:
namespace g3;
class Utils {
public function __construct() {}
public static $UtilsDtStart = [];
public static $UtilsDtStats = [];
public static function dt() {
global $UtilsDtStart, $UtilsDtStats;
$obj = new \stdClass();
$obj->start = function(int $ndx = 0) use (&$UtilsDtStart) {
$UtilsDtStart[$ndx] = \microtime(true) * 1000;
};
$obj->codeStart = function(int $ndx = 0) use (&$UtilsDtStart) {
$use = \getrusage();
$UtilsDtStart[$ndx] = ($use["ru_utime.tv_sec"] * 1000) + ($use["ru_utime.tv_usec"] / 1000);
};
$obj->resourceStart = function(int $ndx = 0) use (&$UtilsDtStart) {
$use = \getrusage();
$UtilsDtStart[$ndx] = $use["ru_stime.tv_usec"] / 1000;
};
$obj->end = function(int $ndx = 0) use (&$UtilsDtStart, &$UtilsDtStats) {
$t = @$UtilsDtStart[$ndx];
if($t === null)
return false;
$end = \microtime(true) * 1000;
$dt = $end - $t;
$UtilsDtStats[$ndx][] = $dt;
return $dt;
};
$obj->codeEnd = function(int $ndx = 0) use (&$UtilsDtStart, &$UtilsDtStats) {
$t = @$UtilsDtStart[$ndx];
if($t === null)
return false;
$use = \getrusage();
$dt = ($use["ru_utime.tv_sec"] * 1000) + ($use["ru_utime.tv_usec"] / 1000) - $t;
$UtilsDtStats[$ndx][] = $dt;
return $dt;
};
$obj->resourceEnd = function(int $ndx = 0) use (&$UtilsDtStart, &$UtilsDtStats) {
$t = @$UtilsDtStart[$ndx];
if($t === null)
return false;
$use = \getrusage();
$dt = ($use["ru_stime.tv_usec"] / 1000) - $t;
$UtilsDtStats[$ndx][] = $dt;
return $dt;
};
$obj->stats = function(int $ndx = 0) use (&$UtilsDtStats) {
$s = @$UtilsDtStats[$ndx];
if($s !== null)
$s = \array_slice($s, 0);
else
$s = false;
return $s;
};
$obj->statsLength = function() use (&$UtilsDtStats) {
return \count($UtilsDtStats);
};
return $obj;
}
}
现在你所要做的就是调用属于特定类别的方法,索引表示它的唯一组:
File A
------
\call_user_func_array(\g3\Utils::dt()->start, [0]); // point A
...
File B
------
$dt = \call_user_func_array(\g3\Utils::dt()->end, [0]); // point B
值$dt包含点A和点B之间壁钟持续时间的毫秒数。
估算php代码运行所花费的时间:
File A
------
\call_user_func_array(\g3\Utils::dt()->codeStart, [1]); // point A
...
File B
------
$dt = \call_user_func_array(\g3\Utils::dt()->codeEnd, [1]); // point B
注意我们是如何改变传递给方法的索引的。
代码基于从函数返回对象/函数时发生的闭包效应(参见示例中重复的\g3\Utils::dt())。
我用php单元进行了测试,在同一测试文件中的不同测试方法之间,到目前为止它表现良好!
希望这能帮助到别人!
如果你需要的是挂钟时间,而不是CPU执行时间,那么计算起来很简单:
//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 '<b>Total Execution Time:</b> '.$execution_time.' Mins';
// if you get weird results, use number_format((float) $execution_time, 10)
注意,这将包括PHP等待外部资源(如磁盘或数据库)的时间,而max_execution_time没有使用这个时间。
在页面底部居中打印的小脚本,在服务器调用时以微秒精度开始脚本执行。
为了不扭曲结果,并与页面中的内容100%兼容,我使用浏览器端本地javascript代码段在页面上编写结果。
//Uncomment the line below to test with 2 seconds
//usleep(2000000);
$prec = 5; // numbers after comma
$time = number_format(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], $prec, '.', '');
echo "<script>
if(!tI) {
var tI=document.createElement('div');
tI.style.fontSize='8px';
tI.style.marginBottom='5px';
tI.style.position='absolute';
tI.style.bottom='0px';
tI.style.textAlign='center';
tI.style.width='98%';
document.body.appendChild(tI);
}
tI.innerHTML='$time';
</script>";
另一种方法是使代码片段尽可能小,并使用样式表中的类对其进行样式化。
替换回显…;与以下部分分开: echo "<script>if(!tI){var tI=document.createElement('div');tI. classname ='ldtme';document.body.appendChild(tI);}tI. innerhtml ='$time'; 在CSS中创建并填充.ldtme{…}类。