Contained Within
Find More Documentation
Featured Support Resources
| Download this book in PDF (2009 KB)
Chapter 12 Output Formatting
DTrace provides built-in formatting functions printf() and printa() that you can use from your D programs to format output.
The D compiler provides features not found in the printf(3C) library routine, so you should
read this chapter even if you are already familiar with printf().
This chapter also discusses the formatting behavior of the trace() function
and the default output format used by dtrace(1M) to display aggregations.
printf()
The printf() function combines the ability to trace data, as if by the trace() function, with the ability to output the data and other text
in a specific format that you describe. The printf() function
tells DTrace to trace the data associated with each argument after the first
argument, and then to format the results using the rules described by the
first printf() argument, known as a format string.
The format string is a regular string that contains any number of format
conversions, each beginning with the % character, that
describe how to format the corresponding argument. The first conversion in
the format string corresponds to the second printf() argument,
the second conversion to the third argument, and so on. All of the text between
conversions is printed verbatim. The character following the % conversion
character describes the format to use for the corresponding argument.
Unlike printf(3C),
DTrace printf() is a built-in function that is recognized
by the D compiler. The D compiler provides several useful services for DTrace printf() that are not found in the C library printf():
-
The D compiler compares the arguments to the conversions in
the format string. If an argument's type is incompatible with the format conversion,
the D compiler provides an error message explaining the problem.
-
The D compiler does not require the use of size prefixes with printf() format conversions. The C printf() routine
requires that you indicate the size of arguments by adding prefixes such as %ld for long or %lld for long long. The D compiler knows the size and type of your arguments,
so these prefixes are not required in your D printf() statements.
-
DTrace provides additional format characters that are useful
for debugging and observability. For example, the %a format
conversion can be used to print a pointer as a symbol name and offset.
In order to implement these features, the format string in the DTrace printf() function must be specified as a string constant in your
D program. Format strings may not be dynamic variables of type string.
Conversion Specifications
Each conversion specification in the
format string is introduced by the % character, after which
the following information appears in sequence:
-
Zero or more flags (in any order),
that modify the meaning of the conversion specification as described in the
next section.
-
An optional minimum field width. If
the converted value has fewer bytes than the field width, the value will be
padded with spaces on the left by default, or on the right if the left-adjustment
flag (-) is specified. The field width can also be specified
as an asterisk (*), in which case the field width is set
dynamically based on the value of an additional argument of type int.
-
An optional precision that indicates
the minimum number of digits to appear for the d, i, o, u, x, and X conversions
(the field is padded with leading zeroes); the number of digits to appear
after the radix character for the e, E,
and f conversions, the maximum number of significant digits
for the g and G conversions; or the
maximum number of bytes to be printed from a string by the s conversion.
The precision takes the form of a period (.) followed by
either an asterisk (*), described below, or a decimal digit
string.
-
An optional sequence of size prefixes that
indicate the size of the corresponding argument, described in Size Prefixes. The size prefixes are not necessary
in D and are provided for compatibility with the C printf() function.
-
A conversion specifier that indicates
the type of conversion to be applied to the argument.
The printf(3C) function
also supports conversion specifications of the form %n$ where n is
a decimal integer; DTrace printf() does not support this
type of conversion specification.
Flag Specifiers
The printf() conversion flags
are enabled by specifying one or more of the following characters, which may
appear in any order:
-
'
-
The integer portion of the result of a decimal conversion
(%i, %d, %u, %f, %g, or %G) is formatted
with thousands grouping characters using the non-monetary grouping character.
Some locales, including the POSIX C locale, do not provide non-monetary grouping
characters for use with this flag.
-
-
-
The result of the conversion is left-justified within the
field. The conversion is right-justified if this flag is not specified.
-
+
-
The result of signed conversion always begins with a sign
(+ or -). If this flag is not specified,
the conversion begins with a sign only when a negative value is converted.
-
space
-
If the first character of a signed conversion is not a sign
or if a signed conversion results in no characters, a space is placed before
the result. If the space and + flags
both appear, the space flag is ignored.
-
#
-
The value is converted to an alternate form if an alternate
form is defined for the selected conversion. The alternate formats for conversions
are described along with the corresponding conversion.
-
0
-
For d, i, o, u, x, X, e, E, f, g, and G conversions,
leading zeroes (following any indication of sign or base) are used to pad
to the field width. No space padding is performed. If the 0 and - flags both appear, the 0 flag is ignored. For d, i, o, u, x, and X conversions, if a precision is specified,
the 0 flag is ignored. If the 0 and ' flags both appear, the grouping characters are inserted before
the zero padding.
Width and Precision Specifiers
The minimum field width can
be specified as a decimal digit string following any flag specifier, in which
case the field width is set to the specified number of columns. The field
width can also be specified as asterisk (*) in which case
an additional argument of type int is accessed to determine
the field width. For example, to print an integer x in
a field width determined by the value of the int variable w, you would write the D statement:
printf("%*d", w, x);
The field width can also be specified using a ? character
to indicate that the field width should be set based on the number of characters
required to format an address in hexadecimal in the data model of the operating
system kernel. The width is set to 8 if the kernel is using the 32–bit
data model, or to 16 if the kernel is using the 64–bit data model.
The precision for the conversion can be specified as a decimal digit
string following a period (.) or by an asterisk (*)
following a period. If an asterisk is used to specify the precision, an additional
argument of type int prior to the conversion argument is
accessed to determine the precision. If both width and precision are specified
as asterisks, the order of arguments to printf() for the
conversion should appear in the following order: width, precision, value.
Size Prefixes
Size prefixes are required in ANSI-C programs
that use printf(3C) in
order to indicate the size and type of the conversion argument. The D compiler
performs this processing for your printf() calls automatically,
so size prefixes are not required. Although size prefixes are provided for
C compatibility, their use is explicitly discouraged in D programs because
they bind your code to a particular data model when using derived types. For
example, if a typedef is redefined to different integer
base types depending on the data model, it is not possible to use a single
C conversion that works in both data models without explicitly knowing the
two underlying types and including a cast expression, or defining multiple
format strings. The D compiler solves this problem automatically by allowing
you to omit size prefixes and automatically determining the argument size.
The size prefixes can be placed just prior to the format conversion
name and after any flags, widths, and precision specifiers. The size prefixes
are as follows:
-
An optional h specifies that a following d, i, o, u, x, or X conversion applies to a short or unsigned short.
-
An optional l specifies that a following d, i, o, u, x, or X conversion applies to a long or unsigned long.
-
An optional ll specifies that a following d, i, o, u, x, or X conversion applies to a long
long or unsigned long long.
-
An optional L specifies that a following e, E, f, g,
or G conversion applies to a long double.
-
An optional l specifies that a following c conversion applies to a wint_t argument,
and that a following s conversion character applies to
a pointer to a wchar_t argument.
Conversion Formats
Each conversion character sequence results
in fetching zero or more arguments. If insufficient arguments are provided
for the format string, or if the format string is exhausted and arguments
remain, the D compiler issues an appropriate error message. If an undefined
conversion format is specified, the D compiler issues an appropriate error
message. The conversion character sequences are:
-
a
-
The pointer or uintptr_t argument is printed
as a kernel symbol name in the form module`symbol-name plus
an optional hexadecimal byte offset. If the value does not fall within the
range defined by a known kernel symbol, the value is printed as a hexadecimal
integer.
-
c
-
The char, short, or int argument is printed as an ASCII character.
-
C
-
The char, short, or int argument is printed as an ASCII character if the character is
a printable ASCII character. If the character is not a printable character,
it is printed using the corresponding escape sequence as shown in Table 2–5.
-
d
-
The char, short, int, long, or long long argument
is printed as a decimal (base 10) integer. If the argument is signed,
it will be printed as a signed value. If the argument is unsigned,
it will be printed as an unsigned value. This conversion has the same meaning
as i.
-
e, E
-
The float, double, or long double argument is converted to the style [-]d.ddde±dd, where there is
one digit before the radix character and the number of digits after it is
equal to the precision. The radix character is non-zero if the argument is
non-zero. If the precision is not specified, the default precision value is
6. If the precision is 0 and the # flag is not specified,
no radix character appears. The E conversion format produces
a number with E instead of e introducing
the exponent. The exponent always contains at least two digits. The value
is rounded up to the appropriate number of digits.
-
f
-
The float, double, or long double argument is converted to the style [-]ddd.ddd,
where the number of digits after the radix character is equal to the precision
specification. If the precision is not specified, the default precision value
is 6. If the precision is 0 and the # flag is not specified,
no radix character appears. If a radix character appears, at least one digit
appears before it. The value is rounded up to the appropriate number of digits.
-
g, G
-
The float, double, or long double argument is printed in the style f or e (or in style E in the case of a G conversion
character), with the precision specifying the number of significant digits.
If an explicit precision is 0, it is taken as 1. The style used depends on
the value converted: style e (or E)
is used only if the exponent resulting from the conversion is less than -4
or greater than or equal to the precision. Trailing zeroes are removed from
the fractional part of the result. A radix character appears only if it is
followed by a digit. If the # flag is specified, trailing
zeroes are not removed from the result.
-
i
-
The char, short, int, long, or long long argument
is printed as a decimal (base 10) integer. If the argument is signed,
it will be printed as a signed value. If the argument is unsigned,
it will be printed as an unsigned value. This conversion has the same meaning
as d.
-
o
-
The char, short, int, long, or long long argument
is printed as an unsigned octal (base 8) integer. Arguments that are signed or unsigned may be used with this conversion.
If the # flag is specified, the precision of the result
will be increased if necessary to force the first digit of the result to be
a zero.
-
p
-
The pointer or uintptr_t argument is printed
as a hexadecimal (base 16) integer. D accepts pointer arguments of any type.
If the # flag is specified, a non-zero result will have 0x prepended to it.
-
s
-
The argument must be an array of char or
a string. Bytes from the array or string are
read up to a terminating null character or the end of the data and interpreted
and printed as ASCII characters. If the precision is not specified, it is
taken to be infinite, so all characters up to the first null character are
printed. If the precision is specified, only that portion of the character
array that will display in the corresponding number of screen columns is printed.
If an argument of type char * is to be formatted, it should
be cast to string or prefixed with the D stringof operator
to indicate that DTrace should trace the bytes of the string and format them.
-
S
-
The argument must be an array of char or
a string. The argument is processed as if by the %s conversion,
but any ASCII characters that are not printable are replaced by the corresponding
escape sequence described in Table 2–5.
-
u
-
The char, short, int, long, or long long argument
is printed as an unsigned decimal (base 10) integer. Arguments that are signed or unsigned may be used with this conversion,
and the result is always formatted as unsigned.
-
wc
-
The int argument is converted to a wide
character (wchar_t) and the resulting wide character is
printed.
-
ws
-
The argument must be an array of wchar_t.
Bytes from the array are read up to a terminating null character or the end
of the data and interpreted and printed as wide characters. If the precision
is not specified, it is taken to be infinite, so all wide characters up to
the first null character are printed. If the precision is specified, only
that portion of the wide character array that will display in the corresponding
number of screen columns is printed.
-
x, X
-
The char, short, int, long, or long long argument
is printed as an unsigned hexadecimal (base 16) integer. Arguments that are signed or unsigned may be used with this conversion.
If the x form of the conversion is used, the letter digits abcdef are used. If the X form of the conversion
is used, the letter digits ABCDEF are used. If the # flag
is specified, a non-zero result will have 0x (for %x)
or 0X (for %X) prepended to it.
-
Y
-
The uint64_t argument is interpreted to
be the number of nanoseconds since 00:00 Universal Coordinated Time, January
1, 1970, and is printed in the following cftime(3C) form: “%Y
%a %b %e %T %Z.” The current number of nanoseconds since 00:00
UTC, January 1, 1970 is available in the walltimestamp variable.
-
%
-
Print a literal % character. No argument
is converted. The entire conversion specification must be %%.
printa()
The printa() function is used to format the results of aggregations in
a D program. The function is invoked using one of two forms:
printa(@aggregation-name);
printa(format-string, @aggregation-name);
If the first form of the function is used, the dtrace(1M) command takes a consistent
snapshot of the aggregation data and produces output equivalent to the default
output format used for aggregations, described in Chapter 9, Aggregations.
If the second form of the function is used, the dtrace(1M) command takes a consistent
snapshot of the aggregation data and produces output according to the conversions
specified in the format string, according to the
following rules:
-
The format conversions must match the tuple signature used
to create the aggregation. Each tuple element may only appear once. For example,
if you aggregate a count using the following D statements:
@a["hello", 123] = count();
@a["goodbye", 456] = count();
and then add the D statement printa(format-string, @a) to a probe clause, dtrace will
snapshot the aggregation data and produce output as if you had entered the
statements:
printf(format-string, "hello", 123);
printf(format-string, "goodbye", 456);
and so on for each tuple defined in the aggregation.
-
Unlike printf(), the format string you
use for printa() need not include all elements of the tuple.
That is, you can have a tuple of length 3 and only one format conversion.
Therefore, you can omit any tuple keys from your printa() output
by changing your aggregation declaration to move the keys you want to omit
to the end of the tuple and then omit corresponding conversion specifiers
for them in the printa() format string.
-
The aggregation result can be included in the output by using
the additional @ format flag character, which is only valid
when used with printa(). The @ flag
can be combined with any appropriate format conversion specifier, and may
appear more than once in a format string so that your tuple result can appear
anywhere in the output and can appear more than once. The set of conversion
specifiers that can be used with each aggregating function are implied by
the aggregating function's result type. The aggregation result types are:
|
avg()
|
uint64_t
|
|
count()
|
uint64_t
|
|
lquantize()
|
int64_t
|
|
max()
|
uint64_t
|
|
min()
|
uint64_t
|
|
quantize()
|
int64_t
|
|
sum()
|
uint64_t
|
For example, to format the results of avg(),
you can apply the %d, %i, %o, %u, or %x format conversions. The quantize() and lquantize() functions format their results
as an ASCII table rather than as a single value.
The following D program shows a complete example of printa(),
using the profile provider to sample the value of caller and then formatting the results as a simple table:
profile:::profile-997
{
@a[caller] = count();
}
END
{
printa("%@8u %a\n", @a);
}
If you use dtrace to execute this program, wait a
few seconds, and press Control-C, you will see output similar to the following
example:
# 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
...
|
trace() Default Format
If
the trace() function is used to capture data rather than printf(), the dtrace command formats the results
using a default output format. If the data is 1, 2, 4, or 8 bytes in size,
the result is formatted as a decimal integer value. If the data is any other
size and is a sequence of printable characters if interpreted as a sequence
of bytes, it will be printed as an ASCII string. If the data is any other
size and is not a sequence of printable characters, it will be printed as
a series of byte values formatted as hexadecimal integers.
|