Xdebug und kCacheGrind: PHP-Skripte debuggen und profilieren

Letzten Monat haben wir eine Möglichkeit vorgestellt, wie wir die Auslastung unserer Infrastruktur mittels StatsD überwachen können. Damit aber diese «Large-Scale»- Probleme optimiert werden können, muss die Performance zuerst im einzelnen Seitenaufruf stimmen. Dies können wir im Einzelfall mittels der PHP Erweiterung Xdebug und einem cachegrind Analysetool wie kCacheGrind lösen.

Bei jedem komplexeren Softwareprojekt ist es fundamental wichtig, unerwartete Verhaltensweisen der Anwendung genauer untersuchen, beziehungsweise “debuggen” zu können. Auch bei der Entwicklung mit PHP braucht es öfters die Fähigkeit, das Skript an mehreren Stellen in der Ausführung anzuhalten und verschiedene Abhängigkeiten in der Laufzeitumgebung zu untersuchen. Ein simples var_dump oder echo gibt zu wenig Einblick in die Funktionsweise des Skripts. Die PHP-Erweiterung Xdebug in Kombination mit einer IDE wie NetBeans oder PhpStorm schafft hier Abhilfe. Xdebug ist eine Erweiterung, die es erlaubt PHP-Skripte anzuhalten und genauer zu untersuchen. Ausserdem kann sie einen ganzen Request profilieren, das heisst: alle Funktionsaufrufe nach Performance sortiert zu analysieren.

Xdebug installieren

Bei der Windows-Version des populären Webserverstack XAMPP ist die Xdebug-Erweiterung installiert, aber nicht aktiviert. Für Mac OSX empfiehlt sich die Installation des Pakets php54-xdebug via Homebrew. Die Erweiterung lässt sich in der von XAMPP mitgelieferten php.ini aktivieren, indem folgende Zeilen auskommentiert werden:

Die zwei Konfigurationsvariablen xdebug.idekey und xdebug.remote_port sind standardmässig nicht in der php.ini vorhanden, die mit XAMPP mitgeliefert wird. Diese sollten aber auf die gleichen Werte eingestellt werden wie die NetBeans-Optionen «Session ID» und «Debugger-Port»:

Nach einem Webserver-Neustart gibt ein phpinfo(); Auskunft darüber, ob die Erweiterung korrekt geladen und die Parameter übernommen wurden. NetBeans ist nun in der Lage, PHP-Projekte mit Ctrl-F5 oder einem Klick auf das Symbol rechts des grünen Pfeils zu debuggen. Das startet einen Aufruf der Website mit der Session ID als GET-Parameter, damit die Xdebug-Erweiterung mit NetBeans über den vorher konfigurierten Port kommunizieren kann. Wartet Netbeans auch nach dem lokalen Website-Aufruf weiter auf eine Verbindung mit Xdebug, kann das bedeuten, dass der Port besetzt ist oder von einer Firewall blockiert wird.

Mit Xdebug debuggen

NetBeans stellt nach dem Erreichen eines Breakpoints die üblichen Debuggerfunktionalitäten bereit, um die Laufzeitumgebung zu untersuchen:

  • Continue: Mit der Ausführung bis zum nächsten Breakpoint fortfahren
  • Step over / out / into / to cursor: PHP-Anweisungen auf der entsprechendem Call-Stack-Ebene ausführen
  • Call-Stack-Navigation: Zu aufrufenden Funktionen navigieren und dessen Variablen-Kontext untersuchen
  • Variablen-Untersuchung: Inhalte eines Arrays oder Felder eines Objektes inspizieren und verändern

Das Skript ist bei der grünen Zeile angehalten: Die Anweisung the_post() hat das globale $post Objekt erstellt, welches nun im Variablenpanel untersucht und verändert werden kann.

Mit Xdebug profilieren

Was tun, wenn nun alle Plugins und Templates richtig funktionieren, und die Website trotzdem noch langsam unterwegs ist? Wie vorgehen, wenn alle Empfehlungen von Pingdom Tools umgesetzt, unnötige Plugins abgeschaltet wurden und die üblichen Beschleuniger wie Memcache, APC oder ein besserer Server immer noch dazu führen, dass die HTML-Ausgabe um unerträglich viele Millisekunden verzögert wird? In diesem Fall kann ein PHP-Profiler dabei helfen, die Stellen im Code zu identifizieren, die am dringendsten eine Verbesserung benötigen.

Das Profiling kann bei Xdebug durch das Auskommentieren folgender Parameter in der php.ini von XAMPP und einem Neustart des Webservers aktiviert werden:

Dabei ist folgendes zu beachten:

  • Solange xdebug.profiler_enable auf 1 gesetzt ist, wird jeder Request aufgezeichnet, was langfristig grosse Logdaten ansammeln kann.
  • Wenn xdebug.profiler_enable ausgeschaltet ist, kann durch xdebug.profiler_enable_trigger immer noch ein einzelner Request aufgezeichnet werden, indem der GET-Parameter ?XDEBUG_PROFILE an einen Request angehängt wird.
  • Bei xdebug.profiler_output_name wurde das Format von «cachegrind…» auf «callgrind…» geändert, da die vorkompilierte Windowsversion von kCacheGrind nur Dateien in diesem Format öffnen kann.

Xdebug kann für jeden (oder einen spezifisch ausgewählten) Request eine sogenannte Cachegrind-Datei mitloggen, die detaillierte Informationen über jeden Funktionsaufruf enthält: an welcher Stelle wurde die Funktion aufgerufen, Anzahl Funktionsaufrufe sowie Zeitkosten der Ausführung der Funktion. Diese Dateien können mit kCacheGrind geöffnet werden (bei Mac OSX mit qCacheGrind via Homebrew oder MacCallGrind), welche eine tabellarische, hierarchische oder graphische Auskunft der Zeitkosten eines Requests geben. Dabei ist zum Beispiel die Fähigkeit, call_user_func Aufrufe nach Zielfunktion und Zeitaufwand summarisch darzustellen, beim Identifizieren problematischer WordPress-Plugins sehr hilfreich:

Zeitkosten aller WordPressfilter und -actions im Twentytwelve Theme, welche mit call_user_func_array aufgerufen wurden

Mit diesen Profiling-Informationen ist es nun ein leichtes, den zeitintensivsten Programmteil auszumachen. Schwieriger wird es vielleicht, die Ursache des Perfomanceverlustes zu debuggen oder zu umgehen – jedoch kommen wir so zielgerichtet zu schnelleren Websites.

Tom Forrer

Tom Forrer ist Software Engineer bei Blogwerk AG.

 

2 Kommentare

  1. Guten Tag Gibt es auch eine Möglichkeit für Java statt PHP? Besten Dank im Voraus und viele Grüsse Beat

  2. Tom Forrer sagt:

    Hallo Beat, Kurze Antwort: Ja. Ausführlicherweise nehme ich an, du willst eine JavaEE / JSF Anwendung Profilen. In der Netbeans IDE geht das eigentlich ganz einfach: Das Java-Projekt im Projekt-Explorer rechtsklicken und “Profile” wählen. Wenn das zum ersten Mal geschieht muss man noch den Profiler auf einer JVM kalibrieren: dies geht über den Menüpunkt “Profile->Advanced Commands->Run Profiler Calibration”. Beim Java-Webanwendungs-Profiling kann man auf verschiedene Arten die Anwendung profilen: Monitoring, CPU oder Memory überwachen. Wenn das Profiling läuft, und der entsprechende Aufruf aufgezeichnet worden ist, kann man mit “Dump Heap” einen Snapshot speichern, bei welchem ähnliche Informationen verfügbar sind, wie hier im Artikel beschrieben. Ein guter Startpunkt bezüglich Profiling mit Netbeans wäre http://profiler.netbeans.org/. Viel Erfolg beim Untersuchen!

Schreiben Sie einen Kommentar

Wir sind sehr an einer offenen Diskussion interessiert, behalten uns aber vor, beleidigende Kommentare sowie solche, die offensichtlich zwecks Suchmaschinenoptimierung abgegeben werden, zu editieren oder zu löschen. Mehr dazu in unseren Kommentarregeln.

Pflichtfelder
OK
Bitte geben Sie Ihren Namen ein.
OK
Bitte geben Sie Ihre E-Mail-Adresse ein.
OK
Bitte geben Sie einen korrekte Website ein.
OK
Bitte geben Sie einen Kommentar ein.