Jak mogę zmierzyć szybkość kodu napisanego w PHP? [Zamknięte]


118

Jak mogę powiedzieć, która klasa z wielu (z których wszystkie wykonują tę samą pracę) wykonuje się szybciej? czy jest oprogramowanie do pomiaru tego?

Odpowiedzi:


195

Masz (przynajmniej) dwa rozwiązania:

Dość „naiwny” używa mikrotime (true) przed i po części kodu, aby sprawdzić, ile czasu minęło podczas jego wykonania; inne odpowiedzi mówiły to i już dawały przykłady, więc nie powiem więcej.

To dobre rozwiązanie, jeśli chcesz porównać kilka instrukcji; na przykład porównać dwa typy funkcji - lepiej zrobić to tysiące razy, aby upewnić się, że każdy „element zakłócający” jest uśredniony.

Coś takiego, więc jeśli chcesz wiedzieć, ile czasu zajmuje serializacja tablicy:

$before = microtime(true);

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

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

Nie jest idealny, ale przydatny, a jego konfiguracja nie zajmuje dużo czasu.



Innym rozwiązaniem, które działa całkiem nieźle, jeśli chcesz zidentyfikować, która funkcja zajmuje dużo czasu w całym skrypcie, jest użycie:

  • Pakiet Xdebug rozszerzeń do generowania danych dla profilowania skryptu
  • Oprogramowanie, które odczytuje dane dotyczące profilowania i przedstawia coś czytelnego. Znam trzy z nich:
    • Webgrind ; interfejs sieciowy ; powinien działać na dowolnym serwerze Apache + PHP
    • WinCacheGrind ; tylko w oknach
    • KCacheGrind ; prawdopodobnie tylko Linux i podobny do Linuksa; Przy okazji, to ten, który wolę

Aby uzyskać pliki profilowania, musisz zainstalować i skonfigurować Xdebug; spójrz na profilowanie skryptów PHP w dokumentacji.

Zwykle nie włączam profilera domyślnie (generuje dość duże pliki i spowalnia działanie) , ale korzystam z możliwości przesłania parametru o nazwie XDEBUG_PROFILEGET data, aby aktywować profilowanie tylko dla potrzebnej strony.
Część mojego php.ini związana z profilowaniem wygląda następująco:

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

(Przeczytaj dokumentację, aby uzyskać więcej informacji)

Ten zrzut ekranu pochodzi z programu C ++ w KcacheGrind: (źródło: sourceforge.net ) Otrzymasz dokładnie to samo ze skryptami PHP ;-) (Mam na myśli KCacheGrind; WinCacheGrind nie jest tak dobry jak KCacheGrind ... )http://kcachegrind.sourceforge.net/html/pics/KcgShot3Large.gif



To pozwala uzyskać widok piękny, co wymaga czasu w aplikacji - i to czasem zdecydowanie pomaga zlokalizować funkcję, która spowalnia wszystko w dół ^^

Zauważ, że Xdebug zlicza czas procesora spędzony przez PHP; kiedy PHP czeka na odpowiedź z bazy danych (na przykład), nie działa; tylko czekam. Więc Xdebug pomyśli, że żądanie DB nie zajmie dużo czasu!
Powinno to być sprofilowane na serwerze SQL, a nie w PHP, więc ...


Mam nadzieję, że to jest pomocne :-)
Miłej zabawy!


1
Istnieje wersja QCacheGrind dla systemu Windows :-) sourceforge.net/projects/qcachegrindwin
François Breton

43

Dla szybkich rzeczy robię to (w PHP):

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

Możesz także użyć programu profilującego, takiego jak http://xdebug.org/ .


2
Dla dodatkowej dokładności sugerowałbym (a) użycie pętli i uśrednienie czasu oraz (b) użycie oddzielnych plików dla każdej testowanej rzeczy. Jeśli masz kilka czasów w jednym skrypcie, ich kolejność może czasami mieć znaczenie.
DisgruntledGoat

9

Zrobiłem prostą klasę pomiaru czasu, może komuś się przyda:

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

}

Posługiwać się:

$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 


9

Aktualizacja 2020

Minęło wiele lat, odkąd ostatnio odpowiedziałem na to pytanie, więc pomyślałem, że zasługuje na aktualizację w krajobrazie APM.

  • AppDynamics zostało kupione przez Cisco i darmowe konto, które oferował, zostało usunięte z ich strony internetowej.
  • NewRelic obniżył ceny z 149 USD / miesiąc / host do 25 USD / miesiąc / host, aby konkurować z nowym graczem na rynku APM, Datadog, który oferuje 31 USD / miesiąc / host.
  • Funkcje Datadog APM są nadal lekkie i pozostawiają wiele do życzenia. Jednak widzę, jak będą je ulepszać i ulepszać przez następny rok.
  • Ruxit został kupiony przez Dynatrace. Nic dziwnego, ponieważ Ruxit jest zbudowany przez byłych pracowników Dynatrace. To pozwoliło firmie Dynatrace przekształcić się w model prawdziwie SaaS na lepsze. Jeśli chcesz, pożegnaj się z tym nieporęcznym klientem Java.
  • Dostępne są teraz również opcje bezpłatne / open source. Checkout Apache Skywalking, który jest bardzo popularny w Chinach wśród ich najlepszych firm technologicznych i PinPoint który oferuje wersję demonstracyjną, którą możesz wypróbować przed instalacją. Oba wymagają zarządzania hostingiem, więc przygotuj się na uruchomienie kilku maszyn wirtualnych i poświęć trochę czasu na instalację i konfigurację.
  • Nie wypróbowałem żadnego z tych rozwiązań APM typu open source, więc nie mogę ich polecić, jednak osobiście zarządzałem wdrażaniem wszystkich tych rozwiązań APM dla wielu organizacji, lokalnie lub w chmurze dla setek aplikacji / mikrousługi. Mogę więc śmiało powiedzieć, że nie możesz pomylić się z żadnym z dostawców, jeśli pasują do twojego rachunku.


Pierwotnie odpowiedział w październiku 2015

Oto bezpośrednia odpowiedź na Twoje pytanie

czy jest oprogramowanie do pomiaru tego?

Tak jest. Zastanawiam się, dlaczego nikt jeszcze o tym nie wspomniał. Chociaż odpowiedzi sugerowane powyżej wydają się w porządku do szybkiego sprawdzenia, ale nie są skalowalne na dłuższą metę lub dla większego projektu.

Dlaczego nie skorzystać z narzędzia do monitorowania wydajności aplikacji (APM), które zostało stworzone specjalnie do tego i nie tylko. Sprawdź NewRelic, AppDynamics, Ruxit (wszystkie mają bezpłatną wersję), aby monitorować czas wykonania, wykorzystanie zasobów, przepustowość każdej aplikacji do poziomu metody.


6

Jeśli chcesz szybko przetestować wydajność frameworka, możesz umieścić go w pliku index.php

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

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

Za każdym razem otrzymasz czas wykonania w milisekundach . Ponieważ mikrosekundy nie są zbyt przydatne w testowaniu przypadku struktury.



4

Chciałbym podzielić się z wami własną funkcją, której używam do pomiaru szybkości dowolnej istniejącej funkcji do 10 argumentów:

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;

}

Przykład

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

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

Zwroty

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

3

Jeśli jest to coś, co można przetestować poza kontekstem WWW, po prostu używam timepolecenia Unix .


3

Zend Studio ma wbudowaną obsługę profilowania przy użyciu XDebug lub ZendDebugger. Sprofiluje Twój kod, informując dokładnie, ile czasu zajęła każda funkcja. To fantastyczne narzędzie do ustalania, gdzie są Twoje wąskie gardła.


1

Możesz użyć podstawowych rzeczy, takich jak przechowywanie znaczników czasu lub mikrotime () przed i po operacji, aby obliczyć potrzebny czas. To łatwe, ale niezbyt dokładne. Może lepszym rozwiązaniem jest Xdebug , nigdy z nim nie pracowałem, ale wydaje się, że jest to najbardziej znany debugger / profiler PHP, jaki mogę znaleźć.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.