source

PHP에서 스크립트 실행 시간 추적

manysource 2022. 10. 14. 22:12

PHP에서 스크립트 실행 시간 추적

PHP는 max_execution_time 제한을 적용하기 위해 특정 스크립트가 사용한 CPU 시간을 추적해야 합니다.

스크립트 내에서 이 정보에 접근할 수 있는 방법이 있나요?실제 PHP에 사용된 CPU의 양에 대한 테스트에 로깅을 포함시키고 싶습니다(스크립트가 데이터베이스를 대기하고 있을 때 시간은 증가하지 않습니다).

Linux 박스를 사용하고 있습니다.

필요한 것은 CPU 실행 시간이 아니라 벽 클럭 시간뿐이라면 다음과 같이 간단하게 계산할 수 있습니다.

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

은, 「PHP」에 사용되지 .max_execution_time.

unixoid 시스템(및 Windows의 php 7+)에서는 다음과 같은 getrusage를 사용할 수 있습니다.

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

모든 테스트에 대해 php 인스턴스를 생성할 경우 차이를 계산할 필요가 없습니다.

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

지적했듯이 이것은 'cpu time'이 아니라 'wallclock time'입니다.

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

실행을 작성했습니다.시간 클래스가 phihag에서 벗어나면 바로 사용할 수 있습니다.

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

사용방법:

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

주의: PHP 5에서 getrusage 기능은 Unix-oid 시스템에서만 작동합니다.PHP 7 이후 Windows에서도 동작합니다.

출력의 초수를 다음과 같이 포맷하면 더 예뻐집니다.

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

인쇄하다

Process took 6.45 seconds.

이것은 보다 훨씬 낫다.

Process took 6.4518549156189 seconds.

developerfusion.com의 Gringod는 다음과 같은 좋은 답변을 제공합니다.

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

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

사용할 수 있는 분 및 초를 표시하려면:

    $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

더러운 이다.microtime()벤치마킹하고 싶은 코드의 장소에서 콜을 실시합니다.데이터베이스 쿼리 직전과 직후에 실행할 수 있습니다.스크립트 실행 시간의 나머지 시간에서 이러한 기간을 쉽게 제거할 수 있습니다.

힌트: PHP 실행 시간이 스크립트 타임아웃을 만드는 경우는 거의 없습니다.스크립트가 타임아웃되면 거의 항상 외부 리소스에 대한 호출이 됩니다.

PHP 마이크로타임 매뉴얼:http://us.php.net/microtime

xdebug를 봐야 할 것 같아요.프로파일링 옵션을 사용하면 프로세스와 관련된 많은 항목을 미리 알 수 있습니다.

http://www.xdebug.org/

$_SERVER['REQUEST_TIME']

이것 좀 봐.

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

PHP에 클로징 기능이 있다면, 그 혜택을 보는 것은 어떨까요?

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

이제 위의 기능을 사용하여 이렇게 시간을 추적할 수 있습니다.

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

의 모든 콜startTime기능이 별도의 타임 트래커를 시작합니다.원하는 만큼 시작할 수 있고 원하는 곳이면 어디에서든 멈출 수 있습니다.

남은 실행 시간을 체크하는 기능을 작성했습니다.

경고:실행 시간 계산은 윈도우즈와 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);
}

사용방법:

while (true) {
    // so something

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

Hamid의 답변을 더 자세히 설명하자면, 시작과 중지를 반복할 수 있는 도우미 클래스를 작성했습니다(루프 내 프로파일링).

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

페이지 하단을 중심으로 서버 호출 시 시작된 스크립트 실행을 마이크로초 단위로 인쇄하는 작은 스크립트입니다.

결과를 왜곡하지 않고 페이지 내 콘텐츠와 100% 호환되도록 브라우저 측 네이티브 자바스크립트 스니펫을 사용하여 페이지에 결과를 작성하였습니다.

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

또 다른 접근법은 스니펫을 가능한 한 작게 만들고 스타일시트의 클래스로 스타일링하는 것입니다.

  1. 「 「 」를 교환해 .echo ...;다음을 포함합니다.

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

  2. 에서 CSS를 ..ldtme{...}를 누릅니다

스크립트의 일부 실행 시간만 알 수 있습니다.부품 또는 스크립트 전체를 시간화하는 가장 유연한 방법은 3개의 간단한 함수를 만드는 것입니다(여기에서는 프로시저 코드를 제공하지만 클래스 타이머 {}을(를) 주변에 배치하고 몇 가지 조정을 하면 클래스로 전환할 수 있습니다).이 코드는 동작합니다.복사하여 붙여넣기만 하면 됩니다.

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

이 대화에 참여하기 위해:

  • 측정이 다른 php 파일의 두 점 A와 B를 대상으로 하면 어떻게 됩니까?

  • 시간 기반, 코드 실행 기간, 외부 리소스 액세스 기간 등 다양한 측정이 필요한 경우 어떻게 해야 합니까?

  • 측정값을 각각 다른 시작점이 있는 범주로 구성해야 할 경우 어떻게 해야 할까요?

클래스 오브젝트 또는 스태틱메서드로 접근하려면 글로벌 변수가 필요합니다.두 번째 접근방식을 선택하면 다음과 같습니다.

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

이제 고유 그룹을 나타내는 인덱스를 사용하여 특정 범주에 속하는 메서드를 호출하기만 하면 됩니다.

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

가치$dt에 포인트 A와 포인트B 사이의 벽시계 지속시간(밀리초)을 나타냅니다.

php 코드를 실행하는 데 걸린 시간을 추정하려면:

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

메서드에서 전달되는 인덱스를 어떻게 변경했는지 확인하십시오.

코드는 함수에서 개체/함수를 반환할 때 발생하는 폐쇄 효과를 기반으로 합니다( 참조).\g3\Utils::dt()반복한다).

php 유닛과 같은 테스트 파일에서 다른 테스트 방법 간에 테스트를 해봤더니 지금까지 정상적으로 동작하고 있습니다!

그게 도움이 됐으면 좋겠네요!

다른 방법으로는 코드 블록에 이 행을 삽입하고 php 로그를 체크하는 것만으로 매우 느린 함수의 경우 매우 유용합니다.

trigger_error("Task done at ". strftime('%H:%m:%S', time()), E_USER_NOTICE); 

심각한 디버깅에 대해서는 XDebug + Cachegrind를 사용합니다.https://blog.nexcess.net/2011/01/29/diagnosing-slow-php-execution-with-xdebug-and-kcachegrind/ 를 참조해 주세요.

여기에는 다음과 같은 몇 가지 방법이 있습니다.하지만 각각 장단점이 있다.그리고 (내 생각에) 모든 더 긴 답변의 가독성은 형편없다.

그래서 저는 모든 것을 쉽게 사용할 수 있고 읽을 수 있는 하나의 답변으로 정리하기로 했습니다.

사용.

$start = get_timers();
for( $i = 0; $i < 100000; $i++ ){
  // Code to check
}
$end = get_timers();
display_timer_statistics( $start, $end );

함수 정의

function display_timer_statistics( $start_timers, $end_timers ){

    // Settings
    $key_width = '100px';
    $decimals = 4;
    $decimals_wallclock = $decimals;
    $decimals_request_time_float = $decimals;

    // Variables
    $start_resource_usage_timer = $start_timers[0];
    $start_wallclock = $start_timers[1];
    $end_resource_usage_timer = $end_timers[0];
    $end_wallclock = $end_timers[1];

    // # User time
    // Add seconds and microseconds for the start/end, and subtract from another
    $end_user_time_seconds = $end_resource_usage_timer["ru_utime.tv_sec"]*1000;
    $end_user_time_microseconds = intval($end_resource_usage_timer["ru_utime.tv_usec"]/1000);
    $start_user_time_seconds = $start_resource_usage_timer["ru_utime.tv_sec"]*1000;
    $start_user_time_microseconds = intval($start_resource_usage_timer["ru_utime.tv_usec"]/1000);
    $total_user_time = ($end_user_time_seconds + $end_user_time_microseconds) - ($start_user_time_seconds + $start_user_time_microseconds);

    // # System time
    // Add seconds and microseconds for the start/end, and subtract from another
    $end_system_time_seconds = $end_resource_usage_timer["ru_stime.tv_sec"]*1000;
    $end_system_time_microseconds = intval($end_resource_usage_timer["ru_stime.tv_usec"]/1000);
    $start_system_time_seconds = $start_resource_usage_timer["ru_stime.tv_sec"]*1000;
    $start_system_time_microseconds = intval($start_resource_usage_timer["ru_stime.tv_usec"]/1000);
    $total_system_time = ($end_system_time_seconds + $end_system_time_microseconds) - ($start_system_time_seconds + $start_system_time_microseconds);

    // Wallclock
    $total_wallclock_time = number_format( ( $end_wallclock - $start_wallclock), $decimals_wallclock );

    // Server request_time_float
    $request_time_float = microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"];
    $request_time_float = number_format( $request_time_float, $decimals_request_time_float );

    // Print
    $span_start = "<span style='width: $key_width; display: inline-block;'>";
    $span_end = "</span>";

    $output = "# RUNTIME AND TIMERS " . PHP_EOL ;
    $output .= PHP_EOL;
    $output .= $span_start . $total_user_time . $span_end . " User time (utime)" . PHP_EOL;
    $output .= $span_start . $total_system_time . $span_end . " System time (stime)" . PHP_EOL;
    $output .= PHP_EOL;
    $output .= $span_start . $total_wallclock_time . $span_end . " Wallclock" . PHP_EOL;
    $output .= PHP_EOL;
    $output .= $span_start . $request_time_float . $span_end . " REQUEST_TIME_FLOAT" . PHP_EOL . PHP_EOL . PHP_EOL;

    echo nl2br( $output );
}

function get_timers(){
    return [ getrusage(), microtime( true ) ];
}

용어집

모두 Getrusage를 위해 PHP 문서에서 가져온 것입니다.

  • 벽시계 = 소요시간
  • ru= 자원 사용량
  • utime=사용시간
  • stime= 시스템 사용시간
  • tv_sec=초 단위입니다.
  • tv_usec= 마이크로초 단위.
  • tv=?모르겠어.

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

언급URL : https://stackoverflow.com/questions/535020/tracking-the-script-execution-time-in-php