Profiling von PHP Anwendungen

2 Kommentare

Wir bei codecentric haben nicht nur den Anspruch führend im Bereich Java Performance zu sein, sondern auch auf anderen Gebieten unseren Kunden mit Rat und Tat zur Seite zu stehen.

In einem früheren Eintrag habe ich schon einmal über einen Vergleich von PHP und Java geschrieben. Dabei habe ich unter anderem Tooling Probleme bei PHP bemängelt. In diesem Eintrag möchte ich deshalb darauf eingehen wie man PHP Anwendungen Profilen kann.

Für Java Entwickler sollte JProfiler ein Begriff sein. Das Äquivalent auf PHP Seite nennt sich Xdebug + CacheGrind. Xdebug ist dabei das Mittel um Skriptaufrufe zu profilen, WinCacheGrind nutzen wir dann anschließend um die gesammelten Daten auszuwerten. In diesem Beispiel profilen wir einen Kommandozeilen Aufruf des symfony Framworks. Da ich dort auch commiter bin nutze ich Xdebug dort häufiger um eine gute nichtfunktionale Qualität sicherzustellen.

Zuerst lädt man die ‚.dll‘ (oder ‚.so‘ für Linux) Extension von Xdebug herunter und legt sie zu den weiteren Extensions in das ‚php/ext‘ Verzeichnis. Um die Extension zu aktivieren muss man in der ‚php.ini‘ Xdebug einbinden und mitteilen wo es hin profilen soll:

zend_extension_ts="d:\dev\php\ext\php_xdebug-2.0.3-5.2.5.dll"
xdebug.profiler_output_dir="c:\xdebug-profiling"
xdebug.profiler_enable=1

Es ist dabei darauf zu achten, daß diese Einstellungen in den richtigen ‚php.ini‘ Dateien gemacht werden. im PHP Verzeichnis findet sich die für die Kommandozeile, im Apache Verzeichnis üblicherweise die für den von Apache gestarteten PHP Prozess. Auch muss das angegebene Zielverzeichnis existieren, ansonsten werden keine Dateien abgelegt.

Als kurzer Test sollte ein Aufruf von ‚php -m‘ folgendes liefern:

[Zend Modules]
Xdebug

Als nächstes profilen wir einen Aufruf. Z.B. einen der symfony sandbox, zum generieren einer Anwendung:

php symfony generate:app codecentric

In diesem Fall entsteht eine etwa 8MB große ‚cachegrind.out.4896‘. Dieses kann nun mit WinCacheGrind geladen werden. Dies sieht dann in etwa so aus:

Leider bietet WinCacheGrind nur begrenzte Funktionalität. KCacheGrind ist da schon etwas weiter, jedoch bei weitem noch nicht so ausgereift wie die häufig von uns eingesetzten Java Tools. Außerdem findet sich keine Memory Ansicht. Dies ist wohl auch darauf zurückzuführen, daß das Memory Management in PHP sehr dürftig ist. Brauchbar ist dagegen die Anzeige der benötigten Zeit.

Auf dem Tab ‚Overall‘ findet sich der Code der in Summe die meiste Zeit verbraucht hat. Dies ist für gewöhnlich auch die Stelle an der man schnell die größten Gewinne machen kann. Für den Symfony Task findet sich beispielsweise hier:

Function  : sfFinder->search_in
Avg. Self : 0,2ms
Avg. Cum. : 5,1ms
Total Self: 127ms
Total Cum.: 3214ms
Calls     : 629

die search_in Funktion benötigt selbst im Schnitt 0,2ms, aufgerufene Funktionen benötigen in Summe im Schnitt 5,1ms. Da die Funktion 629 mal aufgerufen wurde ergibt dies dann die entsprechenden Gesamtsummen. Nun kann man entweder schauen ob die Funktion wirklich so oft aufgerufen werden muss, und wenn ja, ob man nicht einen einzigen Durchlauf noch optmieren kann.

Auch ohne die richtige Spürnase für Performanceprobleme kann man mit dem beschriebenen Tooling auch PHP Anwendungen in der Performance optimieren. Es bleibt abzuwarten ob sich PHP und die entsprechenden Tools soweit entwickeln werden wie es heute schon status quo in Java ist.

Fabian Lange ist Lead Agent Engineer bei Instana und bei der codecentric als Performance Geek bekannt. Er baut leidenschaftlich gerne schnelle Software und hilft anderen dabei, das Gleiche zu tun.
Er kennt die Java Virtual Machine bis in die letzte Ecke und beherrscht verschiedenste Tools, die JVM, den JIT oder den GC zu verstehen.
Er ist beliebter Vortragender auf zahlreichen Konferenzen und wurde unter anderem mit dem JavaOne Rockstar Award ausgezeichnet.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentare

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.