379 Stimmen

Verfolgung der Skriptausführungszeit in PHP

PHP muss die Menge an CPU-Zeit verfolgen, die ein bestimmtes Skript verbraucht hat, um das Limit max_execution_time durchzusetzen.

Gibt es eine Möglichkeit, innerhalb des Skripts Zugriff darauf zu erhalten? Ich möchte einige Protokollierung mit meinen Tests über wie viel CPU in der tatsächlichen PHP verbrannt wurde (die Zeit wird nicht erhöht, wenn das Skript sitzt und wartet auf die Datenbank).

Ich verwende einen Linux-Rechner.

7voto

T.Todua Punkte 48569

$_SERVER['REQUEST_TIME']

Überprüfen Sie das auch, z.B.

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

6voto

Mukarram Ishaq Punkte 640

Wenn es in PHP eine Schließungsfunktion gibt, warum sollten wir nicht davon profitieren?

function startTime(){
    $startTime = microtime(true);
    return function () use ($startTime){
        return microtime(true) - $startTime;
    };
}

Mit Hilfe der obigen Funktion können wir nun die Zeit wie folgt verfolgen

$stopTime = startTime();
//some code block or line
$elapsedTime = $stopTime();

Jeder Aufruf an startTime Funktion wird eine separate Zeiterfassung initiiert. Sie können also so viele Zeiterfassungen initiieren, wie Sie wollen, und sie an jeder beliebigen Stelle stoppen.

3voto

Meloman Punkte 3120

Kleines Skript, das unten auf der Seite zentriert die Skriptausführung ausgibt, die beim Serveraufruf gestartet wurde mit Mikrosekundengenauigkeit .

Um das Ergebnis nicht zu verfälschen und um 100% kompatibel mit dem Inhalt der Seite zu sein, habe ich für das Ergebnis auf der Seite ein browser-seitiges natives Javascript-Snippet verwendet.

//Uncomment the line below to test with 2 seconds 
//usleep(2000000);

$prec = 5; // numbers after comma
$time = number_format(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], $prec, '.', '');
echo "<script>
    if(!tI) { 
        var tI=document.createElement('div');
        tI.style.fontSize='8px';
        tI.style.marginBottom='5px';
        tI.style.position='absolute';
        tI.style.bottom='0px';
        tI.style.textAlign='center';
        tI.style.width='98%';
        document.body.appendChild(tI);
    }
    tI.innerHTML='$time';
</script>";

Ein anderer Ansatz besteht darin, das Snippet so klein wie möglich zu machen und es mit einer Klasse in Ihrem Stylesheet zu gestalten.

  1. Ersetzen Sie die echo ...; Teil mit dem Folgenden:

    echo "<script>if(!tI){var tI=document.createElement('div');tI.className='ldtme';document.body.appendChild(tI);}tI.innerHTML='$time';</script>";

  2. In Ihrem CSS erstellen und füllen Sie die .ldtme{...} Klasse.

2voto

Oded Punkte 895

Um die Antwort von Hamid zu erweitern, habe ich eine Hilfsklasse geschrieben, die wiederholt gestartet und gestoppt werden kann (für die Profilerstellung 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";
      }
   }

1voto

centurian Punkte 1152

Ich möchte nur einen Beitrag zu diesem Gespräch leisten:

  • Was passiert, wenn die Messung auf zwei Punkte A und B in verschiedenen php-Dateien abzielt?

  • Was ist, wenn wir verschiedene Messungen benötigen, wie z. B. die Dauer der Codeausführung, die Dauer des Zugriffs auf externe Ressourcen?

  • Was ist, wenn wir unsere Messungen in Kategorien einteilen müssen, von denen jede einen anderen Ausgangspunkt hat?

Wie Sie vermuten, benötigen wir einige globale Variablen, auf die von einem Klassenobjekt oder einer statischen Methode zugegriffen werden kann: Ich habe mich für den 2. Ansatz entschieden und hier ist er:

namespace g3;

class Utils {
   public function __construct() {}

   public static $UtilsDtStart = [];
   public static $UtilsDtStats = [];

   public static function dt() {
      global $UtilsDtStart, $UtilsDtStats;
      $obj = new \stdClass();
      $obj->start = function(int $ndx = 0) use (&$UtilsDtStart) {
         $UtilsDtStart[$ndx] = \microtime(true) * 1000;
      };
      $obj->codeStart = function(int $ndx = 0) use (&$UtilsDtStart) {
         $use = \getrusage();
         $UtilsDtStart[$ndx] = ($use["ru_utime.tv_sec"] * 1000) + ($use["ru_utime.tv_usec"] / 1000);
      };
      $obj->resourceStart = function(int $ndx = 0) use (&$UtilsDtStart) {
         $use = \getrusage();
         $UtilsDtStart[$ndx] = $use["ru_stime.tv_usec"] / 1000;
      };
      $obj->end = function(int $ndx = 0) use (&$UtilsDtStart, &$UtilsDtStats) {
         $t = @$UtilsDtStart[$ndx];
         if($t === null)
            return false;
         $end = \microtime(true) * 1000;
         $dt = $end - $t;
         $UtilsDtStats[$ndx][] = $dt;
         return $dt;
      };
      $obj->codeEnd = function(int $ndx = 0) use (&$UtilsDtStart, &$UtilsDtStats) {
         $t = @$UtilsDtStart[$ndx];
         if($t === null)
            return false;
         $use = \getrusage();
         $dt = ($use["ru_utime.tv_sec"] * 1000) + ($use["ru_utime.tv_usec"] / 1000) - $t;
         $UtilsDtStats[$ndx][] = $dt;
         return $dt;
      };
      $obj->resourceEnd = function(int $ndx = 0) use (&$UtilsDtStart, &$UtilsDtStats) {
         $t = @$UtilsDtStart[$ndx];
         if($t === null)
            return false;
         $use = \getrusage();
         $dt = ($use["ru_stime.tv_usec"] / 1000) - $t;
         $UtilsDtStats[$ndx][] = $dt;
         return $dt;
      };
      $obj->stats = function(int $ndx = 0) use (&$UtilsDtStats) {
         $s = @$UtilsDtStats[$ndx];
         if($s !== null)
            $s = \array_slice($s, 0);
         else
            $s = false;
         return $s;
      };
      $obj->statsLength = function() use (&$UtilsDtStats) {
         return \count($UtilsDtStats);
      };
      return $obj;
   }
}

Jetzt müssen Sie nur noch die Methode aufrufen, die zu der spezifischen Kategorie mit dem Index gehört, der ihre eindeutige Gruppe bezeichnet:

File A
------
\call_user_func_array(\g3\Utils::dt()->start, [0]);   // point A
...
File B
------
$dt = \call_user_func_array(\g3\Utils::dt()->end, [0]);  // point B

Wert $dt enthält die Millisekunden der Wanduhrdauer zwischen den Punkten A und B.

Schätzung der Zeit, die für die Ausführung von PHP-Code benötigt wird:

File A
------
\call_user_func_array(\g3\Utils::dt()->codeStart, [1]);   // point A
...
File B
------
$dt = \call_user_func_array(\g3\Utils::dt()->codeEnd, [1]);  // point B

Beachten Sie, dass wir den Index geändert haben, den wir an die Methoden übergeben.

Der Code basiert auf dem Closure-Effekt, der auftritt, wenn wir ein Objekt/eine Funktion aus einer Funktion zurückgeben (siehe das \g3\Utils::dt() bei den Beispielen wiederholt).

Ich testete mit php unit und zwischen verschiedenen Testmethoden an der gleichen Testdatei verhält es sich gut so weit!

Hoffentlich hilft das jemandem!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X