6 出力フォーマット

DTraceには、フォーマット設定関数としてprintfprintaが組み込まれており、Dプログラムから使用して出力のフォーマットを設定できます。Dコンパイラには、Cライブラリのprintf()ルーチンにはない機能があるため、すでにprintfをよく理解している場合でもこの章はお読みください。

この章では、trace関数のフォーマット設定機能と、dtraceコマンドが集積体を表示するときに使用するデフォルトの出力フォーマットについても説明します。

printfアクション

printfアクションには、trace関数と同じようにデータをトレースする機能に、データや他のテキストを指定のフォーマットで出力する機能が組み合されています。printfからDTraceに対する指示により、最初の引数の後ろにある各引数に関連付けられたデータがトレースされ、フォーマット文字列と呼ばれる最初のprintf引数によって記述されるルールを使用して、結果がフォーマットされます。フォーマット文字列は、任意の数のフォーマット変換を含む規則的な文字列です。それぞれ%文字で始まり、対応する引数のフォーマット設定方法を決定します。フォーマット文字列の最初の変換が2番目のprintf引数に対応し、2番目の変換が3番目の引数に対応し、以降同様に続きます。変換と変換の間のテキストは一語一句そのまますべて出力されます。%変換文字に続く文字が、対応する引数に対して使用されるフォーマットを表します。

Cライブラリのprintf()関数とは異なり、DTraceのprintf関数はDコンパイラによって認識される組込み関数です。Dコンパイラには、printf()にはない、次を含む便利なサービスがDTrace printf関数のためにいくつか用意されています。

  • Dコンパイラは、引数をフォーマット文字列の変換と比較します。引数の型とフォーマット変換に互換性がない場合、Dコンパイラはその問題を示すエラー・メッセージを表示します。

  • Dコンパイラは、printfのフォーマット変換でサイズ接頭辞を使用する必要がありません。Cのprintfルーチンは、%ld (long,の場合)、%lld (long longの場合)などの接頭辞を追加して、引数のサイズを指定する必要があります。Dコンパイラは、引数の型とサイズを認識するため、Dのprintf文ではこのような接頭辞が不要です。

  • DTraceには、デバッグと監視に役立つフォーマット文字が追加されています。たとえば、%aフォーマット変換を使用すると、ポインタをシンボル名およびオフセットとして出力できます。

このような機能を実装するには、Dプログラムにおいて、DTraceのprintf関数のフォーマット文字列を文字列定数として指定する必要があります。フォーマット文字列は、string型の動的変数としては使用できません。

変換指定

フォーマット文字列の変換指定はそれぞれ%で始まり、続けて次の情報を順番に指定します。

  • 0個以上のフラグ(順番は任意)。「フラグ指定子」で説明するように、変換指定の意味を変更します。

  • 最小フィールド幅(オプション)。変換後の値のバイト数がフィールド幅より小さい場合には、値が空白文字で埋められます。埋められるのは、デフォルトでは値の左側、左揃えフラグ(-)を指定している場合は右側です。フィールド幅は、アスタリスク(*)でも指定でき、この場合のフィールド幅は、int型の追加の引数の値に基づいて動的に設定されます。

  • 次のことを示すオプションのprecision指定子。

    • diouxおよびXの各変換に対して表示される最小桁数。フィールドは先頭のゼロで埋められます。これは、eEおよびfの変換の基数文字の後に表示される桁数です。

    • gおよびGの各変換の最大有効桁数。

    • または、s変換によって文字列から出力される最大バイト数。

    精度の指定子は、ピリオド(.)の後にアスタリスク(*)を続けるか、ピリオドの後に10進数文字列を続けて指定します。「幅と精度の指定子」を参照してください。

  • 一連のサイズ接頭辞(オプション)。対応する引数のサイズを指定します。サイズ接頭辞は、Dでは必要ありませんが、Cのprintf()関数との互換性のために用意されています。

  • 変換指定子。引数に適用される変換のタイプを指定します。

Cのprintf()関数は、%n$,という形式(nは10進整数)の変換指定もサポートしています。DTraceのprintf関数では、このタイプの変換指定はサポートされていません。

フラグ指定子

printfの変換フラグを有効にするには、次の表に示すように、次の文字を1つ以上指定します。順序は問いません。
フラグ指定子 説明

'

10進変換(%d%f%g%G%iまたは%u)の結果のうち整数部分のフォーマットに、通貨文字を除くグループ化文字を使用して千桁区切りを指定します。POSIXのCロケールなど、ロケールによっては、このフラグと併用できる通貨文字以外のグループ化文字が用意されていません。(該当するのは、dtraceを実行しているロケールです。)

-

変換の結果を、フィールド内で左揃えします。このフラグを指定しない場合、変換は右揃えされます。

+

符号付きの変換の結果を、常に符号(+または-)で始めます。このフラグを指定しないと、負の値の変換の場合にのみ変換が符号で始まります。

space

符号付き変換の先頭文字が符号でない場合や、符号付き変換の結果として文字がなくなった場合に、結果の前に空白文字を追加します。spaceフラグと +フラグの両方を指定した場合は、spaceフラグが無視されます。

#

選択した変換に代替書式が定義されている場合に、値をその代替書式に変換します。変換の代替フォーマットについては、該当する変換の項を参照してください。

0

deEfgGiouxおよびXの各変換では、フィールド幅を埋めるために、先頭のゼロ(符号や底の指定の後)が使用され、スペースのパディングは実行されません。0フラグと -フラグの両方を指定した場合は、0フラグが無視されます。diouxおよびXの変換の場合は、精度を指定すると0フラグが無視されます。0フラグと'フラグの両方を指定した場合は、ゼロを埋め込む前にグループ化文字が挿入されます。

 幅と精度の指定子

最小フィールド幅を指定するには、任意のフラグ指定子の後に10進の文字列を続けます。この場合、フィールド幅は指定された桁数に設定されます。フィールド幅は、アスタリスク(*)でも指定でき、この場合はint型の追加の引数によってフィールド幅が決定されます。

たとえば、int型の変数wによって決定されるフィールド幅で整数xを出力するには、次のようなD文を記述します。

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

フィールド幅は、?文字でも指定できます。この場合は、オペレーティング・システム・カーネルのデータ・モデル内で、アドレスを(16進で)フォーマット設定するために必要な文字数に基づいて、フィールド幅が設定されます。幅は、カーネルが32ビットのデータ・モデルを使用している場合は8に、64ビットのデータ・モデルを使用している場合には16に設定されます。変換の精度は、ピリオド(.),に10進数の文字列を続けて、またはピリオドにアスタリスク(*)を続けて指定できます。アスタリスクを使用して精度を指定する場合、変換引数の前に追加したint型の引数によって精度が指定されます。フィールド幅と精度の両方をアスタリスクで指定した場合、変換のprintfの引数は、幅、精度、値の順で指定する必要があります。

サイズ接頭辞

ANSI Cプログラムでprintf()を使用する場合は、変換引数のサイズと型を指定するために、サイズ接頭辞が必要です。Dコンパイラは、printfコールでこの処理を自動的に実行するため、サイズ接頭辞は必要ありません。Cとの互換性のためにサイズ接頭辞は用意されていますが、Dプログラムでは明示的に非推奨となっています。派生型を使用するとき、コードが特定のデータ・モデルにバインドされるためです。

たとえば、データ・モデルに応じてtypedefを異なる整数基本型に再定義する場合、両方のデータ・モデルで機能する単一のC変換を使用するには、基礎となる2つの型を明示的に認識したうえで、キャスト式を追加するか、複数のフォーマット文字列を定義する必要があります。Dコンパイラは、サイズ接頭辞を省略可能にして引数のサイズを自動的に決定することによって、この問題を自動的に解決します。

サイズ接頭辞は、フォーマット変換名の前に、またフラグ、幅、精度の指定子があればその後ろに指定し、次のようになります。

  • h (オプション)。後に続くdiouxまたはX変換をshortまたはunsigned shortに適用することを指定します。

  • l (オプション)。後に続くdiouxまたはX変換をlongまたはunsigned longに適用することを指定します。

  • ll (オプション)。後に続くdiouxまたはX変換をlong longまたはunsigned long longに適用することを指定します。

  • L (オプション)。後に続くeEfgまたはG変換をlong doubleに適用することを指定します。

  • l (オプション)。後に続くc変換をwint_t引数に適用し、s変換文字をwchar_t引数のポインタに適用することを指定します。

変換フォーマット

変換文字の各シーケンスは、0個以上の引数をフェッチします。フォーマット文字列に指定された引数の数が不足している場合や、フォーマット文字列がなくなって引数が余る場合、または未定義の変換フォーマットが指定された場合、Dコンパイラは該当するエラー・メッセージを発行します。次の表では、変換文字のシーケンスについて説明します。
変換文字 説明

a

ポインタすなわちuintptr_t引数が、module'symbol-nameに任意の16進のバイト・オフセットを追加した形式のカーネル・シンボル名として出力されます。既知のカーネル・シンボルによって定義された範囲にない値は、16進の整数として出力されます。

A

%aと同じですが、ユーザー・シンボルに使用されます。

c

charshortまたはint引数がASCII文字として出力されます。

C

charshortまたはint引数が、出力可能なASCII文字であればASCII文字として出力されます。出力可能ではない文字の場合は、表2-6に示すように、対応するエスケープ・シーケンスを使用して出力されます。

d

charintlonglong longまたはshort引数が10進(base 10)の整数として出力されます。引数がsignedの場合、符号付きの値として出力されます。引数がunsignedの場合、符号なしの値として出力されます。この変換の意味はiと同じです。

eE

doublefloatまたはlong double引数が、[-]d.ddde[+-]ddというスタイル(基数の前に1桁があり、基数文字の後の桁数が精度と同じになる)に変換されます。引数がゼロ以外の場合、基数文字もゼロ以外になります。精度を指定しない場合、デフォルトの精度値は6です。精度が0#フラグを指定しない場合、基数文字は表示されません。E変換フォーマットは、eのかわりに、指数を導くEを使用して数値を生成します。指数は常に2桁以上です。値は、適切な桁数に丸められます。

f

doublefloatまたはlong double引数が、[-]ddd.dddというスタイル(基数文字の後の桁数が精度の指定と同じになる)に変換されます。精度を指定しない場合、デフォルトの精度値は6です。精度が0#フラグを指定しない場合、基数文字は表示されません。基数文字が表示される場合、その前に1桁以上の数字が表示されます。値は、適切な桁数に丸められます。

gG

doublefloatまたはlong double引数が、fまたはeのスタイル(あるいはG変換文字の場合にはEのスタイル)と、有効桁数を指定する精度で出力されます。明示的な精度が0の場合には、1とみなされます。使用されるスタイルは変換する値によって異なります。e (またはE)のスタイルは、変換で生成される指数が-4より小さいか、精度以上の場合にのみ使用されます。結果の小数部分から、後続のゼロは削除されます。基数文字は、後ろに1桁が続く場合にのみ表示されます。#フラグを指定すると、結果の小数部分から後続のゼロが削除されなくなります。

i

charintlonglong longまたはshort引数が10進(base 10)の整数として出力されます。引数がsignedの場合、符号付きの値として出力されます。引数がunsignedの場合、符号なしの値として出力されます。この変換の意味はdと同じです。

k

stack引数は、trace()のコールの場合と同じように出力され、カーネル・レベルのスタックを処理します。stackはD式からコールできないため、この引数はprintaでのみ有効です(Dプログラムのコンテキストが必要)。

o

charintlonglong longおよびshort引数が符号なしの8進(base 8)の整数として出力されます。この変換には、signedまたはunsignedの引数を使用できます。#フラグを指定すると、結果の精度が上がり、結果の最初の桁が強制的にゼロになります(必要な場合)。

p

ポインタすなわちuintptr_t引数が、16進(base 16)の整数として出力されます。Dは任意の型のポインタ引数をとります。#フラグを指定すると、ゼロ以外の結果の前に0xが付加されます。

s

引数は、charの配列または1つのstringです。配列またはstringのバイトが、終端NULL文字またはデータの末尾まで読み取られ、解釈されてからASCII文字として出力されます。精度を指定しない場合は無限とみなされるため、最初のNULL文字までのすべての文字が出力されます。精度を指定した場合は、対応する数の画面の列に表示される部分の文字配列のみが出力されます。char *型の引数をフォーマット設定する場合は、string型にキャストするか、接頭辞としてDの演算子stringofを付加して、DTraceが文字列のバイトをトレースしてそれらをフォーマット設定することを指示する必要があります。

S

引数は、charの配列またはstringです。引数は%s変換の場合と同じように処理されますが、出力可能ではないASCII文字があれば、表2-6に示すように、対応するエスケープ・シーケンスによって置き換えられます。

u

charintlonglong longまたはshort引数が符号なしの10進(base 10)の整数として出力されます。この変換には、signedまたはunsignedの引数を使用できます。結果は常にunsignedとしてフォーマットされます。

wc

int引数がワイド文字(wchar_t)に変換され、その結果のワイド文字が出力されます。

ws

引数は、wchar_tの配列です。配列のバイトが、終端NULL文字またはデータの末尾まで読み取られ、解釈されてからワイド文字として出力されます。精度を指定しない場合は無限とみなされるため、最初のNULL文字までのすべてのワイド文字が出力されます。精度を指定した場合は、対応する数の画面の列に表示される部分のワイド文字配列のみが出力されます。

xX

charintlonglong longまたはshort引数が符号なしの16進(base 16)の整数として出力されます。この変換には、signedまたはunsignedの引数を使用できます。x形式の変換を使用する場合は、文字の数字abcdefを使用します。X形式の変換を使用する場合は、文字の数字ABCDEFを使用します。#フラグを指定すると、ゼロ以外の結果の前に0x (%xの場合)、または0X (%Xの場合)が付加されます。

Y

uint64_t引数が、協定世界時の1970年1月1日00:00からの経過時間(ナノ秒数)として解釈され、「%Y %a %b %e %T %Z」という形式で出力されます。協定世界時の1970年1月1日00:00から現在までのナノ秒数は、walltimestamp変数として使用できます。

%

%文字をリテラルとして出力します。引数は変換されません。変換指定の全体は%%と指定する必要があります。

printaアクション

printaアクションを使用すると、Dプログラムで集積体の結果をフォーマット設定できます。この関数は、次のいずれかの形式を使用して呼び出します。

printa(@aggregation-name); 
printa(format-string, @aggregation-name);

関数の最初の形式を使用する場合、dtraceコマンドは常時、集積体データのスナップショットを取得し、集積体のデフォルト出力フォーマットと同じフォーマットで結果を出力します。「集積体」を参照してください。関数の2番目の形式を使用する場合、dtraceコマンドは常時、集積体データのスナップショットを取得し、次のルールに従ってフォーマット文字列に指定された変換に応じた出力を生成します。

  • フォーマット変換は、集積体を作成する際に使用したタプル・シグネチャと一致する必要があります。各タプル要素は1回ずつ使用できます。たとえば、次のようなD文でカウントを集積するとします。

    @a["hello", 123] = count(); 
    @a["goodbye", 456] = count();

    次に、プローブ節にD文printa(format-string , @a)を追加すると、dtraceは集積体データのスナップショットを取得し、次の文を入力した場合と同じ結果を出力します。

    printf(format-string, "hello", 123); 
    printf(format-string, "goodbye", 456);

    次に、集積体に定義されている各タプルも同様に処理します。

  • printfとは異なり、printaで使用するフォーマット文字列に、すべてのタプル要素を含める必要はありません。長さ3のタプルと1つのフォーマット変換のみを使用できます。したがって、printa出力では、任意のタプル・キーを省略できます。そのためには、集積体の宣言を変更して、省略するキーをタプルの末尾に移動し、そのキーに対応する変換指定子をprintaフォーマット文字列から除外します。

  • フォーマット設定フラグ文字@を追加すると、出力に集積体の結果が含まれます。これは、printaで使用した場合にのみ有効です。@フラグは、任意の適切な形式変換指定子と組み合せることができます。また、1つのフォーマット文字列にこのフラグを複数回含めることができるため、出力内の任意の場所にタプルの結果を複数回表示できます。各集積関数とともに使用できる変換指定子のセットは、集積関数の結果の型によって決まります。次の表に集積体の結果の型を示します。

集積体 結果の種類

avg

uint64_t

count

uint64_t

llquantize

int64_t

lquantize

int64_t

max

uint64_t

min

uint64_t

quantize

int64_t

sum

uint64_t

たとえば、avgの結果にフォーマットを設定するには、%d%i%o%u%xのいずれかのフォーマット変換を適用できます。quantizelquantizeおよびllquantize関数は、結果を単一の値としてではなくASCIIテーブルとしてフォーマット設定します。

次のDプログラムは、printaを使用する例を示しています。profileプロバイダを使用してcallerの値をサンプリングし、結果を単純な表としてフォーマット設定しています。次のソース・コードを入力し、printa.dという名前のファイルに保存します。

profile:::tick-1000
{
  @myagg[caller] = count();
}

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

dtraceコマンドを使用してこのプログラムを実行する場合は、数秒待ってから[Ctrl]キーを押しながら[C]キーを押します。次のような出力が表示されます。

# dtrace -qs printa.d
                  ^C
       1 vmlinux`do_syscall_64+0x2f
       1 vmlinux`___bpf_prog_run+0x528
       1 vmlinux`page_frag_free+0x3e
       1 vmlinux`__legitimize_mnt
       1 vmlinux`seq_printf+0x1b
       1 vmlinux`selinux_sb_show_options+0x39
       1 vmlinux`strchr+0x1f
       1 ip6_tables`ip6t_do_table+0xbb
       2 vmlinux`__raw_callee_save___pv_queued_spin_unlock+0x10
      14 libata`__dta_ata_sff_pio_task_1036+0x9e
   12975 vmlinux`native_safe_halt+0x6

traceのデフォルト・フォーマット

printfのかわりにtraceを使用してデータを取得する場合、dtraceコマンドがデフォルトの出力フォーマットを使用して結果をフォーマット設定します。データのサイズが1、2、4または8バイトの場合、結果は10進整数値としてフォーマット設定されます。データがこれ以外のサイズで、バイトのシーケンスとして解釈されるときに出力可能な文字である場合には、ASCII文字列として出力されます。データがこれ以外のサイズで、出力可能な文字のシーケンスでない場合には、16進整数としてフォーマット設定された一連のバイト値として出力されます。