PHP mit DTrace verwenden

PHP kann auf Plattformen, die DTrace Dynamic Tracing unterstützen, mit statischen DTrace-Sonden konfiguriert werden.

PHP für statische DTrace-Sonden konfigurieren

Um die DTrace-Unterstützung des Betriebssystems zu aktivieren, siehe die externe plattformspezifische Dokumentation. Unter Oracle Linux muss zum Beispiel ein UEK3-Kernel gebootet und anschließend Folgendes ausgeführt werden:

# modprobe fasttrap
# chmod 666 /dev/dtrace/helper

Anstatt chmod zu verwenden, kann stattdessen eine ACL-Paketregel verwendet werden, um den Gerätezugriff auf einen bestimmten Benutzer zu beschränken.

PHP mit dem Konfigurationsparameter --enable-dtrace kompilieren:

# ./configure --enable-dtrace ...
# make
# make install

Dies aktiviert die statischen Sonden im Kern von PHP. Alle PHP-Erweiterungen, die ihre eigenen Sonden bereitstellen, müssen separat als dynamische Erweiterungen gebaut werden.

Statische DTrace-Sonden im Kern von PHP

Die folgenden statischen Sonden stehen in PHP zur Verfügung
Name der ProbeBeschreibung der ProbeParameter der Probe
request-startupWird ausgelöst, wenn eine Anfrage beginnt.char *file, char *request_uri, char *request_method
request-shutdownWird ausgelöst, wenn eine Anfrage endet.char *file, char *request_uri, char *request_method
compile-file-entryWird ausgelöst, wenn die Kompilierung eines Skripts beginnt.char *compile_file, char *compile_file_translated
compile-file-returnWird ausgelöst, wenn die Kompilierung eines Skripts endet.char *compile_file, char *compile_file_translated
execute-entry Wird ausgelöst, wenn ein OpCode-Array ausgeführt wird, z. B. bei Funktionsaufrufen, Includes und wenn ein Generator fortfährt. char *request_file, int lineno
execute-returnWird nach der Ausführung eines OpCode-Arrays ausgelöst.char *request_file, int lineno
function-entry Wird ausgelöst, wenn die PHP-Engine in eine PHP-Funktion oder -Methode gelangt. char *function_name, char *request_file, int lineno, char *classname, char *scope
function-return Wird ausgelöst, wenn die PHP-Engine aus einer PHP-Funktion oder -Methode zurückkehrt. char *function_name, char *request_file, int lineno, char *classname, char *scope
exception-thrownWird ausgelöst, wenn eine Exception ausgelöst wird.char *classname
exception-caughtWird ausgelöst, wenn eine Exception abgefangen wird.char *classname
error Wird ausgelöst, wenn ein Fehler auftritt, unabhängig von der error_reporting-Stufe. char *errormsg, char *request_file, int lineno

PHP-Erweiterungen verfügen möglicherweise über zusätzliche statische Sonden.

Liste statischer DTrace-Sonden in PHP

Um die verfügbaren Sonden aufzulisten, ist es nötig, einen PHP-Prozess zu starten und dann Folgendes auszuführen:

 # dtrace -l 

Die Ausgabe wird ungefähr so aussehen:

 ID PROVIDER MODULE FUNCTION NAME [ . . . ] 4 php15271 php dtrace_compile_file compile-file-entry 5 php15271 php dtrace_compile_file compile-file-return 6 php15271 php zend_error error 7 php15271 php ZEND_CATCH_SPEC_CONST_CV_HANDLER exception-caught 8 php15271 php zend_throw_exception_internal exception-thrown 9 php15271 php dtrace_execute_ex execute-entry 10 php15271 php dtrace_execute_internal execute-entry 11 php15271 php dtrace_execute_ex execute-return 12 php15271 php dtrace_execute_internal execute-return 13 php15271 php dtrace_execute_ex function-entry 14 php15271 php dtrace_execute_ex function-return 15 php15271 php php_request_shutdown request-shutdown 16 php15271 php php_request_startup request-startup 

Die Werte der Spalte PROVIDER setzen sich aus php und der Prozess-ID des aktuell laufenden PHP-Prozesses zusammen.

Wenn der Apache-Webserver läuft, könnte der Modulname zum Beispiel libphp5.so sein, und es gäbe pro laufendem Apache-Prozess einen Auflistungs-Block.

Die Spalte FUNCTION verweist auf den Funktionsnamen der PHP-internen C-Implementierung, in der sich der jeweilige Provider befindet.

Wenn kein PHP-Prozess läuft, werden auch keine PHP-Sonden angezeigt.

DTrace-Beispiel für PHP

Dieses Beispiel zeigt die grundlegenden Möglichkeiten der DTrace-Skriptsprache D.

Beispiel #1 all_probes.d für die Verfolgung aller statischen PHP-Sonden mit DTrace

 #!/usr/sbin/dtrace -Zs #pragma D option quiet php*:::compile-file-entry { printf("PHP compile-file-entry\n"); printf(" compile_file %s\n", copyinstr(arg0)); printf(" compile_file_translated %s\n", copyinstr(arg1)); } php*:::compile-file-return { printf("PHP compile-file-return\n"); printf(" compile_file %s\n", copyinstr(arg0)); printf(" compile_file_translated %s\n", copyinstr(arg1)); } php*:::error { printf("PHP error\n"); printf(" errormsg %s\n", copyinstr(arg0)); printf(" request_file %s\n", copyinstr(arg1)); printf(" lineno %d\n", (int)arg2); } php*:::exception-caught { printf("PHP exception-caught\n"); printf(" classname %s\n", copyinstr(arg0)); } php*:::exception-thrown { printf("PHP exception-thrown\n"); printf(" classname %s\n", copyinstr(arg0)); } php*:::execute-entry { printf("PHP execute-entry\n"); printf(" request_file %s\n", copyinstr(arg0)); printf(" lineno %d\n", (int)arg1); } php*:::execute-return { printf("PHP execute-return\n"); printf(" request_file %s\n", copyinstr(arg0)); printf(" lineno %d\n", (int)arg1); } php*:::function-entry { printf("PHP function-entry\n"); printf(" function_name %s\n", copyinstr(arg0)); printf(" request_file %s\n", copyinstr(arg1)); printf(" lineno %d\n", (int)arg2); printf(" classname %s\n", copyinstr(arg3)); printf(" scope %s\n", copyinstr(arg4)); } php*:::function-return { printf("PHP function-return\n"); printf(" function_name %s\n", copyinstr(arg0)); printf(" request_file %s\n", copyinstr(arg1)); printf(" lineno %d\n", (int)arg2); printf(" classname %s\n", copyinstr(arg3)); printf(" scope %s\n", copyinstr(arg4)); } php*:::request-shutdown { printf("PHP request-shutdown\n"); printf(" file %s\n", copyinstr(arg0)); printf(" request_uri %s\n", copyinstr(arg1)); printf(" request_method %s\n", copyinstr(arg2)); } php*:::request-startup { printf("PHP request-startup\n"); printf(" file %s\n", copyinstr(arg0)); printf(" request_uri %s\n", copyinstr(arg1)); printf(" request_method %s\n", copyinstr(arg2)); } 

Dieses Skript verwendet dtrace mit der Option -Z, damit es auch dann ausgeführt werden kann, wenn gerade kein PHP-Prozess läuft. Ohne diese Option würde das Skript sofort beendet, weil es erkennt, dass keine der zu überwachenden Sonden vorhanden ist.

Das Skript verfolgt während der gesamten Zeit, in der ein PHP-Skript läuft, alle statischen Sondenpunkte des PHP-Kerns.

 # ./all_probes.d 

Sobald nun ein PHP-Skript oder eine Anwendung ausgeführt wird, beginnt das überwachende D-Skript, alle Parameter der ausgelösten Sonden auszugeben.

Um die Überwachung abzuschließen, kann das D-Skript mittels CTRL+C beendet werden.

Auf Rechnern mit mehreren CPUs ist die Reihenfolge der Tests möglicherweise nicht sequentiell. Dies hängt davon ab, welche CPU die Sonden verarbeitet hat und wie die Threads zwischen den CPUs wechseln. Die Anzeige der Zeitstempel der Sonden hilft, Verwechslungen zu vermeiden, zum Beispiel:

 php*:::function-entry { printf("%lld: PHP function-entry ", walltimestamp); [ . . .] } 
To Top