Monitoraggio del tempo di esecuzione dello script in PHP


289

PHP deve tenere traccia della quantità di tempo della CPU utilizzata da un determinato script per imporre il limite max_execution_time.

C'è un modo per accedere a questo all'interno dello script? Vorrei includere alcune registrazioni con i miei test su quanta CPU è stata bruciata nel PHP effettivo (il tempo non viene incrementato quando lo script è in attesa e in attesa del database).

Sto usando una scatola Linux.

Risposte:


237

Sui sistemi unixoid (e anche in php 7+ su Windows), puoi usare getrusage , come:

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

Nota che non devi calcolare una differenza se stai generando un'istanza php per ogni test.


Il valore alla fine deve essere sottratto dal valore all'inizio dello script? Sto ottenendo dei numeri davvero strani se non lo faccio. Come una pagina che ha impiegato 0,05 secondi per generare, sta dicendo che ci sono voluti 6 secondi di tempo CPU ... è corretto? Vedi qui: blog.rompe.org/node/85
Darryl Hein il

@Darryl Hein: Oh, e ottieni strani risultati perché stai usando la concatenazione di stringhe invece dell'aggiunta;)
phihag

@phihag Mi dà anche strani momenti, in cui una pagina ha impiegato 40 secondi nei calcoli ma è stata caricata in 2 secondi. Il numero tende a saltare tra 1,4 secondi e 40 secondi
Timo Huovinen,

1
@TimoHuovinen Quali valori ottieni esattamente per utime/ stime/ l'ora dell'orologio da parete? E puoi pubblicare un link a un esempio riproducibile che mostra questo comportamento? Su quale versione di OS / php / versione web server sei? In ogni caso, potresti voler pubblicare una nuova domanda e collegarti qui.
phihag,

4
Basta aggiungere un piccolo aggiornamento: questa funzione è ora supportata anche su Windows.
ankush981,

522

Se tutto ciò che serve è il tempo dell'orologio da parete, piuttosto che il tempo di esecuzione della CPU, è semplice calcolare:

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

Tieni presente che ciò includerà il tempo in cui PHP è in attesa di risorse esterne come dischi o database, che non viene utilizzato per max_execution_time.


38
Salve, questo tiene traccia del "tempo del wallclock", non del tempo della CPU.
twk,

18
Perfetto, stavo cercando una soluzione per il monitoraggio del tempo degli orologi a muro.
samiles

118

Versione più breve della risposta di 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);

Come sottolineato, questo è "tempo di wallclock" non "tempo di CPU"


74

La via più facile:

<?php

$time1 = microtime(true);

//script code
//...

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

9
in cosa differisce dalla risposta di talal7860 ...?
benomatis,

@webeno Non divide per 60.. Nessuna differenza.
A1rPun

[come 2] come questa risposta non ha alcun voto negativo? è uguale alla risposta sopra.
T.Todua,

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

Non ho ottenuto il risultato in pochi secondi

Dovresti usare PHP 5.4.0
Joyal

29

Ho creato una classe ExecutionTime dalla risposta phihag che puoi usare immediatamente:

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

utilizzo:

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

Nota: in PHP 5, la funzione getrusage funziona solo nei sistemi Unix-oid. Da PHP 7, funziona anche su Windows.


2
Nota: su Windows getrusagefunziona solo da PHP 7.
Martin van Driel

@MartinvanDriel Ho aggiunto la nota. Grazie
Hamid Tavakoli il

3
Immagino che se metti inizio nel costruttore e finisci nel tostring, ogni utilizzo richiederebbe 2 righe di codice in meno. +1 per OOP
toddmo il

13

Gringod su developerfusion.com dà questa buona risposta:

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

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


11

Sarà più bello se si formatta l'output dei secondi come:

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

stamperà

Process took 6.45 seconds.

Questo è molto meglio di

Process took 6.4518549156189 seconds.

9

Il modo più economico e più sporco per farlo è semplicemente effettuare microtime()chiamate nei punti del codice che si desidera confrontare. Fallo subito prima e subito dopo le query del database ed è semplice rimuovere quelle durate dal resto del tempo di esecuzione dello script.

Un suggerimento: il tempo di esecuzione di PHP raramente sarà la cosa che rende il timeout dello script. Se uno script scade, sarà quasi sempre una chiamata a una risorsa esterna.

Documentazione PHP microtime: http://us.php.net/microtime


8

Penso che dovresti guardare xdebug. Le opzioni di profilazione ti daranno un vantaggio per conoscere molti elementi relativi al processo.

http://www.xdebug.org/


1
Assicurati di non installare xdebug su un server di produzione con molti siti Web. Produce un'enorme quantità di registrazione e può sopraffare un piccolo disco SSD.
Corgalore,

8

Per mostrare minuti e secondi puoi usare:

    $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

2

Ho scritto una funzione che controlla i tempi di esecuzione rimanenti.

Avvertenza: il conteggio dei tempi di esecuzione è diverso su Windows e su piattaforma 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.
    }
}

1

Potresti voler conoscere solo i tempi di esecuzione di parti del tuo script. Il modo più flessibile per eseguire il time part o un intero script è quello di creare 3 semplici funzioni (codice procedurale indicato qui, ma è possibile trasformarlo in una classe inserendo il timer di classe {} e apportando un paio di modifiche). Questo codice funziona, basta copiare e incollare ed eseguire:

$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

$_SERVER['REQUEST_TIME']

controlla anche quello. vale a dire

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


0

Espandendo ulteriormente la risposta di Hamid, ho scritto una classe di supporto che può essere avviata e interrotta ripetutamente (per la creazione di profili all'interno di un ciclo).

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

-1

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.