Nierentowne profile php. Profilowanie i debugowanie aplikacji PHP przy użyciu xhprof i FirePHP. Optymalizacja kodu w oparciu o profilowanie danych

Dostępne jest rozszerzenie PHP o nazwie Xdebug, które pomaga w profilowaniu aplikacji PHP, a także debugowaniu w czasie wykonywania. Po uruchomieniu profilera dane wyjściowe są zapisywane w pliku w formacie binarnym o nazwie „cachegrind”. Na każdej platformie dostępne są aplikacje umożliwiające analizę tych plików. Do przeprowadzenia tego profilowania nie są konieczne żadne zmiany w kodzie aplikacji.

Aby włączyć profilowanie, zainstaluj rozszerzenie i dostosuj ustawienia php.ini. Niektóre dystrybucje Linuksa są dostarczane ze standardowymi pakietami (np. pakiet php-xdebug Ubuntu). W naszym przykładzie uruchomimy profil opcjonalnie w oparciu o parametr żądania. Dzięki temu możemy zachować ustawienia statyczne i włączyć profiler tylko w razie potrzeby.

# ustawienia php.ini # Ustaw na 1, aby włączyć je dla każdego żądania xdebug.profiler_enable = 0 # Użyjmy parametru GET/POST, aby włączyć profiler xdebug.profiler_enable_trigger = 1 # Wartość GET/POST, którą przekażemy pustą; for any value xdebug.profiler_enable_trigger_value = "" # Wyprowadź pliki cachegrind do /tmp, aby nasz system oczyścił je później xdebug.profiler_output_dir = "/tmp" xdebug.profiler_output_name = "cachegrind.out.%p"

Następnie użyj klienta sieciowego, aby wysłać żądanie do adresu URL aplikacji, który chcesz sprofilować, np.

Http://example.com/article/1?XDEBUG_PROFILE=1

W trakcie przetwarzania strona zapisze do pliku o nazwie podobnej do

/tmp/cachegrind.out.12345

Domyślnie liczba w nazwie pliku to identyfikator procesu, który go napisał. Można to skonfigurować za pomocą ustawienia xdebug.profiler_output_name.

Zauważ, że zapisze jeden plik dla każdego wykonywanego żądania/procesu PHP. Na przykład, jeśli chcesz przeanalizować wpis w formularzu, zostanie zapisany jeden profil dla żądania GET w celu wyświetlenia formularza HTML. Parametr XDEBUG_PROFILE będzie musiał zostać przekazany do kolejnego żądania POST, aby przeanalizować drugie żądanie, które przetwarza formularz. Dlatego podczas profilowania czasami łatwiej jest uruchomić polecenie curl bezpośrednio w celu wysłania formularza.

Analiza wyników

Po zapisaniu pamięć podręczna profilu może zostać odczytana przez aplikację taką jak lub Webgrind. PHPStorm, popularne środowisko PHP IDE, może również wyświetlać te dane profilowania.

Na przykład KCachegrind wyświetli informacje obejmujące:

  • Funkcje wykonane
  • Czas wywołania, zarówno sam, jak i łącznie z kolejnymi wywołaniami funkcji
  • Liczba wywołań każdej funkcji
  • Zadzwoń do wykresów
  • Linki do kodu źródłowego

Czego szukać

Oczywiście dostrajanie wydajności jest bardzo specyficzne dla przypadków użycia każdej aplikacji. Ogólnie rzecz biorąc, dobrze jest szukać:

  • Powtarzające się wywołania tej samej funkcji, których się nie spodziewasz. W przypadku funkcji przetwarzających dane i wysyłających zapytania do danych mogą to być doskonałe możliwości buforowania aplikacji.
  • Wolno działające funkcje. Gdzie aplikacja spędza najwięcej czasu? Największą korzyścią z dostrajania wydajności jest skupienie się na tych częściach aplikacji, które zajmują najwięcej czasu.

Notatka: Xdebug, a w szczególności jego funkcje profilowania, pochłaniają bardzo dużo zasobów i spowalniają wykonywanie PHP. Zaleca się, aby nie uruchamiać ich w środowisku serwera produkcyjnego.

Korzystając z systemów profilowania, możesz zbierać informacje o tym, które funkcje w kodzie PHP zużywają więcej czasu procesora i pamięci RAM, czyli identyfikować najwolniejsze i najbardziej wymagające pamięci miejsca w programie PHP.

xhprof

XHProf - profiler PHP opracowany przez Facebooka.

Instalacja:

Aptitude zainstaluj php-pear pecl zainstaluj xhprof-0.9.4 echo "extension=xhprof.so" > /etc/php5/mods-available/xhprof.ini ln -s /etc/php5/mods-available/xhprof.ini /etc /php5/conf.d/xhprof.ini uruchom ponownie apachectl

Pliki niezbędne do pracy znajdują się w katalogu /usr/share/php. Jednak nie wszystko, ale tylko z kodem PHP. Do normalnego wyświetlania raportów wymagane są jquery i css. Można je uzyskać z repozytorium github:

Klon Gita https://github.com/facebook/xhprof.git

Następnie dodaj linię do kodu skryptu PHP w miejscu, w którym powinno rozpocząć się zbieranie danych:

Xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);

Parametry zbierania danych podano w nawiasach. W takim przypadku zbierane będą dane dotyczące obciążenia procesora i wykorzystania pamięci RAM. Możliwa jest jeszcze jedna opcja XHPROF_FLAGS_NO_BUILTINS w przypadku użycia dane o funkcjach wbudowanych nie są zbierane.

$xhprof_data = xhprof_disable(); include_once "xhprof_lib/utils/xhprof_lib.php"; include_once "xhprof_lib/utils/xhprof_runs.php"; $xhprof_runs = nowy XHProfRuns_Default(); $run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_test"); echo "Raport: http://domain.tld/xhprof_html/index.php?run=$run_id&source=xhprof_test"; echo "\n";

W kolejce $run_id Cudzysłowy oznaczają nazwę profilu, którą można ustawić dowolnie.

Przetworzony wynik wygląda następująco:

Jeśli określisz parametr XHPROF_FLAGS_NO_BUILTINS widać, że liczba wywołań funkcji jest znacznie zmniejszona:

Tabela zawiera następujące informacje:

Połączenia- liczba wywołań funkcji,
Czas na ścianę- całkowity czas działania funkcji, uwzględniający czas oczekiwania na odpowiedź z zasobów zewnętrznych,
procesor- ile czasu zajęło przetwarzanie funkcji,
Użyj pamięci- ile pamięci RAM zostało wykorzystane,
Szczytowe wykorzystanie pamięci- szczytowe zużycie pamięci.

Modyfikatory to:

Zawiera- włącznie - uwzględnia wywołania innych funkcji z tej funkcji,
Wyłącznie- wyłączne - z wyłączeniem wywołań funkcji.

Dodatkowo nad tabelą znajduje się informacja o całkowitym czasie przetwarzania, wykorzystanej pamięci oraz liczbie wywołań funkcji.

Również XHProf pozwala na budowanie raportów różnicowych pomiędzy dwoma przebiegami, które są oznaczone kolorami czerwonym i zielonym. Dzięki tym raportom możesz uzyskać jasny obraz ulepszeń po każdej zmianie kodu.

Aby otrzymać taki raport należy skorzystać z takiego linku:

http://domain.tld/xhprof_html/index.php?run1=run_id1&run2=run_id2&source=xhprof_test

Gdzie run_id1 I run_id2- identyfikatory uruchomienia.

Jeśli zainstalujesz Grafwiz:

Aptitude zainstaluj graphviz

Istnieją również interfejsy internetowe innych firm dla profilera php xhprof, które korzystają z baz danych:

xDebug

xDebug- Debuger kodu PHP z możliwością profilowania, napisany przez Dericka Rethansa.

Instalacja:

Mniam, zainstaluj php5-xdebug

Następnie edytujemy konfigurację:

Nano /etc/php5/mods-available/xdebug.ini

dodając do niego linie:

Xdebug.profiler_enable = 1 xdebug.profiler_aggregate = Wł. xdebug.profiler_output_dir = /tmp

Tutaj włączamy profiler PHP i określamy katalog, w którym będą przechowywane profile. Profile są tworzone z nazwami takimi jak cachegrind.out.*

Istnieje klient WWW webgrind: https://github.com/jokkedk/webgrind. Nie działa to bardzo szybko, ale pozwala na szybkie przeglądanie małych profili. W rzeczywistości jest to kod PHP, który należy sklonować z githuba:

Klon Gita https://github.com/jokkedk/webgrind.git

zostanie utworzony katalog webgrind, który należy skopiować do katalogu dowolnej witryny internetowej i uzyskać do niego dostęp z poziomu przeglądarki. Następnie, aby kreślenie w pliku konfiguracyjnym działało w Debianie config.php musisz poprawić ścieżkę do pliku wykonywalnego grafwiz. To powinno wyglądać tak:

Statyczny $dotExecutable = "/usr/bin/dot";

Ponadto możesz dostosować strefę czasową:

Static $defaultTimezone = "Europa/Moskwa";

W nagłówku możesz wybrać profil i zaznaczyć pole, aby uwzględnić wbudowane funkcje. Sama tabela pokazuje funkcje, liczbę połączeń, czas działania samej funkcji i czas łącznie z oczekiwaniem. Aby wejść głębiej w funkcje, wystarczy kliknąć trójkątną strzałkę. W moim przypadku przy dość dużych profilach (od kilku megabajtów) czas oczekiwania na wynik był niepotrzebnie długi. W przypadku dość dużych profili prawdopodobnie lepiej jest używać lokalnych programów do przeglądania.

Wykres może wyglądać następująco:

zauważ to webgrind nie należy używać na serwerach produkcyjnych, ponieważ nie ma autoryzacji, ale jest dostęp do kodu pliku php. Jeśli to konieczne, użyj przynajmniej podstawowej autoryzacji Apache.

Istnieją również programy do analizy profili dla systemu Linux:

O profilowaniu

Dane profilowe mogą pomóc w ulepszeniu aplikacji, czyli osiągnięciu określonych celów, na przykład zmniejszeniu zużycia pamięci, skróceniu czasu generowania strony i tak dalej.

Informacje zawarte w profilu są punktem wyjścia do optymalizacji: mówią, ile czasu zajmuje wygenerowanie wyniku, ile pamięci jest wykorzystywane i ile jest wykonanych wywołań funkcji. Dzięki bardziej szczegółowym danym możesz poprawić te wskaźniki.

Na przykład, jeśli używasz frameworka, wówczas użycie niektórych funkcji frameworku może prowadzić do wywołań kilku podstawowych funkcji. Jeśli czytasz niektóre dane wielokrotnie, warto zapisać wynik w zmiennej.

Profiler może również pomóc Ci zrozumieć, gdzie używać buforowania kodu PHP, na przykład za pomocą APCu Lub memcached.

Przede wszystkim warto zoptymalizować funkcje, które wymagają najwięcej czasu wykonania. Gdy już wszystko jest zoptymalizowane i wydaje się, że nie ma już co poprawiać, warto posortować funkcje po liczbie połączeń i popracować nad jej zmniejszeniem. Nawet jeśli PHP jest szybkie, warto zastanowić się, czy funkcje nie muszą być wywoływane tak często?

Jeśli napotkasz następujące sytuacje, powinieneś rozważyć buforowanie:

  • Funkcje niezmienne wywoływane są wewnątrz pętli,
  • Niektóre treści są generowane dwukrotnie,
  • Za każdym razem generowana jest niezmienna treść,
  • Treść jest generowana, nawet jeśli nie jest używana.

Nie powinieneś buforować wszystkiego, ponieważ pamięć jest również cennym zasobem. Buforuj dane, do których stale uzyskujesz dostęp. Ponadto buforowanie nie ma większego sensu, jeśli marnuje więcej zasobów niż oszczędza.

Oprócz buforowania w kodzie nie zapomnij o buforowaniu za pomocą serwera WWW (), a także po stronie klienta. Jeśli użyjesz właściwych nagłówków, wiele żądań można obsłużyć, zanim w ogóle dotrą one do serwera.

FirePHP to rozszerzenie dla Firebuga, które w połączeniu z małą klasą php umożliwia rozgłaszanie danych z php, na przykład wszelkiego rodzaju var_dump i innych informacji debugowania, do konsoli Firebuga. Główną zaletą tego rozszerzenia jest to wszystkie informacje dotyczące debugowania są transmitowane poprzez nagłówki i nie zaśmiecają stron ani w żaden sposób nie łamią logiki aplikacji Oficjalna strona internetowa: http://firephp.org/.

Główny pomysł.

Ogólny algorytm profilowania wygląda następująco:
  1. Na początku strony umożliwiamy profilowanie za pomocą xhprof_enable()
  2. Na końcu strony wyłącz profilowanie za pomocą xhprof_disable() i zapisz zebrane dane za pomocą save_run()
  3. Następnie za pomocą klasy firephp php przekazujemy do części klienckiej link do danych profilowania
  4. W konsoli Firebuga otwieramy potrzebne nam informacje
  5. Cieszymy się :)
Chciałbym również powiedzieć, że oczywiście ręczne dodanie tych funkcji do skryptów PHP jest świetne. Chcę jednak, aby te informacje były zawsze pod ręką podczas tworzenia oprogramowania i nie trafiały na serwery produkcyjne. Rozwiązujemy ten problem w następujący sposób:

W naszych projektach prawie we wszystkich skryptach na początku podłączany jest działający plik z modułem ładującym klasy, funkcjami łączącymi i innymi niezbędnymi rzeczami. Dlatego też uwzględniliśmy w tym pliku uwzględnienie profilowania. Aby móc dowolnie włączać/wyłączać tryb debugowania, dodaliśmy kontrolę stałej konfiguracji, a ponadto umieściliśmy te kontrole w niektórych metatagach, które są automatycznie usuwane podczas budowania projektu. To samo tyczy się wyłączania profilowania i zapisywania informacji do nagłówków przy pomocy Firephp - zadania te rozwiązuje jedna funkcja, która wywoływana jest na końcu każdego skryptu PHP i dodatkowo jest opakowana w metatagi. Wygląda to mniej więcej tak:

// Następujące stałe są zapisywane w pliku konfiguracyjnym aplikacji

/** Tryb działania środowiska * */
zdefiniuj("APPLICATION_ENV" , "dev" ); // deweloper - debugowanie | pro - produkcja
/** Ścieżka do profilera */
zdefiniuj("XHPROF_ROOT" , __DIR__ . „/ExtProcs/debug/xhprof-0.9.2”);

/***************************************************************************************
* Następnie w pliku, który ładuje się na początku każdego skryptu, uruchamiamy profilowanie
* DEV_START i DEV_END to nasze metatagi, wszystko pomiędzy nimi jest wycinane podczas montażu
***************************************************************************************/

//-- DEV_START
//-- w trybie debugowania łączymy biblioteki debugowania

// Załaduj Firephp
require_once(__DIR__ . „/include/ExtProcs/debug/firephp/FirePHP.class.php”);
//-- załaduj profiler
„/xhprof_lib/utils/xhprof_lib.php”);
require_once(XHPROF_ROOT. „/xhprof_lib/utils/xhprof_runs.php”);
// Zainicjuj profilowanie za pomocą niezbędnych flag. Szczegółowy opis flag
// można znaleźć pod adresem php.net/manual/ru/xhprof.constants.php
xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
}
//-- DEV_END

// Cóż, ta funkcja jest wywoływana na końcu każdego skryptu
// Jego wywołanie jest również zawinięte w DEV_START i DEV_END

/**
* Utwórz link do wyniku profilowania i wyświetl go w konsoli
*/
funkcja dev_boot_Down() (
if (APPLICATION_ENV === "dev" ) (
// Zainicjuj instancję Firephp
$firephp = FirePHP::getInstance(true);
// Wyłącz profilowanie i zapisz dane
$xhprof_data = xhprof_disable();
$xhprof_runs = nowy XHProfRuns_Default();
$run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_testing" );
// Utwórz link do danych profilowania i zapisz go w konsoli
$link = "http://" . $_SERVER["HTTP_HOST"] . "/includes/ExtProcs/debug/xhprof-0.9.2/xhprof_html/index.php?run=($run_id)&source=xhprof_testing\n";
$firephp->info($link, "dane profilowania" );
}
}


* Ten kod źródłowy został wyróżniony za pomocą narzędzia Source Code Highlighter.

Nie będę wdawał się w szczegóły dotyczące instalowania tych rozszerzeń, ponieważ tutaj wszystko jest proste. Powiem tylko o niektórych aspektach konfiguracji. xhproof posiada tylko jedną zmienną konfiguracyjną - xhprof.output_dir, która wskazuje folder, w którym będą zapisywane dane profilowania. Dlatego upewnij się, że użytkownik, na którym wykonywane są skrypty PHP, ma prawa zapisu do określonego katalogu. Napisz więc coś takiego w swoim php.ini:


rozszerzenie=xhprof.so
xhprof.output_dir="/var/tmp/xhprof"

Dobrym pomysłem jest także zainstalowanie czegoś takiego jak kropka lub Graphviz, aby rysować wykresy połączeń. Mam Graphviz na MacOS X.

Po wykonaniu opisanych powyżej procedur mogliśmy w każdej chwili otworzyć i podejrzeć profilowanie dowolnego z naszych skryptów bezpośrednio w przeglądarce.

Instalowanie xhprof dla php:

Sudo apt-get install php5-xhprof

Uruchom ponownie Apache'a:

Uruchom ponownie usługę Sudo Apache2

Wydrukuj phpinfo(); i sprawdzić czy moduł jest podłączony czy nie?

Sprawdzamy plik /etc/php5/apache2/conf.d, aby zobaczyć, czy pojawia się tam link do konfiguracji xhprof.ini.

Jeśli nie, utwórz łącze samodzielnie i uruchom ponownie Apache.

Sudo ln -s /etc/php5/mods-available/xhprof.ini /etc/php5/apache2/conf.d/20-xhprof.ini sudo restart usługi Apache2

Sprawdzamy połączenie xhprof, sprawdzamy, czy 20-xhprof.ini jest podłączony:

Na zrzucie ekranu widać wersję 0.9.2, chociaż podczas instalacji wyświetliła się wersja 0.9.4, ale nie jest to dla nas przeszkodą.

Teraz możemy profilować nasz kod.

  1. Na początku strony włącz profilowanie za pomocą xhprof_enable();
  2. Na końcu strony wyłącz profilowanie za pomocą xhprof_disable() i zapisz zebrane dane za pomocą save_run();
  3. Następnie analizujemy.

Funkcjonować xhprof_enable() przyjmuje flagi jako argumenty:

XHPROF_FLAGS_CPU do rejestrowania statystyk procesora,

XHPROF_FLAGS_MEMORY - dla pamięci,

XHPROF_FLAGS_NO_BUILTINS - aby zignorować wbudowane funkcje.

Aby zapisać i dalej podsumować, musimy zainstalować narzędzie do analizy profilu.

Pobierz archiwum z narzędziem analitycznym ze strony xhprof:, pobierz wersję 0.9.4.

Na serwerze lub komputerze lokalnym utwórz folder dostępny poprzez localhost lub osobną domenę, do której rozpakujemy pobrane archiwum:

Teraz możemy zapisać profil.

https://xn--d1acnqm.xn--j1amh/altadmin/posts/edit/188

Kod śledzenia wygląda mniej więcej tak:

// Zainicjuj profiler - policzymy zarówno czas procesora, jak i zużycie pamięci xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY);
// Kod profilowany # Zatrzymaj profiler $xhprof_data = xhprof_disable(); # Zapisz raport i wygeneruj link do jego wyświetlenia. include_once "/var/www/html/xhprof-0.9.4/xhprof_lib/utils/xhprof_lib.php"; include_once "/var/www/html/xhprof-0.9.4/xhprof_lib/utils/xhprof_runs.php"; $xhprof_runs = nowy XHProfRuns_Default(); $run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_test"); echo "Raport: http://localhost/xhprof-0.9.4/xhprof_html/index.php?run=$run_id&source=xhprof_test"; echo "\n";

/var/www/html/xhprof-0.9.4 - ścieżka do folderu, w którym rozpakowaliśmy potrzebne biblioteki.

Raport: http://localhost/xhprof-0.9.4/xhprof_html/index.php?run=57c32f3095d21&source=xhprof_test

Tak wygląda analiza profilu. W tej tabeli wyświetlane są wszystkie profilowane wywołania funkcji.

Funkcje możemy sortować klikając na nagłówki tabeli.

Kiedy widzimy, że jakaś funkcja jest wykonywana wiele razy lub przez bardzo długi czas, możemy kliknąć tę funkcję i otworzy się podobna tabela, ale z wewnętrznymi wywołaniami wewnątrz danej funkcji i środowiskiem nadrzędnym, w którym funkcja została wywołana.

Wskaźniki:
Total Inc. Wall Time (czas spędzony na wykonywaniu funkcji, biorąc pod uwagę oczekiwanie na odpowiedzi z gniazd, systemu plików i innych zasobów)
Total Inc. Procesor (czas spędzony na wykonywaniu funkcji)
Total Inc. MemUse (zużycie pamięci)
Total Inc. PeakMemUse (szczytowe wykorzystanie pamięci)
Liczba wywołań funkcji

Istnieje również możliwość graficznego przedstawienia raportu. Ale aby to zrobić, musisz upewnić się, że masz zainstalowaną bibliotekę graphviz:

Apt-get install graphviz

Następnie w swoim profilu kliknij, aby wyświetlić i voila:

Teraz możesz analizować i ulepszać kod.