Handbuch zur dynamischen Ablaufverfolgung in Solaris

Kapitel 38 Überlegungen zur Leistung

Aufgrund der zusätzlichen Arbeit, die DTrace im System verursacht, wirkt sich die Aktivierung von DTrace immer auf irgendeine Art und Weise auf die Systemleistung aus. Dabei handelt es sich häufig um eine vernachlässigbare Beeinträchtigung, die jedoch bei Aktivierung sehr vieler und aufwändiger Prüfpunkte beträchtlich werden kann. In diesem Kapitel werden Techniken zur Minimierung der Leistungsbeeinträchtigung durch DTrace beschrieben.

Begrenzen aktivierter Prüfpunkte

Dank dynamischer Instrumentationstechniken bietet DTrace eine unvergleichliche Reichweite der Ablaufverfolgung, die den Kernel und beliebige Benutzerprozesse einschließt. Diese Reichweite ermöglicht einerseits revolutionäre Einblicke in das Systemverhalten, kann aber andererseits auch eine sehr intensive Prüftätigkeit verursachen. Wenn zehn- oder gar hunderttausende Prüfpunkte aktiviert sind, kann es leicht zu einer beträchtlichen Auswirkung auf das System kommen. Aus diesem Grund sollten stets nur so viele Prüfpunkte aktiviert werden, wie zur Lösung eines Problems erforderlich sind. Beispielsweise empfiehlt es sich nicht, alle FBT-Prüfpunkte zu aktivieren, wenn eine etwas komplexere Aktivierung die jeweilige Fragestellung beantworten kann. So bietet es sich etwa bei einigen Fragestellungen an, sich auf ein bestimmtes Modul oder eine bestimmte Funktion zu konzentrieren.

Bei Verwendung des Providers pid ist besondere Vorsicht geboten. Da der Provider pid jede Anweisung instrumentieren kann, könnten Sie mehrere Millionen Prüfpunkte in einer Anwendung aktivieren und den Zielprozess dadurch extrem verlangsamen.

DTrace kann auch dann eingesetzt werden, wenn zur Beantwortung einer Frage zahlreiche Prüfpunkte aktiviert werden müssen. Die Aktivierung sehr vieler Prüfpunkte verlangsamt das System mitunter recht deutlich, wird das System aber keinesfalls zum Abstürzen bringen. Sie sollten also nicht zögern, viele Prüfpunkte zu aktivieren, wenn dies erforderlich ist.

Verwenden von Aggregaten

Wie bereits in Kapitel 9Aggregate besprochen, bieten DTrace-Aggregate die Möglichkeit, Daten auf skalierbare Art und Weise zusammenzufassen - zu aggregieren. Auf den ersten Blick könnte man annehmen, dass auch assoziative Vektoren eine ähnliche Funktion haben. Doch da es sich dabei um globale Allzweckvariablen handelt, lässt sich mit ihnen nicht die lineare Skalierbarkeit von Aggregaten erzielen. Wo dies möglich ist, sollten also Aggregate den assoziativen Vektoren vorgezogen werden. Das folgende Beispiel ist nicht empfehlenswert:

syscall:::entry
{
	totals[execname]++;
}

syscall::rexit:entry
{
	printf("%40s %d\n", execname, totals[execname]);
	totals[execname] = 0;
}

Dieses Beispiel ist dem obigen vorzuziehen:

syscall:::entry
{
	@totals[execname] = count();
}

END
{
	printa("%40s %@d\n", @totals);
}

Verwenden zwischenspeicherbarer Prädikate

DTrace-Prädikate dienen zum Herausfiltern unerwünschter Daten aus dem Experiment, indem nur Daten aufgezeichnet werden, die eine angegebene Bedingung erfüllen. Beim Aktivieren zahlreicher Prüfpunkte greift man im Allgemeinen auf Prädikate wie zum Beispiel /self->traceme/ oder /pid == 12345/ zurück, die einen oder mehrere spezifische Threads angeben. Obwohl viele dieser Prädikate für die meisten Threads in den meisten Prüfpunkten den Wert „falsch“ ergeben, kann die Auswertung selbst sehr aufwändig werden, wenn sie für tausende von Prüfpunkten erfolgen muss. Um diesen Aufwand herabzusetzen, speichert DTrace die Auswertung von Prädikaten, die nur thread-lokale (z. B. /self->traceme/) oder unveränderliche Variablen enthalten (z. B. /pid == 12345/) in einem Cache. Zwischengespeicherte Prädikate lassen sich unter wesentlich geringerem Aufwand auswerten als nicht zwischengespeicherte. Dies gilt insbesondere dann, wenn die Prädikate thread-lokale Variablen, Zeichenkettenvergleiche oder andere relativ aufwändige Operationen beinhalten. Die Zwischenspeicherung von Prädikaten ist für die Benutzer transparent, unterliegt aber den in der folgenden Tabelle aufgeführten Richtlinien zum Erzeugen optimaler Prädikate:

Zwischenspeicherbar 

Nicht zwischenspeicherbar 

self->mumble

mumble[curthread], mumble[pid, tid]

execname

curpsinfo->pr_fname, curthread->t_procp->p_user.u_comm

pid

curpsinfo->pr_pid, curthread->t_procp->p_pipd->pid_id

tid

curlwpsinfo->pr_lwpid, curthread->t_tid

curthread

curthread->beliebige Komponente, curlwpsinfo->beliebige Komponente, curpsinfo->beliebige Komponente

Das folgende Beispiel ist nicht empfehlenswert:

syscall::read:entry
{
	follow[pid, tid] = 1;
}

fbt:::
/follow[pid, tid]/
{}

syscall::read:return
/follow[pid, tid]/
{
	follow[pid, tid] = 0;
}

Das folgende Beispiel mit thread-lokalen Variablen ist dem obigen vorzuziehen:

syscall::read:entry
{
	self->follow = 1;
}

fbt:::
/self->follow/
{}

syscall::read:return
/self->follow/
{
	self->follow = 0;
}

Nur Prädikate, die ausschließlich aus zwischenspeicherbaren Ausdrücken bestehen, können selbst zwischengespeichert werden. Alle nachfolgenden Prädikate können zwischengespeichert werden:

/execname == "myprogram"/
/execname == $$1/
/pid == 12345/
/pid == $1/
/self->traceme == 1/

Die folgenden Beispiele mit globalen Variablen sind nicht zwischenspeicherbar:

/execname == one_to_watch/
/traceme[execname]/
/pid == pid_i_care_about/
/self->traceme == my_global/