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.

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.


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.


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»


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

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

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.


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


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.

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


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/


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

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.
    }
}

2

$_SERVER['REQUEST_TIME']

vérifiez cela aussi. c'est à dire

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

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');


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

-1

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.