Suivi du temps d'exécution du script en PHP

289

PHP doit suivre la quantité de temps CPU qu'un script particulier a utilisé afin d'appliquer la limite max_execution_time.

Existe-t-il un moyen d'accéder à cela à l'intérieur du script? Je voudrais inclure une journalisation avec mes tests sur la quantité de CPU brûlée dans le PHP réel (le temps n'est pas incrémenté lorsque le script est assis et attend la base de données).

J'utilise une box Linux.

twk
la source

Réponses:

237

Sur les systèmes unixoïdes (et dans php 7+ sur Windows également), vous pouvez utiliser getrusage , comme:

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

Notez que vous n'avez pas besoin de calculer une différence si vous générez une instance php pour chaque test.

phihag
la source
La valeur à la fin doit-elle être soustraite de la valeur au début du script? Je reçois des chiffres vraiment étranges si je ne le fais pas. Comme une page qui a mis 0,05 seconde à générer, cela dit qu'il a fallu 6s de temps CPU ... Voir ici: blog.rompe.org/node/85
Darryl Hein
@Darryl Hein: Oh, et vous obtenez des résultats étranges parce que vous utilisez la concaténation de chaînes au lieu de l'addition;)
phihag
@phihag me donne également des moments étranges, qu'une page a pris 40 secondes en calculs mais chargée en 2 secondes. Le nombre a tendance à sauter entre 1,4 seconde et 40 secondes
Timo Huovinen
1
@TimoHuovinen Quelles valeurs obtenez-vous exactement pour l' heure d'horloge murale utime/ stime/? Et pouvez-vous publier un lien vers un exemple reproductible qui montre ce comportement? Sur quelle version OS / php / version webserver êtes-vous? Dans tous les cas, vous voudrez peut-être publier une nouvelle question et un lien vers celle-ci ici.
phihag du
4
Ajout d'une petite mise à jour: cette fonction est désormais également prise en charge sous Windows.
ankush981
522

Si tout ce dont vous avez besoin est le temps d'horloge murale, plutôt que le temps d'exécution du CPU, alors il est simple de calculer:

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

Notez que cela inclura le temps pendant lequel PHP est assis à attendre des ressources externes telles que des disques ou des bases de données, qui n'est pas utilisé pour max_execution_time.

talal7860
la source
38
Salut - cela suit le «temps d'horloge» - pas le temps CPU.
twk
18
Parfait, je cherchais une solution de suivi du temps d'horloge murale.
samiles
118

Version plus courte de la réponse 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);

Comme indiqué, il s'agit du «temps d'horloge murale» et non du «temps processeur»

C. Lee
la source
74

La façon la plus simple:

<?php

$time1 = microtime(true);

//script code
//...

$time2 = microtime(true);
echo 'script execution time: ' . ($time2 - $time1); //value in seconds
joan16v
la source
9
en quoi est-ce différent de la réponse de talal7860 ...?
benomatis
@webeno Il ne divise pas par 60.. Aucune différence en effet.
A1rPun
[comment 2] comment cette réponse n'a pas de downvotes? c'est la même chose que la réponse ci-dessus.
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";
?>
Joyal
la source
Je n'ai pas obtenu le résultat en quelques secondes
Vous devriez utiliser PHP 5.4.0
Joyal
29

J'ai créé une classe ExecutionTime à partir de la réponse phihag que vous pouvez utiliser hors de la boîte:

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

usage:

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

Remarque: En PHP 5, la fonction getrusage ne fonctionne que dans les systèmes Unix-oid. Depuis PHP 7, il fonctionne également sous Windows.

Hamid Tavakoli
la source
2
Remarque: sous Windows getrusagene fonctionne que depuis PHP 7.
Martin van Driel
@MartinvanDriel J'ai joint la note. Merci
Hamid Tavakoli
3
Je suppose que si vous mettez début dans le constructeur et fin dans la chaîne de caractères, chaque utilisation aurait besoin de 2 lignes de code en moins. +1 pour OOP
toddmo
13

Gringod sur developerfusion.com donne cette bonne réponse:

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

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

lencho patasplanas
la source
11

Cela va être plus joli si vous formatez la sortie des secondes comme:

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

imprimera

Process took 6.45 seconds.

C'est bien mieux que

Process took 6.4518549156189 seconds.
Sinan Eldem
la source
9

La façon la moins chère et la plus sale de le faire est simplement de passer des microtime()appels aux endroits de votre code que vous souhaitez comparer. Faites-le juste avant et juste après les requêtes de base de données et il est simple de supprimer ces durées du reste du temps d'exécution de votre script.

Un conseil: votre temps d'exécution PHP va rarement être la chose qui fait expirer votre script. Si un script arrive à expiration, il s'agit presque toujours d'un appel à une ressource externe.

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

danieltalsky
la source
8

Je pense que vous devriez regarder xdebug. Les options de profilage vous donneront une longueur d'avance pour connaître de nombreux éléments liés au processus.

http://www.xdebug.org/

Stewart Robinson
la source
1
Assurez-vous simplement de ne pas installer xdebug sur un serveur de production avec beaucoup de sites Web. Il produit une énorme quantité de journalisation et peut submerger un petit disque SSD.
Corgalore
8

Pour afficher les minutes et les secondes, vous pouvez utiliser:

    $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
la source
2

J'ai écrit une fonction qui vérifie le temps d'exécution restant.

Avertissement: le comptage du temps d'exécution est différent sur Windows et sur la plate-forme 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);
}

En utilisant:

while (true) {
    // so something

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

$_SERVER['REQUEST_TIME']

vérifiez cela aussi. c'est à dire

...
// your codes running
...
echo (time() - $_SERVER['REQUEST_TIME']);
T.Todua
la source
intéressant $_SERVER['REQUEST_TIME']est également disponible dans php-cli (où il n'y a pas de serveur)
hanshenrik Il y a
1

Vous voudrez peut-être seulement connaître le temps d'exécution de certaines parties de votre script. La façon la plus flexible de chronométrer des parties ou un script entier est de créer 3 fonctions simples (code procédural donné ici mais vous pouvez le transformer en classe en mettant autour de lui le minuteur de classe {} et en faisant quelques ajustements). Ce code fonctionne, il suffit de copier-coller et d'exécuter:

$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
la source
0

Développant davantage la réponse de Hamid, j'ai écrit une classe d'aide qui peut être démarrée et arrêtée à plusieurs reprises (pour le profilage dans une boucle).

   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
la source
-1

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

ICP
la source