Handbuch zur dynamischen Ablaufverfolgung in Solaris

Kapitel 34 Statisch definierte Ablaufverfolgung für Benutzeranwendungen

DTrace bietet Entwicklern von Benutzeranwendungen die Möglichkeit, die Fähigkeiten des Providers pid durch benutzerdefinierte Prüfpunkte im Anwendungscode zu ergänzen. Diese statischen Prüfpunkte bedeuten im deaktivierten Zustand so gut wie keinen Overhead und werden wie alle anderen DTrace-Prüfpunkte dynamisch aktiviert. Mit statischen Prüfpunkten können Sie DTrace-Benutzern eine Beschreibung der Anwendungssemantik bereitstellen, ohne dafür die Implementierung der Anwendungen offen zu legen oder eine Kenntnis dieser bei den Benutzern vorauszusetzen. Dieses Kapitel befasst sich mit der Definition von statischen Prüfpunkten in Benutzeranwendungen und erklärt, wie sie sich mit DTrace in Benutzerprozessen aktivieren lassen.

Auswahl der Prüfpunktstellen

Mit DTrace können Entwickler statische Prüfpunktstellen in Anwendungscode einbetten. Das gilt sowohl für vollständige Anwendungen als auch für gemeinsam genutzte Bibliotheken. Diese Prüfpunkte können in Entwicklung oder Produktion überall dort aktiviert werden, wo die Anwendung oder Bibliothek läuft. Bei der Definition von Prüfpunkten sollten Sie darauf achten, dass der Kreis Ihrer DTrace-Benutzer die semantische Bedeutung der Prüfpunkte problemlos versteht. So ließen sich beispielsweise für einen Webserver die Prüfpunkte query-receive und query-respond definieren, die sich auf die Anforderung eines Clients an den Webserver und die entsprechende Reaktion des Webservers beziehen. Diese Beispielprüfpunkte sind für die meisten DTrace-Benutzer eindeutig verständlich und beziehen sich nicht auf tief verborgene Implementierungsdetails, sondern auf Abstraktionen auf der höchsten Ebene der Anwendung. DTrace-Benutzer können diese Prüfpunkte zur Betrachtung der zeitlichen Verteilung von Anforderungen nutzen. Wenn der Prüfpunkt query-receive die URL-Anforderungszeichenketten als Argument wiedergibt, können DTrace-Benutzer ermitteln, welche Anforderungen die höchste Festplatten-E/A verursacht haben, indem sie diesen Prüfpunkt mit dem io-Provider verbinden.

Darüber hinaus ist bei der Wahl von Prüfpunktnamen und -stellen die Stabilität der beschriebenen Abstraktionen zu beachten. Bleibt dieser Prüfpunkt in künftigen Versionen der Anwendung auch dann erhalten, wenn sich die Implementierung ändert? Ist der Prüfpunkt auf allen Systemarchitekturen sinnvoll oder bezieht er sich nur auf einen bestimmten Befehlssatz? In diesem Kapitel erfahren Sie im Detail, wie diese Entscheidungen die Definition der statischen Ablaufverfolgung beeinflussen.

Einfügen von Prüfpunkten in Anwendungen

DTrace-Prüfpunkte für Bibliotheken und ausführbare Dateien werden in einem ELF-Abschnitt des entsprechenden Anwendungscodes definiert. In diesem Teil des Handbuchs erfahren Sie, wie Sie Prüfpunkte definieren, in den Anwendungsquellcode einfügen und den Build-Prozess der Anwendung um die DTrace-Prüfpunktdefinitionen erweitern.

Definieren von Providern und Prüfpunkten

Sie definieren DTrace-Prüfpunkte in einer .d-Quelldatei, auf die später bei der Kompilierung und Verknüpfung der Anwendung zurückgegriffen wird. Wählen Sie zuerst einen geeigneten Namen für den Provider Ihrer Benutzeranwendung. Für jeden Prozess, der den Anwendungscode ausführt, wird die jeweilige Prozess-ID an den gewählten Providernamen angehängt. Wenn Sie beispielsweise für einen Webserver, der einen Prozess mit der ID 1203 ausführt, den Providernamen myserv wählen, dann lautet der DTrace-Providername für diesen Prozess myserv1203. Fügen Sie der .d-Quelldatei eine Providerdefinition wie in diesem Beispiel hinzu:

provider myserv {
	...
};			

Als Nächstes fügen Sie für jeden Prüfpunkt eine Definition und die entsprechenden Argumente hinzu. Im folgenden Beispiel werden die beiden unter Auswahl der Prüfpunktstellen behandelten Prüfpunkte definiert. Der erste Prüfpunkt besitzt zwei Argumente des Typs string, der zweite hat kein Argument. Der D-Compiler wandelt zwei aufeinander folgende Unterstriche (__) in jedem Prüfpunktnamen in einen Bindestrich um (-).

provider myserv {
	probe query__receive(string, string);
	probe query__respond();
};

Um den Verbrauchern der Prüfpunkte Auskunft über die Wahrscheinlichkeit einer Änderung in künftigen Versionen der Anwendung zu erteilen, sollten Sie Stabilitätsattribute in die Providerdefinition aufnehmen. In Kapitel 39Stabilität finden Sie nähere Informationen zu den Stabilitätsattributen in DTrace. Das folgende Beispiel zeigt die Definition von Stabilitätsattributen:


Beispiel 34–1 myserv.d: Statisch definierte Anwendungsprüfpunkte

#pragma D attributes Evolving/Evolving/Common provider myserv provider
#pragma D attributes Private/Private/Unknown provider myserv module
#pragma D attributes Private/Private/Unknown provider myserv function
#pragma D attributes Evolving/Evolving/Common provider myserv name
#pragma D attributes Evolving/Evolving/Common provider myserv args

provider myserv {
	probe query__receive(string, string);
	probe query__respond();
};


Hinweis –

D-Skripten, die nicht ganzzahlige Argumente aus benutzerdefinierten Prüfpunkten verwenden, müssen diese Argumente mithilfe der Funktionen copyin() und copyinstr() abrufen. Weitere Informationen finden Sie in Kapitel 33Ablaufverfolgung von Benutzerprozessen.


Einfügen von Prüfpunkten in Anwendungscode

Nachdem Sie Ihre Prüfpunkte nun in einer .d-Datei definiert haben, müssen Sie den Quellcode um die Angabe der Positionen erweitern, die Ihre Prüfpunkte auslösen sollen. Betrachten wir als Beispiel den folgenden C-Anwendungsquellcode:

void
main_look(void)
{
	...
	query = wait_for_new_query();
	process_query(query)
	...
}

Zum Angeben der Prüfpunktstelle fügen Sie einen Verweis auf die in <sys/sdt.h> definierte Makro DTRACE_PROBE() hinzu:

#include <sys/sdt.h>
...

void
main_look(void)
{
	...
	query = wait_for_new_query();
	DTRACE_PROBE2(myserv, query__receive, query->clientname, query->msg);
	process_query(query)
	...
}

Der Zusatz 2 im Makronamen DTRACE_PROBE2 bezieht sich auf die Anzahl der dem Prüfpunkt übergebenen Argumente. Die ersten beiden Argumente der Prüfpunktmakro bestehen in dem Providernamen und dem Prüfpunktnamen, die mit den D-Definitionen des Providers und des Prüfpunkts übereinstimmen müssen. Die übrigen Makro-Argumente werden den DTrace-Variablen arg0..9 zugewiesen, wenn der Prüfpunkt ausgelöst wird. Der Quellcode Ihrer Anwendung darf mehrere Verweise·auf den gleichen Provider- und Prüfpunktnamen enthalten. Sind im Quellcode mehrere Verweise auf denselben Prüfpunkt vorhanden, wird der Prüfpunkt durch jede Makroreferenz ausgelöst.

Erstellen von Anwendungen mit Prüfpunkten

Sie müssen den Build-Prozess der Anwendung um die DTrace-Provider- und -Prüfpunktdefinitionen erweitern. Bei einem typischen Erstellungsprozess werden die einzelnen Quelldateien in Objektdateien kompiliert. Die kompilierten Objektdateien werden, wie das nächste Beispiel zeigt, anschließend zu einer fertigen Anwendungsbinärdatei verknüpft:


cc -c src1.c
cc -c src2.c
...
cc -o myserv src1.o src2.o ...

Zum Aufnehmen von DTrace-Prüfpunktdefinitionen in die Anwendung fügen Sie angemessene Makefile-Regeln in den Build-Prozess ein, sodass der Befehl dtrace wie in folgendem Beispiel ausgeführt wird:


cc -c src1.c
cc -c src2.c
...
dtrace -G -32 -s myserv.d src1.o src2.o ...
cc -o myserv myserv.o src1.o src2.o ...

Der obige dtrace-Befehl führt eine Nachbearbeitung der durch die vorangehenden Compiler-Befehle generierten Objektdateien durch und erzeugt die Objektdatei myserv.o aus myserv.d sowie die anderen Objektdateien. Die dtrace-Option -G dient zum Verknüpfen der Provider- und Prüfpunktdefinitionen mit einer Benutzeranwendung. Die Option -32 dient zum Erstellen von 32-Bit-Anwendungsbinärdateien. Die Option -64 dient zum Erstellen von 64-Bit-Anwendungsbinärdateien.