Rastreando o tempo de execução do script em PHP

289

O PHP deve rastrear a quantidade de tempo da CPU que um script específico usou para aplicar o limite de max_execution_time.

Existe uma maneira de obter acesso a isso dentro do script? Gostaria de incluir alguns registros nos meus testes sobre a quantidade de CPU que foi queimada no PHP real (o tempo não é incrementado quando o script está parado e aguardando o banco de dados).

Eu estou usando uma caixa Linux.

twk
fonte

Respostas:

237

Em sistemas unixóides (e também no php 7+ no Windows), você pode usar getrusage , como:

// 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\n";
echo "It spent " . rutime($ru, $rustart, "stime") .
    " ms in system calls\n";

Observe que você não precisa calcular a diferença se estiver gerando uma instância de php para cada teste.

phihag
fonte
O valor no final deve ser subtraído do valor no início do script? Estou recebendo números realmente estranhos, se não o faço. Como uma página que levou 0,05 segundos para gerar está dizendo que levou 6s de tempo de CPU ... isso está correto? Veja aqui: blog.rompe.org/node/85
Darryl Hein
@Darryl Hein: Ah, e você terá resultados estranhos porque você está usando concatenação em vez de adição;)
phihag
@phihag Também me dá momentos estranhos: uma página demorou 40 segundos em cálculos, mas carregada em 2 segundos. O número tende a saltar entre 1,4 segundos e 40 segundos
Timo HUOVINEN
1
@TimoHuovinen Que valores você recebe exatamente para utime/ stime/ hora do relógio de parede? E você pode postar um link para um exemplo reproduzível que mostra esse comportamento? Em qual versão do OS / php / versão do servidor da web você está? De qualquer forma, você pode postar uma nova pergunta e criar um link para ela aqui.
phihag
4
Apenas adicionando uma pequena atualização: Agora, esta função também é suportada no Windows.
precisa saber é o seguinte
522

Se tudo o que você precisa é o tempo do relógio de parede, em vez do tempo de execução da CPU, é simples calcular:

//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) 

Observe que isso incluirá tempo em que o PHP ficará aguardando recursos externos, como discos ou bancos de dados, que não serão utilizados para max_execution_time.

talal7860
fonte
38
Oi - isso rastreia o 'tempo do relógio de parede' - não o tempo da CPU.
Twk
18
Perfeito, eu estava procurando uma solução de rastreamento de tempo para relógios de parede.
samiles 16/11
118

Versão mais curta da resposta de talal7860

<?php
// At start of script
$time_start = microtime(true); 

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

Como apontado, este é o 'tempo do relógio de parede' e não o 'tempo da CPU'

C. Lee
fonte
74

A maneira mais fácil:

<?php

$time1 = microtime(true);

//script code
//...

$time2 = microtime(true);
echo 'script execution time: ' . ($time2 - $time1); //value in seconds
joan16v
fonte
9
como isso é diferente da resposta de talal7860 ...?
benomatis
@weno Ele não divide por 60.. Não há diferença mesmo.
A1rPun
[como 2] como esta resposta não tem votos negativos? é o mesmo da resposta acima.
T.Todua 18/03
36
<?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\n";
?>
Joyal
fonte
Eu não obter o resultado em segundos
Você deve usar o PHP 5.4.0
Joyal
29

Eu criei uma classe ExecutionTime a partir da resposta phihag que você pode usar fora da caixa:

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";
     }
 }

uso:

$executionTime = new ExecutionTime();
$executionTime->start();
// code
$executionTime->end();
echo $executionTime;

Nota: No PHP 5, a função getrusage funciona apenas em sistemas Unix-oid. Desde o PHP 7, ele também funciona no Windows.

Hamid Tavakoli
fonte
2
Nota: No Windows getrusagesó funciona desde o PHP 7.
Martin van Driel
@MartinvanDriel Anexei a nota. Graças
Hamid Tavakoli
3
Eu acho que se você colocar start no construtor e terminar no tostring, cada uso precisaria de 2 linhas a menos de código. +1 para OOP
toddmo 6/06/18
13

Gringod em developerfusion.com dá esta boa resposta:

<!-- 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"; 
;?>

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

lencho patasplanas
fonte
11

Será mais bonito se você formatar os segundos como:

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

irá imprimir

Process took 6.45 seconds.

Isso é muito melhor do que

Process took 6.4518549156189 seconds.
Sinan Eldem
fonte
9

A maneira mais barata e suja de fazer isso é simplesmente fazer microtime() chamadas nos locais do seu código que você deseja comparar. Faça isso antes e depois das consultas ao banco de dados e é simples remover essas durações do restante do tempo de execução do script.

Uma dica: o tempo de execução do PHP raramente será o que causa o tempo limite do script. Se um script atingir o tempo limite, quase sempre será uma chamada para um recurso externo.

Documentação sobre microtime do PHP: http://us.php.net/microtime

danieltalsky
fonte
8

Eu acho que você deveria olhar para o xdebug. As opções de criação de perfil fornecerão uma vantagem para conhecer muitos itens relacionados ao processo.

http://www.xdebug.org/

Stewart Robinson
fonte
1
Apenas certifique-se de não instalar o xdebug em um servidor de produção com muitos sites. Produz uma enorme quantidade de registros e pode sobrecarregar uma pequena unidade SSD.
Corgalore 7/03/15
8

Para mostrar minutos e segundos, você pode usar:

    $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
Aris
fonte
2

Eu escrevi uma função que verifica o tempo de execução restante.

Aviso: A contagem do tempo de execução é diferente na plataforma Windows e Linux.

/**
 * 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);
}

Usando:

while (true) {
    // so something

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

Você pode apenas querer saber o tempo de execução de partes do seu script. A maneira mais flexível de cronometrar partes ou um script inteiro é criar três funções simples (código de procedimento fornecido aqui, mas você pode transformá-lo em uma classe colocando o timer de classe {} em volta dele e fazendo alguns ajustes). Este código funciona, basta copiar e colar e executar:

$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');
JG Estiot
fonte
1

$_SERVER['REQUEST_TIME']

confira isso também. ie

...
// your codes running
...
echo (time() - $_SERVER['REQUEST_TIME']);
T.Todua
fonte
0

Expandindo ainda mais a resposta de Hamid, escrevi uma classe auxiliar que pode ser iniciada e interrompida repetidamente (para criação de perfil dentro de um loop).

   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";
      }
   }
Oded
fonte
-1

microtime de retorno (true) - $ _SERVER ["REQUEST_TIME_FLOAT"];

ICP
fonte