ติดตามเวลาการเรียกใช้สคริปต์ใน PHP


289

PHP ต้องติดตามจำนวนเวลา CPU ที่สคริปต์เฉพาะใช้เพื่อบังคับใช้ขีด จำกัด max_execution_time

มีวิธีเข้าถึงสคริปต์นี้ภายในสคริปต์หรือไม่ ฉันต้องการรวมการบันทึกบางอย่างกับการทดสอบของฉันเกี่ยวกับจำนวน CPU ที่ถูกเผาใน PHP จริง (เวลาไม่เพิ่มขึ้นเมื่อสคริปต์กำลังนั่งและรอฐานข้อมูล)

ฉันใช้กล่อง Linux

คำตอบ:


238

ในระบบ unixoid (และใน php 7+ บน Windows เช่นกัน) คุณสามารถใช้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 สำหรับการทดสอบทุกครั้ง


ควรที่จะลบค่าตอนท้ายออกจากค่าเมื่อเริ่มต้นสคริปต์หรือไม่ ฉันจะได้ตัวเลขแปลก ๆ จริง ๆ ถ้าไม่ เช่นเดียวกับหน้าเว็บที่ใช้เวลา 0.05 วินาทีในการสร้างกำลังบอกว่าใช้เวลา CPU ถึง 6 วินาที ... ถูกต้องหรือไม่ ดูที่นี่: blog.rompe.org/node/85
Darryl Hein

@Darryl Hein: Oh, และคุณได้รับผลลัพธ์ที่แปลกเพราะคุณกำลังใช้ concatenation สตริงแทนนอกจากนี้;)
phihag

@phihag ให้เวลาฉันประหลาดด้วยเช่นกันหน้าเว็บใช้เวลาในการคำนวณ 40 วินาที แต่โหลดใน 2 วินาที จำนวนมีแนวโน้มที่จะกระโดดระหว่าง 1.4 วินาทีถึง 40 วินาที
Timo Huovinen

1
@TimoHuovinen คุณมีค่าเท่าไหร่สำหรับutime/ stime/ เวลานาฬิกาแขวน? และคุณสามารถโพสต์ลิงก์ไปยังตัวอย่างที่ทำซ้ำได้ซึ่งแสดงพฤติกรรมนี้หรือไม่? คุณเป็น OS / php version / webserver รุ่นใด ไม่ว่าในกรณีใดคุณอาจต้องการโพสต์คำถามใหม่และลิงก์ไปที่นี่
Phihag

4
เพียงแค่เพิ่มการอัพเดทเล็กน้อย: ตอนนี้ฟังก์ชั่นนี้รองรับบน Windows เช่นกัน
ankush981

522

หากสิ่งที่คุณต้องการคือเวลาของนาฬิกาแขวนแทนที่จะใช้เวลาประมวลผลของ 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


38
สวัสดี - สิ่งนี้ติดตาม 'เวลา wallclock' - ไม่ใช่เวลา CPU
twk

18
สมบูรณ์แบบฉันกำลังมองหาทางออกสำหรับการติดตามเวลาของวอลล์ล็อค
samiles

118

รุ่นที่สั้นกว่าสำหรับคำตอบของ 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);

ตามที่ระบุไว้นี่คือ 'เวลา wallclock' ไม่ใช่ 'เวลา cpu'


74

วิธีที่ง่ายที่สุด:

<?php

$time1 = microtime(true);

//script code
//...

$time2 = microtime(true);
echo 'script execution time: ' . ($time2 - $time1); //value in seconds

9
สิ่งนี้แตกต่างจากคำตอบของ talal7860 อย่างไร?
benomatis

@webeno เขาไม่ได้หารด้วย60.. ไม่มีความแตกต่างแน่นอน
A1rPun

[วิธีที่ 2] วิธีคำตอบนี้ไม่มี downvote ใด ๆ มันเหมือนกับคำตอบข้างต้น
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";
?>

ฉันไม่ได้ผลลัพธ์ในไม่กี่วินาที

คุณควรใช้ PHP 5.4.0
Joyal

29

ฉันสร้างคลาส ExecutionTime จากคำตอบ 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


2
หมายเหตุ: บน Windows ใช้getrusageงานได้ตั้งแต่ PHP 7
Martin van Driel

@MartinvanDriel ฉันผนวกบันทึกย่อ ขอบคุณ
ฮามิด Tavakoli

3
ฉันเดาว่าถ้าคุณใส่ start ใน constructor และสิ้นสุดใน tostring การใช้แต่ละครั้งจะต้องมีโค้ดน้อยกว่า 2 บรรทัด +1 สำหรับ OOP
toddmo

13

Gringod ที่ developerfusion.com ให้คำตอบที่ดีนี้:

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


11

มันจะสวยกว่านี้ถ้าคุณจัดรูปแบบเอาต์พุตวินาทีเช่น:

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

จะพิมพ์

Process took 6.45 seconds.

มันดีกว่า

Process took 6.4518549156189 seconds.

9

วิธีที่ถูกที่สุดและสกปรกที่สุดในการทำคือเพียงmicrotime()โทรหาสถานที่ในรหัสของคุณที่คุณต้องการมาตรฐาน ทำก่อนและหลังการสืบค้นฐานข้อมูลและง่ายต่อการลบระยะเวลาเหล่านั้นออกจากเวลาที่เหลือในการเรียกใช้สคริปต์ของคุณ

คำแนะนำ: เวลาดำเนินการ PHP ของคุณไม่ค่อยเป็นสิ่งที่ทำให้สคริปต์ของคุณหมดเวลา หากสคริปต์หมดเวลาการโทรไปยังทรัพยากรภายนอกจะเป็นการโทรออกเกือบตลอดเวลา

เอกสาร PHP microtime: http://us.php.net/microtime


8

ฉันคิดว่าคุณควรดู xdebug ตัวเลือกการทำโปรไฟล์จะช่วยให้คุณเริ่มรู้ถึงรายการที่เกี่ยวข้องกับกระบวนการจำนวนมาก

http://www.xdebug.org/


1
เพียงให้แน่ใจว่าคุณไม่ได้ติดตั้ง xdebug บนเซิร์ฟเวอร์การผลิตที่มีเว็บไซต์จำนวนมาก มันสร้างการบันทึกจำนวนมหาศาลและสามารถครอบงำไดรฟ์ SSD ขนาดเล็กได้
Corgalore

8

ในการแสดงนาทีและวินาทีที่คุณสามารถใช้:

    $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

ฉันเขียนฟังก์ชันที่ตรวจสอบเวลาดำเนินการที่เหลืออยู่

คำเตือน: การนับเวลาดำเนินการจะแตกต่างกันใน Windows และบนแพลตฟอร์ม 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.
    }
}

2

$_SERVER['REQUEST_TIME']

ตรวจสอบว่าเกินไป กล่าวคือ

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

น่าสนใจ$_SERVER['REQUEST_TIME']มีอยู่ใน php-cli (ที่ไม่มีเซิร์ฟเวอร์)
hanshenrik

1

คุณอาจต้องการทราบเวลาดำเนินการของสคริปต์บางส่วนเท่านั้น วิธีที่ยืดหยุ่นที่สุดในการแบ่งเวลาหรือสคริปต์ทั้งหมดคือการสร้างฟังก์ชั่นง่าย ๆ 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');

0

เป็นอีกทางเลือกหนึ่งที่คุณสามารถใส่บรรทัดนี้ในบล็อครหัสของคุณและตรวจสอบไฟล์บันทึก 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/


0

การขยายคำตอบของฮามิดเพิ่มเติมฉันเขียนคลาสผู้ช่วยที่สามารถเริ่มและหยุดซ้ำได้ (สำหรับการทำโปรไฟล์ภายในวง)

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.