Verfolgen der Skriptausführungszeit in PHP

289

PHP muss die CPU-Zeit verfolgen, die ein bestimmtes Skript verwendet hat, um das Limit für max_execution_time durchzusetzen.

Gibt es eine Möglichkeit, innerhalb des Skripts darauf zuzugreifen? Ich möchte meinen Tests einige Protokollierungen hinzufügen, wie viel CPU im eigentlichen PHP verbrannt wurde (die Zeit wird nicht erhöht, wenn das Skript sitzt und auf die Datenbank wartet).

Ich benutze eine Linux-Box.

twk
quelle

Antworten:

237

Auf unixoiden Systemen (und in PHP 7+ auch unter Windows) können Sie getrusage verwenden , wie:

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

Beachten Sie, dass Sie keine Differenz berechnen müssen, wenn Sie für jeden Test eine PHP-Instanz erzeugen.

Phihag
quelle
Sollte der Wert am Ende vom Wert am Anfang des Skripts abgezogen werden? Ich bekomme ein paar wirklich komische Zahlen, wenn ich das nicht tue. Wie eine Seite, deren Generierung 0,05 Sekunden gedauert hat, sagt, dass sie 6 Sekunden CPU-Zeit benötigt hat ... ist das richtig? Siehe hier: blog.rompe.org/node/85
Darryl Hein
@ Darryl Hein: Oh, und Sie erhalten seltsame Ergebnisse, weil Sie String-Verkettung anstelle von Addition verwenden;)
Phihag
@phihag Gibt mir auch komische Zeiten, dass eine Seite 40 Sekunden in Berechnungen dauerte, aber in 2 Sekunden geladen wurde. Die Zahl neigt dazu, zwischen 1,4 Sekunden und 40 Sekunden zu springen
Timo Huovinen
1
@ TimoHuovinen Welche Werte erhalten Sie genau für utime/ stime/ Wanduhrzeit ? Und können Sie einen Link zu einem reproduzierbaren Beispiel veröffentlichen , das dieses Verhalten zeigt? Auf welcher OS / PHP-Version / Webserver-Version sind Sie? In jedem Fall möchten Sie möglicherweise eine neue Frage stellen und hier darauf verlinken.
Phihag
4
Nur ein kleines Update hinzufügen: Diese Funktion wird jetzt auch unter Windows unterstützt.
ankush981
522

Wenn Sie lediglich die Wanduhrzeit und nicht die CPU-Ausführungszeit benötigen, ist die Berechnung einfach:

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

Beachten Sie, dass dies die Zeit einschließt, in der PHP auf externe Ressourcen wie Festplatten oder Datenbanken wartet, die nicht für max_execution_time verwendet werden.

talal7860
quelle
38
Hallo - dies verfolgt die 'Wanduhrzeit' - nicht die CPU-Zeit.
Twk
18
Perfekt, ich suchte nach einer Wanduhr-Zeiterfassungslösung.
Tamilen
118

Kürzere Version der Antwort von 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);

Wie bereits erwähnt, ist dies "Wanduhrzeit" und nicht "CPU-Zeit".

C. Lee
quelle
74

Der einfachste Weg:

<?php

$time1 = microtime(true);

//script code
//...

$time2 = microtime(true);
echo 'script execution time: ' . ($time2 - $time1); //value in seconds
joan16v
quelle
9
Wie unterscheidet sich das von der Antwort von talal7860 ...?
Benomatis
@webeno Er teilt nicht durch 60.. Kein Unterschied in der Tat.
A1rPun
[wie 2] wie hat diese Antwort keine Downvotes? es ist das gleiche wie oben Antwort.
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
quelle
Ich habe das Ergebnis nicht in Sekunden bekommen
Sie sollten PHP 5.4.0
Joyal
29

Ich habe eine ExecutionTime-Klasse aus einer Phihag-Antwort erstellt, die Sie sofort verwenden können:

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

Verwendung:

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

Hinweis: In PHP 5 funktioniert die Funktion getrusage nur in Unix-oid-Systemen. Seit PHP 7 funktioniert es auch unter Windows.

Hamid Tavakoli
quelle
2
Hinweis: Unter Windows getrusagefunktioniert nur seit PHP 7.
Martin van Driel
@ MartinvanDriel Ich habe die Notiz angehängt. Vielen Dank
Hamid Tavakoli
3
Ich denke, wenn Sie start in den Konstruktor setzen und end in the tostring setzen, würde jede Verwendung 2 Codezeilen weniger benötigen. +1 für OOP
Toddmo
13

Gringod von developerfusion.com gibt diese gute Antwort:

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

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

lencho patasplanas
quelle
11

Es wird schöner, wenn Sie die Sekundenausgabe wie folgt formatieren:

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

wird gedruckt

Process took 6.45 seconds.

Das ist viel besser als

Process took 6.4518549156189 seconds.
Sinan Eldem
quelle
9

Der billigste und schmutzigste Weg, dies zu tun, besteht darin, einfach microtime()an Stellen in Ihrem Code zu telefonieren, die Sie als Benchmark verwenden möchten. Wenn Sie dies direkt vor und direkt nach Datenbankabfragen tun, können Sie diese Dauer einfach aus dem Rest Ihrer Skriptausführungszeit entfernen.

Ein Hinweis: Ihre PHP-Ausführungszeit ist selten das, was Ihr Skript-Timeout verursacht. Wenn ein Skript eine Zeitüberschreitung aufweist, wird fast immer eine externe Ressource aufgerufen.

PHP-Microtime-Dokumentation: http://us.php.net/microtime

danieltalsky
quelle
8

Ich denke, Sie sollten sich xdebug ansehen. Die Profilierungsoptionen verschaffen Ihnen einen Vorsprung bei der Kenntnis vieler prozessbezogener Elemente.

http://www.xdebug.org/

Stewart Robinson
quelle
1
Stellen Sie nur sicher, dass Sie xdebug nicht auf einem Produktionsserver mit vielen Websites installieren. Es erzeugt eine enorme Menge an Protokollierung und kann ein kleines SSD-Laufwerk überfordern.
Corgalore
8

Um Minuten und Sekunden anzuzeigen, können Sie Folgendes verwenden:

    $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
quelle
2

Ich habe eine Funktion geschrieben, die die verbleibende Ausführungszeit überprüft.

Warnung: Die Zählung der Ausführungszeit ist unter Windows und Linux unterschiedlich.

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

Verwenden von:

while (true) {
    // so something

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

Möglicherweise möchten Sie nur die Ausführungszeit von Teilen Ihres Skripts kennen. Die flexibelste Möglichkeit, Teile oder ein gesamtes Skript zu zeitigen, besteht darin, drei einfache Funktionen zu erstellen (hier angegebener Prozedurcode, aber Sie können ihn in eine Klasse verwandeln, indem Sie den Klassen-Timer {} darum legen und einige Änderungen vornehmen). Dieser Code funktioniert, einfach kopieren und einfügen und ausführen:

$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
quelle
1

$_SERVER['REQUEST_TIME']

Schau dir das auch an. dh

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

Um Hamids Antwort weiter auszubauen, habe ich eine Hilfsklasse geschrieben, die wiederholt gestartet und gestoppt werden kann (zum Profilieren innerhalb einer Schleife).

   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
quelle
-1

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

ICP
quelle