Disassembler

Artificial intelligence is no match for natural stupidity.
23října2011

Xdebug: Přehledný PHP debugger a profiler


Všechny své aplikace se snažím optimalizovat, jak nejlépe to jde. Občas se mi sice stane, že honba za rychlostí se změní přímo v posedlost, ale o pár dní a několik revertů později z mého snažení téměř vždy vzejde něco použitelného. PHP aplikace píšu optimalizované tak nějak „od pasu“ (a když ne přímo optimalizované, tak alespoň bez nějakých očividných bottlenecků), ale říkal jsem si, že by nebylo na škodu se i u nich pomocí nějakého profileru přesvědčit, zda se někde nedá vyždímat nějaká milisekunda k dobru.

Závod s časem


Slyšel jsem už tisíckrát moudra typu „Rychlost není důležitá. Důležité je, aby byl kód jednoduchý a přehledný“. To beru, za předpokladu, že se v kódu vrtá spousta lidí a je kladen důraz na srozumitelnost. Ale přehlednost a rychlost se přece nevylučuje. Když by někde mohl být polynomiální algoritmus, ale já tam mám exponenciální, tak je to prostě špatně, přehlednost nepřehlednost. A jelikož je mým denním chlebem správa Java Enterprise aplikací, je mi smutno vždycky, když vývojáři své počínání ospravedlňují slovy „Výpočetní výkon je levný“. Naštěstí je můj přístup přesně opačný. Nechci nechat uživatele čekat pět minut na vykreslení okna jen proto, že jsem líný aplikaci napsat pořádně. A totéž platí i u webových aplikací.

Xdebug + KCacheGrind


Hledal jsem tedy nějaký hezký a snadno použitelný PHP profiler. A našel jsem xdebug. Instaluje se jako klasické PHP rozšíření skrze PEAR/PECL. Na oficiálních stránkách má velmi slušně zpracovanou dokumentaci, takže nastavení profileru bylo otázkou dvou řádků v configu. Pak už zbývá jen restartovat HTTP server (resp. CGI/FastCGI) a může se vesele profilovat. Xdebugem vytvořené profily se pak dají otevřít a analyzovat v aplikaci zvané KCacheGrind. KCacheGrind zobrazí nasbíraná data v přehledných grafech a pavoucích a řekne vám, jak dlouho trvalo provádění té či oné funkce a odkud byla kolikrát volána. Obrázek vydá za tisíc slov.

xdebug profil v KCacheGrindu
xdebug profil v KCacheGrindu

Instalace a užití


Jak jsem již zmínil, samotný xdebug se instaluje jako PECL balíček

pecl install xdebug

Poté je třeba jej v php.ini nastavit jako Zend extenstion, nejlépe s absolutní cestou.

zend_extension="/usr/lib/php5/xdebug.so"

Restartujte FastCGI a pomocí funkce phpinfo() ověřte, že je rozšíření správně nahráno. V případě, že jste jej nahráli jako obyčejný PHP extension a ne jako Zend extension, bude křičet

XDEBUG NOT LOADED AS ZEND EXTENSION

Pokud je vše v pořádku, v tuto chvíli už vám funguje debugger. Místo strohých hlášek

Fatal error:  Call to a member function fetch_assoc() on a non-object in /var/www/db/mysqli.php on line 127

Uvidíte krásný stack trace

PHP Fatal error:  Call to a member function fetch_assoc() on a non-object in /var/www/db/mysqli.php on line 127
PHP Stack trace:
PHP   1. {main}() /var/www/index.php:0
PHP   2. Content::Load() /var/www/index.php:91
PHP   3. DB::LoadPreviewBlocks() /var/www/presentation/content.php:78

Po tomhle ale momentálně neprahnete, takže pokračujte s nastavováním profileru. Do php.ini přidejte

xdebug.profiler_enable = 1
xdebug.profiler_output_dir = "/var/www/xdebug/"

a opět restartujte FastCGI. Volba xdebug.profiler_output_dir udává, jak název napovídá, adresář do kterého budou profily ukládány.

Dalším krokem je stažení KCacheGrindu. Linuxoví uživatelé si jej mohou zkompilovat sami, uživatelé Windows pak najdou zkompilovanou binárku na SourceForge. No a pak už můžete vytvořený profil nahrát do KCacheGrindu a sprostě nadávat nad tím, kterej pitomec vymyslel ten padesátkrát vnořenej cyklus.