Làm cách nào để đo tốc độ mã được viết bằng PHP? [đóng cửa]


118

Làm cách nào để nói lớp nào trong số nhiều lớp (tất cả đều làm cùng một công việc) thực thi nhanh hơn? là có một phần mềm để đo lường điều đó?

Câu trả lời:


195

Bạn có (ít nhất) hai giải pháp:

Cái khá "ngây thơ" đang sử dụng microtime (true) trước và sau một phần mã, để biết thời gian đã trôi qua trong quá trình thực thi nó; những câu trả lời khác đã nói điều đó và đã đưa ra ví dụ, vì vậy tôi sẽ không nói nhiều nữa.

Đây là một giải pháp tốt nếu bạn muốn đánh giá một vài hướng dẫn; chẳng hạn như so sánh hai loại hàm - sẽ tốt hơn nếu được thực hiện hàng nghìn lần, để đảm bảo bất kỳ "phần tử nhiễu loạn" nào đều được tính trung bình.

Một cái gì đó như thế này, vì vậy, nếu bạn muốn biết mất bao lâu để tuần tự hóa một mảng:

$before = microtime(true);

for ($i=0 ; $i<100000 ; $i++) {
    serialize($list);
}

$after = microtime(true);
echo ($after-$before)/$i . " sec/serialize\n";

Không hoàn hảo, nhưng hữu ích và không mất nhiều thời gian để thiết lập.



Giải pháp khác, hoạt động khá tốt nếu bạn muốn xác định chức năng nào mất nhiều thời gian trong toàn bộ tập lệnh, là sử dụng:

  • Phần mở rộng Xdebug , để tạo dữ liệu cấu hình cho tập lệnh
  • Phần mềm đọc dữ liệu hồ sơ và hiển thị cho bạn thứ gì đó có thể đọc được. Tôi biết ba trong số đó:
    • Webgrind ; giao diện web ; sẽ hoạt động trên bất kỳ máy chủ Apache + PHP nào
    • WinCacheGrind ; chỉ trên cửa sổ
    • KCacheGrind ; có lẽ chỉ Linux và giống linux; Đó là cái tôi thích hơn, btw

Để có được các tệp cấu hình, bạn phải cài đặt và cấu hình Xdebug; hãy xem trang Cấu hình PHP Scripts của tài liệu.

Những gì tôi thường làm là không bật trình biên dịch theo mặc định (nó tạo ra các tệp khá lớn và làm chậm mọi thứ) , nhưng sử dụng khả năng gửi một tham số được gọi XDEBUG_PROFILElà dữ liệu GET, để kích hoạt cấu hình chỉ cho trang tôi cần.
Phần liên quan đến hồ sơ của php.ini của tôi trông như thế này:

xdebug.profiler_enable = 0              ; Profiling not activated by default
xdebug.profiler_enable_trigger = 1      ; Profiling activated when requested by the GET parameter
xdebug.profiler_output_dir = /tmp/ouput_directory
xdebug.profiler_output_name = files_names

(Đọc tài liệu để biết thêm thông tin)

Ảnh chụp màn hình này là từ một chương trình C ++ trong KcacheGrind: http://kcachegrind.sourceforge.net/html/pics/KcgShot3Large.gif
(source: sourceforge.net )

Bạn sẽ nhận được điều tương tự với các tập lệnh PHP ;-)
(Ý tôi là với KCacheGrind; WinCacheGrind không tốt bằng KCacheGrind ... )

Điều này cho phép bạn để có được một cái nhìn tốt đẹp của những gì phải mất thời gian trong ứng dụng của bạn - và đôi khi nó chắc chắn là giúp xác định vị trí các chức năng đó đang chậm lại tất cả mọi thứ xuống ^^

Lưu ý rằng Xdebug tính thời gian CPU dành cho PHP; khi PHP đang đợi câu trả lời từ Cơ sở dữ liệu (ví dụ), nó không hoạt động; chỉ chờ đợi. Vì vậy, Xdebug sẽ nghĩ rằng yêu cầu DB không mất nhiều thời gian!
Điều này phải được cấu hình trên máy chủ SQL, không phải PHP, vì vậy ...


Hy vọng điều này là hữu ích :-)
Chúc bạn vui vẻ!


1
Có một bản dựng windows của QCacheGrind :-) sourceforge.net/projects/qcachegrindwin
François Breton

43

Đối với những thứ nhanh chóng, tôi làm điều này (bằng PHP):

$startTime = microtime(true);
doTask(); // whatever you want to time
echo "Time:  " . number_format(( microtime(true) - $startTime), 4) . " Seconds\n";

Bạn cũng có thể sử dụng một hồ sơ như http://xdebug.org/ .


2
Để có thêm độ chính xác, tôi đề xuất (a) sử dụng vòng lặp và tính trung bình thời gian và (b) sử dụng các tệp riêng biệt cho từng thứ bạn đang thử nghiệm. Nếu bạn có nhiều thời gian trong một tập lệnh, thứ tự của chúng đôi khi có thể tạo ra sự khác biệt.
DisgruntledGoat

9

Tôi đã tạo một lớp định thời gian đơn giản, có thể nó hữu ích cho ai đó:

class TimingHelper {

    private $start;

    public function __construct() {
        $this->start = microtime(true);
    }

    public function start() {
        $this->start = microtime(true);
    }

    public function segs() {
        return microtime(true) - $this->start;
    }

    public function time() {
        $segs = $this->segs();
        $days = floor($segs / 86400);
        $segs -= $days * 86400;
        $hours = floor($segs / 3600);
        $segs -= $hours * 3600;
        $mins = floor($segs / 60);
        $segs -= $mins * 60;
        $microsegs = ($segs - floor($segs)) * 1000;
        $segs = floor($segs);

        return 
            (empty($days) ? "" : $days . "d ") . 
            (empty($hours) ? "" : $hours . "h ") . 
            (empty($mins) ? "" : $mins . "m ") . 
            $segs . "s " .
            $microsegs . "ms";
    }

}

Sử dụng:

$th = new TimingHelper();
<..code being mesured..>
echo $th->time();
$th->start(); // if it's the case
<..code being mesured..>
echo $th->time();

// result: 4d 17h 34m 57s 0.00095367431640625ms 

Bạn gõ sai: đó là echo, không$echo
Sun

9

Cập nhật năm 2020

Đã nhiều năm kể từ lần cuối cùng tôi trả lời câu hỏi này vì vậy tôi nghĩ đây xứng đáng là một bản cập nhật về bối cảnh APM.

  • AppDynamics đã được Cisco mua lại và tài khoản vĩnh viễn miễn phí mà họ sử dụng để cung cấp đã bị xóa khỏi trang web của họ.
  • NewRelic đã giảm giá từ $ 149 / tháng / máy chủ xuống 25 $ / tháng / máy chủ để cạnh tranh với người mới tham gia thị trường APM, Datadog, cung cấp $ 31 / tháng / máy chủ.
  • Các tính năng của Datadog APM vẫn còn nhẹ và còn nhiều điều đáng mong đợi. Tuy nhiên, tôi thấy họ tăng cường và cải thiện những điều này trong suốt năm tới.
  • Ruxit đã được mua bởi Dynatrace. Không có gì gây sốc ở đây vì Ruxit được xây dựng bởi các nhân viên cũ của Dynatrace. Điều này cho phép Dynatrace chuyển đổi sang mô hình SaaS thực sự tốt hơn. Nói lời tạm biệt với ứng dụng Java cồng kềnh đó nếu bạn muốn.
  • Hiện cũng có các tùy chọn mã nguồn mở / miễn phí. Kiểm tra Apache Skywalking rất phổ biến ở Trung Quốc trong số các công ty công nghệ hàng đầu của họ và PinPoint cung cấp bản demo mà bạn có thể thử trước khi cài đặt. Cả hai điều này đều yêu cầu bạn quản lý máy chủ lưu trữ, vì vậy hãy sẵn sàng sử dụng một số Máy ảo và dành chút thời gian cài đặt và cấu hình.
  • Tôi chưa thử một trong hai giải pháp APM nguồn mở này vì vậy tôi không có tư cách đề xuất chúng, tuy nhiên, cá nhân tôi đã quản lý việc triển khai tất cả các giải pháp APM này cho nhiều tổ chức, tại chỗ hoặc trên đám mây cho hàng trăm ứng dụng / microservices. Vì vậy, tôi có thể tự tin nói rằng, bạn không thể phạm sai lầm với bất kỳ nhà cung cấp nào nếu họ phù hợp với hóa đơn của bạn.


Được trả lời ban đầu vào tháng 10 năm 2015

Đây là câu trả lời trực tiếp cho câu hỏi của bạn

là có một phần mềm để đo lường điều đó?

Có, có. Tôi đang thắc mắc sao vẫn chưa thấy ai nhắc đến. Mặc dù các câu trả lời được đề xuất ở trên có vẻ tốt để kiểm tra nhanh nhưng không thể mở rộng về lâu dài hoặc cho một dự án lớn hơn.

Tại sao không sử dụng một công cụ Giám sát Hiệu suất Ứng dụng (APM) được xây dựng chính xác cho điều đó và hơn thế nữa. Kiểm tra NewRelic, AppDynamics, Ruxit (tất cả đều có phiên bản miễn phí) để theo dõi thời gian thực thi, sử dụng tài nguyên, thông lượng của mọi ứng dụng ở cấp phương pháp.


6

Nếu bạn muốn thực hiện thử nghiệm nhanh của một khuôn khổ, bạn có thể đặt trong index.php tập tin

//at beginning
$milliseconds = round(microtime(true) * 1000);

//and at the end
echo round(microtime(true) * 1000) - $milliseconds;

Mỗi lần bạn sẽ nhận được thời gian thực hiện tính bằng mili giây . Bởi vì micro giây không quá hữu ích trong việc thử nghiệm một trường hợp khung.



4

Tôi muốn chia sẻ với bạn một hàm tự tạo mà tôi sử dụng để đo tốc độ của bất kỳ hàm hiện có nào lên đến 10 đối số:

function fdump($f_name='', $f_args=array()){

    $f_dump=array();
    $f_result='';

    $f_success=false;

    $f_start=microtime();
    $f_start=explode(' ', $f_start);
    $f_start=$f_start[1] + $f_start[0];

    if(function_exists($f_name)){

        if(isset($f_args[0])&&is_array($f_args[0])){
            if($f_result=$f_name($f_args)){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[1])){
            if($f_result=$f_name($f_args[0])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[2])){
            if($f_result=$f_name($f_args[0],$f_args[1])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[3])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[4])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[5])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[6])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[7])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5],$f_args[6])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[8])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5],$f_args[6],$f_args[7])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[9])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5],$f_args[6],$f_args[7],$f_args[8])){
                $f_success=true;
            }
        }
        elseif(!isset($f_args[10])){
            if($f_result=$f_name($f_args[0],$f_args[1],$f_args[2],$f_args[3],$f_args[4],$f_args[5],$f_args[6],$f_args[7],$f_args[8],$f_args[9])){
                $f_success=true;
            }
        }
    }
    $f_end=microtime();
    $f_end=explode(' ', $f_end);
    $f_end=$f_end[1] + $f_end[0];

    $f_time=round(($f_end - $f_start), 4);
    $f_dump['f_success']=$f_success;
    $f_dump['f_time']=$f_time;
    $f_dump['f_result']=$f_result;

    var_dump($f_dump);exit;

    //return $f_result;

}

Thí dụ

function do_stuff($arg1='', $arg2=''){
    return $arg1.' '.$arg2;
}

fdump('do_stuff',array('hello', 'world'));

Lợi nhuận

  array(3) {
    ["f_success"]=>
    bool(true)
    ["f_time"]=>
    float(0)            //too fast...
    ["f_result"]=>
    string(11) "hello world"
  }

3

Nếu đó là thứ có thể được kiểm tra bên ngoài ngữ cảnh Web, tôi chỉ cần sử dụng timelệnh Unix .


3

Zend Studio đã tích hợp sẵn hỗ trợ cho việc lập hồ sơ bằng XDebug hoặc ZendDebugger. Nó sẽ lập hồ sơ mã của bạn, cho bạn biết chính xác thời gian mọi chức năng diễn ra. Đó là một công cụ tuyệt vời để tìm ra điểm nghẽn của bạn.


1

Bạn có thể sử dụng những thứ cơ bản như lưu trữ dấu thời gian hoặc microtime () trước và sau một thao tác để tính thời gian cần thiết. Điều đó dễ thực hiện, nhưng không chính xác lắm. Có thể một giải pháp tốt hơn là Xdebug , tôi chưa bao giờ làm việc với nó nhưng nó có vẻ là trình gỡ lỗi / cấu hình PHP nổi tiếng nhất mà tôi có thể tìm thấy.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.