dtrace(1M) ユーティリティーを使用すると、D プログラムから、シェルスクリプトによく似たインタプリタファイルを作成することができます。このインタプリタファイルは、再利用可能な対話型 DTrace ツールとしてインストールできます。D コンパイラと dtrace コマンドは、D コンパイラの拡張機能である「マクロ変数」のセットを提供しています。DTrace スクリプトは、これらのマクロ変数を使って簡単に作成できます。この章では、マクロ変数の機能を紹介し、持続的なスクリプトを作成するためのヒントを示します。
シェルや、awk(1)、perl(1) などのユーティリティーと同じように、dtrace(1M) でも、実行可能なインタプリタファイルを作成できます。インタプリタファイルの先頭には、以下の形式の行が挿入されます。
#! pathname arg
pathname はインタプリタのパス、arg は単一の引数 (オプション) です。インタプリタファイルを実行すると、システムにより、指定されたインタプリタが呼び出されます。インタプリタファイル内に指定された arg (オプション) は、引数としてインタプリタに渡されます。インタプリタファイルのパスと、インタプリタファイルの実行時に指定されたその他の引数は、インタプリタ引数リストに追加されます。そのため、DTrace インタプリタファイルを作成するときは、最低限これらの引数を指定する必要があります。
#!/usr/sbin/dtrace -s
-s オプションの引数は、インタプリタファイルの実行時に、インタプリタファイルのパス名に変換されます。その後、dtrace によって、このファイルが読み取られ、コンパイル後、実行されます。これは、シェルウィンドウに次のコマンドを入力した場合と同じです。
# dtrace -s interpreter-file |
以下に、dtrace インタプリタファイルの作成例と実行例を示します。次の D ソースコードを記述し、interp.d という名前のファイルに保存してください。
#!/usr/sbin/dtrace -s BEGIN { trace("hello"); exit(0); }
interp.d ファイルを実行可能にして、実行します。
# chmod a+rx interp.d # ./interp.d dtrace: script './interp.d' matched 1 probe CPU ID FUNCTION:NAME 1 1 :BEGIN hello # |
ファイルの先頭には、これが指令であることを示す 2 文字 (#!) を必ず挿入してください。文字と文字の間、文字の前後には空白文字を入れないでください。D コンパイラは、インタプリタファイルを処理するとき、この行を自動的に無視します。
dtrace は、getopt(3C) を使ってコマンド行オプションを処理します。このため、複数のオプションを単一のインタプリタ引数として指定できます。たとえば、先ほどの例に -q オプションを追加して、インタプリタ指令を変更してみましょう。
#!/usr/sbin/dtrace -qs
複数のオプションを指定する場合、どのブール型オプションよりも後ろに -s オプションを指定します。そうしないと、このあとの引数 (インタプリタファイル名) が -s オプションの引数として処理されません。
インタプリタファイル内に、引数をとるオプションを複数指定する必要がある場合は、すべてのオプションと引数を単一のインタプリタ引数として指定できるとは限りません。この場合は、#pragma D option 指令構文を使ってオプションを設定します。すべての dtrace コマンド行オプションは、#pragma で設定できます (第 16 章オプションとチューニング可能パラメータを参照)。
D コンパイラには、D プログラムやインタプリタファイルの作成時に使用できる組み込みマクロ変数のセットが定義されています。マクロ変数は、ドル記号 ($) で始まる識別子です。D コンパイラは、入力ファイルの処理時に、この変数を 1 回だけ展開します。以下に、D コンパイラのマクロ変数を示します。
表 15–1 D マクロ変数
名前 |
説明 |
参照 |
---|---|---|
$[0-9]+ |
マクロ引数 |
「マクロ引数」を参照してください |
$egid |
実効グループ ID | |
$euid |
実効ユーザー ID | |
$gid |
実グループ ID | |
$pid |
プロセス ID | |
$pgid |
プロセスグループ ID | |
$ppid |
親プロセス ID | |
$projid |
プロジェクト ID | |
$sid |
セッション ID | |
$target |
ターゲットプロセス ID |
「ターゲットプロセス ID」を参照してください |
$taskid |
タスク ID | |
$uid |
実ユーザー ID |
マクロ引数 $[0-9]+ とマクロ変数 $target を除くすべてのマクロ変数は、展開されたあと、システム属性 (プロセス ID、ユーザー ID など) を表す整数になります。変数は、展開されたあと、現在の dtrace プロセスの属性値か、D コンパイラを実行しているプロセスの属性値になります。
インタプリタファイル内でマクロ変数を使用すると、使用するたびに編集を加える必要がない、持続的な D プログラムを作成できます。たとえば、dtrace コマンドによって実行されるものを除くすべてのシステムコールをカウントしたい場合は、以下の例のように、D プログラム節に $pid を指定します。
syscall:::entry /pid != $pid/ { @calls = count(); }
dtrace コマンドを呼び出すたびにプロセス ID は変化しますが、この節は、常に望ましい結果を返します。
マクロ変数は、D プログラム内の整数、識別子、または文字列の代わりに使用できます。マクロ変数は、入力ファイルの解析時に 1 回だけ (非再帰的に) 展開されます。各マクロ変数は、展開後、独立した入力トークンになります。これらを何らかのテキストと連結して 1 つのトークンにすることはできません。たとえば、$pid の展開後の値が 456 であるとして、次の D コードについて考えてみましょう。
123$pid
この D コードを展開すると、123 と 456 の 2 つのトークンが隣接する結果になり、構文エラーが返されます。単一の整数トークン 123456 が得られるわけではありません。
展開後のマクロ変数は、プログラム節の冒頭の D プローブ記述内では、隣接テキストと連結されます。たとえば、以下の節では、DTrace プロバイダ pid を使って dtrace コマンドを計測できます。
pid$pid:libc.so:printf:entry { ... }
マクロ変数は、各プローブ記述フィールド内で 1 回だけ展開されます。プローブ記述の区切り文字 (:) を含めることはできません。
D コンパイラは、マクロ変数のセットも提供します。これらのマクロ変数は、dtrace コマンド呼び出しで指定する引数オペランドに対応しています。これらの「マクロ引数」へのアクセスには、組み込み名を使用します。D プログラムファイル名や dtrace コマンドには $0、最初の追加オペランドには $1、2 番目の追加オペランドには $2 (以下同様) を指定します。dtrace の -s オプションを指定した場合、$0 は、このオプションとともに指定する入力ファイルの名前になります。コマンド行に D プログラムを指定した場合は、$0 は、dtrace 自体を実行するとき使用する argv[0] の値になります。
マクロ引数は、そのテキストの形式によって、整数、識別子、または文字列に展開されます。マクロ引数は、すべてのマクロ変数と同じように、D プログラム内の整数、識別子、文字列トークンの代わりに使用できます。以下に示す例はいずれも、適切なマクロ変数を指定すれば、有効な D 式になります。
execname == $1 /* with a string macro argument */ x += $1 /* with an integer macro argument */ trace(x->$1) /* with an identifier macro argument */
マクロ引数を使って作成した dtrace インタプリタファイルは、実際の Solaris コマンドと同じように機能し、ユーザーやその他のツールによって指定された情報に従って動作を変えます。たとえば次の D インタプリタファイルは、特定のプロセス ID で実行される write(2) システムコールをトレースします。
#!/usr/sbin/dtrace -s syscall::write:entry /pid == $1/ { }
このインタプリタファイルを実行可能ファイルにした場合、コマンド行引数を追加して、$1 の値を指定できます。
# chmod a+rx ./tracewrite # ./tracewrite 12345 |
このコマンド呼び出しでは、プロセス ID 12345 で実行される各 write(2) システムコールがカウントされます。
D プログラムが参照するマクロ引数がコマンド行に指定されていない場合は、プログラムを正常にコンパイルすることができず、エラーメッセージが表示されます。
# ./tracewrite dtrace: failed to compile script ./tracewrite: line 4: macro argument $1 is not defined |
D プログラムに未知のマクロ引数を参照させたい場合は、defaultargs オプションを指定します。defaultargs オプションを指定した場合、未知の引数の値は 0 になります。D コンパイラオプションの詳細については、第 16 章オプションとチューニング可能パラメータを参照してください。コマンド行に、D プログラムが参照しない引数を指定した場合も、D コンパイラはエラーを返します。
マクロ引数の値は、整数、識別子、または文字列の形式になっていなければなりません。それ以外の形式の場合、D コンパイラはエラーを返します。DTrace インタプリタファイルに文字列形式のマクロ引数を指定するときは、シェルが二重引用符や文字列の内容を解釈しないように、引数をさらに単一引用符で囲みます。
# ./foo '"a string argument"' |
D マクロ引数が整数または識別子の形式になっている場合でも、あえて文字列トークンとして解釈したい場合は、マクロ変数またはマクロ引数の名前の前に、ドル記号を 2 つ追加します (例: $$1)。こうすれば、D コンパイラは、引数を「二重引用符で囲まれた文字列」と見なすようになります。通常の D 文字列エスケープシーケンス (表 2–5 を参照) はすべて、文字列形式のマクロ引数の内部で展開されます。これは、$arg や $$arg の形式のマクロで参照されている場合でも変わりません。defaultargs オプションが指定されている場合、$$arg の形式で参照される未知の引数の値は、空文字列 ("") になります。
dtrace コマンド行の p オプションで選択された、または -c オプションで作成された特定のユーザープロセスに適用できるスクリプトを作成したい場合は、-$target マクロ変数を使用します。コマンド行に指定された D プログラムや -s オプションで指定された D プログラムのコンパイルは、プロセスが作成されるか取り込まれるかして、$target 変数がこれらのプロセスのうち最初のプロセスのプロセス ID を表す整数に展開されたあと行われます。たとえば、次の D スクリプトでは、特定の従属プロセスによって実行されるシステムコールの内訳がわかります。
syscall:::entry /pid == $target/ { @[probefunc] = count(); }
このスクリプトを syscall.d という名前のファイルに保存し、次のコマンドを実行すると、date(1) コマンドによって実行されるシステムコール数を特定できます。
# dtrace -s syscall.d -c date dtrace: script 'syscall.d' matched 227 probes Fri Jul 30 13:46:06 PDT 2004 dtrace: pid 109058 has exited gtime 1 getpid 1 getrlimit 1 rexit 1 ioctl 1 resolvepath 1 read 1 stat 1 write 1 munmap 1 close 2 fstat64 2 setcontext 2 mmap 2 open 2 brk 4 |