Handbuch zur dynamischen Ablaufverfolgung in Solaris

Kapitel 12 Formatierung der Ausgabe

Die in DTrace integrierten Formatierungsfunktionen printf() und printa() können Sie in Ihren D-Programmen zum Formatieren der Ausgabe einsetzen. Der D-Compiler bietet Leistungsmerkmale, die in der printf(3C)-Bibliotheksroutine nicht enthalten sind. Deshalb empfiehlt es sich, dieses Kapitel auch dann zu lesen, wenn Sie mit printf() vertraut sind. Darüber hinaus behandelt dieses Kapitel das Formatverhalten der Funktion trace() und das Standardausgabeformat von dtrace(1M) für die Anzeige von Aggregaten.

printf()

Die Funktion printf() bietet zwei Fähigkeiten in Einem: Ähnlich wie die Funktion trace() verfolgt sie Daten, und zusätzlich kann sie die Daten und anderen Text in einem spezifischen, von Ihnen beschriebenen Format ausgeben. Die Funktion printf() weist DTrace an, die jedem Argument nach dem ersten Argument zugehörigen Daten zu verfolgen und die Ergebnisse gemäß den mit dem ersten printf()-Argument, der Formatzeichenkette, beschriebenen Regeln auszugeben.

Die Formatzeichenkette ist eine normale Zeichenkette (string). Sie kann beliebig viele mit dem Zeichen % angeführte Formatumwandlungen enthalten, die beschreiben, wie das entsprechende Argument formatiert werden soll. Die erste Konvertierung in der Formatzeichenkette bezieht sich auf das zweite Argument von printf(), die zweite Konvertierung auf das dritte Argument und so weiter. Text zwischen den Umwandlungen wird wörtlich wiedergegeben. Das auf das %-Umwandlungszeichen folgende Zeichen beschreibt das für das entsprechende Argument zu verwendende Format.

Anders als printf(3C) ist die DTrace-Funktion printf() eine integrierte Funktion, die vom D-Compiler erkannt wird. Der D-Compiler stellt mehrere nützliche Dienste für DTrace printf() zur Verfügung, die in der C-Bibliothek printf() nicht enthalten sind:

Zum Implementieren dieser Leistungsmerkmale muss die Formatzeichenkette in der DTrace-Funktion printf() im D-Programm als konstante Zeichenkette angegeben sein. Formatzeichenketten dürfen keine dynamischen Variablen des Typs string sein.

Umwandlungsangaben

Jede Umwandlungsangabe in der Formatzeichenkette wird durch das Zeichen % eingeleitet, auf das der Reihe nach diese Informationen folgen:

Die Funktion printf(3C) unterstützt auch Umwandlungsangaben der Form % n$, wobei n eine ganze Dezimalzahl ist. DTrace printf() unterstützt diese Art von Umwandlungsangabe nicht.

Flags

Die Umwandlungs-Flags für printf() werden durch Angabe in beliebiger Reihenfolge von mindestens einem der folgenden Zeichen aktiviert:

'

Der ganzzahlige Teil des Ergebnisses einer Dezimalumwandlung (%i, %d, %u, %f, %g oder %G) wird mit Tausenderzeichen formatiert; dabei handelt es sich um das nicht-monetäre Gruppierungszeichen. Einige Sprachumgebungen, einschließlich der POSIX-C-Sprachumgebung, bieten keine nicht-monetären Gruppierungszeichen zur Verwendung mit diesem Flag.

-

Das Ergebnis der Umwandlung wird im Feld links ausgerichtet. Ohne Angabe dieses Flags wird das Umwandlungsergebnis rechts ausgerichtet.

+

Das Ergebnis einer vorzeichenbehafteten Umwandlung beginnt immer mit einem Vorzeichen (+ oder -). Wird das Flag nicht angegeben, beginnt die Umwandlung nur dann mit einem Vorzeichen, wenn ein negativer Wert konvertiert wird.

space

Wenn das erste Zeichen einer vorzeichenbehafteten Umwandlung kein Vorzeichen ist oder eine Umwandlung mit Vorzeichen keine Zeichen ergibt, wird vor das Ergebnis ein Leerzeichen gesetzt. Treten sowohl space- als auch +-Flags auf, wird das Leerzeichen-Flag ignoriert.

#

Der Wert wird in eine alternative Form umgewandelt, sofern für die ausgewählte Umwandlung eine Alternativform definiert ist. Die alternativen Formate für Umwandlungen werden gemeinsam mit der entsprechenden Umwandlung beschrieben.

0

Bei d-, i-, o-, u-, x-, X-, e-, E-, f-, g- und G-Umwandlungen werden zur Anpassung an die Feldbreite führende Nullen (im Anschluss an etwaige Angaben von Vorzeichen oder Basis) eingefügt. Es erfolgt kein Auffüllen mit Leerzeichen. Treten sowohl 0- als auch --Flags auf, wird das 0-Flag ignoriert. Bei Angabe einer Genauigkeit in d-, i-, o-, u-, x- und X-Umwandlungen wird das 0-Flag ignoriert. Treten sowohl das 0- als auch das '-Flag auf, werden vor dem Auffüllen mit Nullen die Gruppierungszeichen eingefügt.

Kennungen für Breite und Genauigkeit

Die minimale Feldbreite kann als Zeichenkette von Dezimalzahlen im Anschluss an ein beliebiges Flag angegeben werden. In diesem Fall wird die Feldbreite auf die angegebene Spaltenanzahl gesetzt. Die Feldbreite kann auch mit einem Asterisk (*) angegeben werden. Dann wird zur Ermittlung der Feldbreite auf ein zusätzliches Argument des Typs int zugegriffen. Um beispielsweise eine Ganzzahl x auf einer durch den Wert der int-Variable w bestimmten Feldbreite darzustellen, schreiben Sie die D-Anweisung:

printf("%*d", w, x);

Die Feldbreite kann auch mit dem Zeichen ? angegeben werden, das bedeutet, dass die Feldbreite auf Grundlage der zur Formatierung einer hexadezimalen Adresse im Datenmodell des Betriebssystemkerns erforderlichen Anzahl von Zeichen festzulegen ist. Beruht der Kernel auf dem 32-Bit-Datenmodell, wird die Breite auf 8, beim 64-Bit-Datenmodell auf 16 gesetzt.

Die Genauigkeit der Umwandlung kann als Zeichenkette von Dezimalzahlen im Anschluss an einen Punkt (.) oder durch einen Asterisk (*) im Anschluss an einen Punkt angegeben werden. Wird die Genauigkeit mit einem Asterisk angegeben, wird zur Ermittlung der Genauigkeit auf ein zusätzliches Argument des Typs int vor dem Umwandlungsargument zugegriffen. Wenn sowohl die Breite als auch die Genauigkeit mit einem Asterisk angegeben werden, sollten die printf()-Argumente für die Umwandlung in folgender Reihenfolge auftreten: Breite, Genauigkeit, Wert.

Größenpräfixe

Größenvorzeichen sind in ANSI-C-Programmen, die printf(3C) enthalten, zur Angabe von Größe und Typ des Umwandlungsarguments erforderlich. Der D-Compiler erledigt diese Verarbeitung für printf()-Aufrufe automatisch. Größenpräfixe werden hier also nicht benötigt. Sie stehen zwar aus Gründen der Kompatibilität mit C zur Verfügung, doch wird von ihrer Verwendung in D-Programmen ausdrücklich abgeraten, da sie den Code bei Einsatz abgeleiteter Typen an ein bestimmtes Datenmodell binden. Wenn beispielsweise eine typedef auf andere ganzzahlige Grundtypen in Abhängigkeit vom Datenmodell umdefiniert wird, kann keine einzelne C-Umwandlung verwendet werden, die für beide Datenmodelle funktioniert, ohne dass die beiden zugrunde liegenden Typen ausdrücklich angegeben und ein Cast-Ausdruck eingefügt oder mehrere Formatzeichenketten definiert werden. Der D-Compiler löst dieses Problem automatisch, indem er auf Größenpräfixe verzichtet und die Argumentgröße automatisch ermittelt.

Die Größenpräfixe können direkt vor den Namen der Formatumwandlung und hinter etwaige Flags, Breiten- und Genauigkeitszeichen gesetzt werden. Die Größenpräfixe lauten:

Umwandlungsformate

Mit jeder Folge von Umwandlungszeichen werden null oder mehr Argumente abgerufen. Wenn der Format-Zeichenkette nicht genügend Argumente geliefert werden oder am Ende der Format-Zeichenkette weitere Argumente übrig bleiben, gibt der D-Compiler eine entsprechende Fehlermeldung aus. Bei Angabe eines undefinierten Umwandlungsformats gibt der D-Compiler ebenfalls eine Fehlermeldung aus. Die Umwandlungszeichenfolgen lauten:

a

Der Zeiger oder das uintptr_t-Argument wird als Kernelsymbolname in der Form Modul`Symbolname plus einem optionalen hexadezimalen Byte-Abstand ausgegeben. Sollte der Wert nicht in den durch ein bekanntes Kernelsymbol definierten Bereich fallen, wird er als hexadezimale Ganzzahl ausgegeben.

c

Das Argument des Typs char, short oder int wird als ASCII-Zeichen ausgegeben.

C

Das Argument des Typs char, short oder int wird als ASCII-Zeichen ausgegeben, sofern es sich um ein druckbares ASCII-Zeichen handelt. Ist dies nicht der Fall, wird das Zeichen mit der entsprechenden Ersatzdarstellung (siehe Tabelle 2–5) ausgegeben.

d

Das Argument des Typs char, short, int, long oder long long wird als dezimale Ganzzahl (Grundzahl 10) ausgegeben. Wenn das Argument signed ist, wird es als Wert mit Vorzeichen ausgegeben. Wenn das Argument unsigned ist, wird es als vorzeichenloser Wert ausgegeben. Diese Umwandlung ist gleichbedeutend mit i.

e, E

Das Argument des Typs float, double oder long double wird in den Stil [-]d.ddddd umgewandelt, wobei vor dem Dezimalzeichen eine Stelle steht und die Anzahl der Stellen dahinter die Genauigkeit angibt. Das Dezimalzeichen ist nicht Null, wenn das Argument nicht Null ist. Wenn kein Genauigkeitswert angegeben wird, beträgt er standardmäßig 6. Wenn die Genauigkeit 0 beträgt und das #-Flag nicht angegeben wurde, wird kein Dezimalzeichen angezeigt. Das Umwandlungsformat E ergibt eine Zahl, in der die Hochzahl nicht mit e, sondern mit E eingeführt wird. Die Hochzahl enthält stets mindestens zwei Stellen. Der Wert wird auf die geeignete Stellenanzahl aufgerundet.

f

Das Argument des Typs float, double oder long double wird in den Stil [-]ddd. ddd umgewandelt, wobei die Anzahl der Stellen hinter dem Dezimalzeichen die Genauigkeit angibt. Wenn kein Genauigkeitswert angegeben wird, beträgt er standardmäßig 6. Wenn die Genauigkeit 0 beträgt und das #-Flag nicht angegeben wurde, wird kein Dezimalzeichen angezeigt. Wenn ein Dezimalzeichen erscheint, steht davor mindestens eine Stelle. Der Wert wird auf die geeignete Stellenanzahl aufgerundet.

g, G

Das Argument des Typs float, double oder long double wird im Stil f oder e (oder im Stil E bei Verwendung des Umwandlungszeichens G) ausgegeben, wobei die Genauigkeit die Anzahl der signifikanten Stellen angibt. Eine explizite Genauigkeit von 0 wird als 1 interpretiert. Der jeweilige Stil hängt von dem Wert ab, der umgewandelt wird: Stil e (oder E) wird nur verwendet, wenn der aus der Umwandlung resultierende Exponent kleiner als -4 oder nicht kleiner als die Genauigkeit ist. Nullen am Schluss werden aus dem Bruchteil des Ergebnisses entfernt. Ein Dezimalzeichen erscheint nur, wenn darauf eine Stelle folgt. Wenn das Flag # angegeben wurde, werden Nullen am Schluss nicht aus dem Ergebnis entfernt.

i

Das Argument des Typs char, short, int, long oder long long wird als dezimale Ganzzahl (Grundzahl 10) ausgegeben. Wenn das Argument signed ist, wird es als Wert mit Vorzeichen ausgegeben. Wenn das Argument unsigned ist, wird es als vorzeichenloser Wert ausgegeben. Diese Umwandlung ist gleichbedeutend mit d.

o

Das Argument des Typs char, short, int, long oder long long wird als vorzeichenlose Oktalzahl (Grundzahl 8) ausgegeben. Für diese Umwandlung können sowohl signed als auch unsigned Argumente benutzt werden. Wenn das Flag # angegeben wurde, wird die Genauigkeit des Ergebnisses bei Bedarf erhöht, sodass die erste Stelle des Ergebnisses eine Null ist.

p

Das Zeiger- oder uintptr_t-Argument wird als Hexadezimalzahl (Grundzahl 16) ausgegeben. D akzeptiert Zeigerargumente jeden Typs. Wenn das Flag # angegeben wurde, wird einem Ergebnis, das nicht Null ist, 0x vorangestellt.

s

Das Argument muss ein Vektor von char oder ein string sein. Die Byte aus dem Vektor oder string werden bis zu einem schließenden Nullzeichen oder bis zum Ende der Daten gelesen und als ASCII-Zeichen interpretiert und ausgegeben. Wenn keine Genauigkeit angegeben ist, wird sie als unendlich angenommen und alle Zeichen bis zu dem ersten Nullzeichen werden ausgegeben. Wenn eine Genauigkeit angegeben wurde, wird nur der Teil des Zeichenvektors ausgegeben, der in der entsprechenden Menge von Bildschirmspalten sichtbar ist. Wenn ein Argument des Typs char * formatiert werden muss, sollte es explizit in den Typ string umgewandelt werden oder den D-Operator stringof als Präfix erhalten, der DTrace anweist, die Byte aus der Zeichenkette zu verfolgen und zu formatieren.

S

Das Argument muss ein Vektor von char oder ein string sein. Das Argument wird wie bei der %s-Umwandlung verarbeitet, aber etwaige nicht druckbare ASCII-Zeichen werden durch die entsprechende Ersatzdarstellung aus Tabelle 2–5 ersetzt.

u

Das Argument des Typs char, short, int, long oder long long wird als vorzeichenlose Dezimalzahl (Grundzahl 10) ausgegeben. Für diese Umwandlung können sowohl signed als auch unsigned Argumente benutzt werden, und das Ergebnis wird stets als unsigned formatiert.

wc

Das Argument des Typs int wird in ein Sonderzeichen des Typs wchar_t (erweitertes Zeichen) umgewandelt und ausgegeben.

ws

Das Argument muss ein Vektor von wchar_t sein. Die Byte aus dem Vektor werden bis zu einem schließenden Nullzeichen oder bis zum Ende der Daten gelesen und als erweiterte Zeichen interpretiert und ausgegeben. Wenn keine Genauigkeit angegeben ist, wird sie als unendlich angenommen und alle erweiterten Zeichen bis zu dem ersten Nullzeichen werden ausgegeben. Wenn eine Genauigkeit angegeben wurde, wird nur der Teil des Vektors von erweiterten Zeichen ausgegeben, der in der entsprechenden Menge von Bildschirmspalten sichtbar ist.

x, X

Das Argument des Typs char, short, int, long oder long long wird als vorzeichenlose Hexadezimalzahl (Grundzahl 16) ausgegeben. Für diese Umwandlung können sowohl signed als auch unsigned Argumente benutzt werden. Bei der Umwandlungsform x werden die Buchstabenstellen abcdef verwendet. Bei der Umwandlungsform X werden die Buchstabenstellen ABCDEF verwendet. Wenn das Flag # angegeben wurde, wird einem Ergebnis, das nicht Null ist, 0x (bei %x) oder 0X (bei %X) vorangestellt.

Y

Das Argument des Typs uint64_twird als Anzahl der seit 00:00 Uhr UCT am 1. Januar 1970 verstrichenen Nanosekunden interpretiert und in der folgenden cftime(3C)-Form ausgegeben: “%Y %a %b %e %T %Z.” Die aktuelle Anzahl der seit 00:00 Uhr UTC am 1. Januar 1970 abgelaufenen Nanosekunden steht in der Variable walltimestamp zur Verfügung.

%

Es wird das Zeichen % ausgegeben. Kein Argument wird umgewandelt. Die vollständige Umwandlungsangabe muss %% lauten.

printa()

Die Funktion printa() dient zum Formatieren der Ergebnisse von Aggregaten in D-Programmen. Die Funktion wird in einer von zwei Formen aufgerufen:

printa(@Aggregationsname);
printa(Formatzeichenkette, @Aggregationsname);

Bei Verwendung der ersten Form erstellt der Befehl dtrace(1M) eine vollständige Momentaufnahme der Aggregatdaten und wendet auf die Ausgabe das entsprechende Standardausgabeformat für Aggregate (siehe Beschreibung in Kapitel 9Aggregate) an.

Bei Verwendung der zweiten Form erstellt der Befehl dtrace(1M) ebenfalls eine vollständige Momentaufnahme der Aggregatdaten und generiert eine Ausgabe gemäß den in der Format-Zeichenkette angegebenen Umwandlungen. Dabei gelten die folgenden Regeln:

Das folgende D-Programm stellt ein vollständiges Beispiel für printa() dar. Darin wird der Wert von caller mit dem Provider profile geprüft und die Ergebnisse werden anschließend in Form einer einfachen Tabelle ausgegeben:

profile:::profile-997
{
	@a[caller] = count();
}

END
{
	printa("%@8u %a\n", @a);
}

Wenn Sie dieses Programm mit dtrace ausführen, warten Sie einige Sekunden lang und drücken Sie dann Strg-C. Sie erhalten eine Ausgabe der Art:


# dtrace -s printa.d
^C
CPU     ID                    FUNCTION:NAME
  1      2                             :END        1 0x1
       1 ohci`ohci_handle_root_hub_status_change+0x148
       1 specfs`spec_write+0xe0
       1 0xff14f950
       1 genunix`cyclic_softint+0x588
       1 0xfef2280c
       1 genunix`getf+0xdc
       1 ufs`ufs_icheck+0x50
       1 genunix`infpollinfo+0x80
       1 genunix`kmem_log_enter+0x1e8
       ...

Standardformat von trace()

Wenn Sie Daten nicht mit printf(), sondern mit der Funktion trace() erfassen, gibt der Befehl dtrace die Ergebnisse in einem Standardausgabeformat aus. Sind die Daten 1, 2, 4 oder 8 Byte groß, wird das Ergebnis als ganzzahliger Dezimalwert formatiert. Bei Daten jeder anderen Größe, die eine Folge druckbarer Zeichen sind und als Byte-Folge interpretiert werden, wird das Ergebnis als ASCII-Zeichenkette ausgegeben. Bei Daten einer anderen Größe, die aber keine Folge druckbarer Zeichen sind, wird das Ergebnis als eine Folge von Byte-Werten im Hexadezimalformat ausgegeben.