この章では、いくつかの基本タスクの例を示しながら、DTrace の機能全般を紹介します。
dtrace コマンドに -l オプションを指定すると、DTrace の全プローブの一覧を表示できます。
# dtrace -l ID PROVIDER MODULE FUNCTION NAME 1 dtrace BEGIN 2 dtrace END 3 dtrace ERROR 4 syscall nosys entry 5 syscall nosys return 6 syscall rexit entry 7 syscall rexit return 8 syscall forkall entry 9 syscall forkall return 10 syscall read entry 11 syscall read return ... |
システム上で使用可能な全プローブの数を確認するには、次のコマンドを入力します。
# dtrace -l | wc -l |
報告されるプローブ数は、使用するオペレーティングプラットフォームとインストールされているソフトウェアの種類によって異なります。先ほどの例の BEGIN プローブと END プローブのように、MODULE 欄と FUNCTION 欄に何も表示されないことがあります。これらのフィールドが空になっているプローブは、特定の計測機能付きプログラムの関数や場所に対応していません。このようなプローブは、トレース要求の終わりなど、より抽象的な概念を表しています。プローブ名にモジュールや関数が含まれている場合、このプローブを「アンカーされたプローブ」と呼びます。特定のモジュールや関数に関連付けられていないプローブを「アンカーされていないプローブ」と呼びます。
次の例のように、オプションを追加して、特定のプローブだけを一覧表示できます。
特定の関数に関連するプローブだけを一覧するには、-f オプションとその関数名を DTrace に指定します。
# dtrace -l -f cv_wait ID PROVIDER MODULE FUNCTION NAME 12921 fbt genunix cv_wait entry 12922 fbt genunix cv_wait return |
特定のモジュールに関連するプローブだけを一覧するには、-m オプションとそのモジュール名を DTrace に指定します。
# dtrace -l -m sd ID PROVIDER MODULE FUNCTION NAME 17147 fbt sd sdopen entry 17148 fbt sd sdopen return 17149 fbt sd sdclose entry 17150 fbt sd sdclose return 17151 fbt sd sdstrategy entry 17152 fbt sd sdstrategy return ... |
指定の名前のプローブを一覧するには、-n オプションとプローブ名を DTrace に指定します。
# dtrace -l -n BEGIN ID PROVIDER MODULE FUNCTION NAME 1 dtrace BEGIN |
特定のプロバイダから提供されるプローブだけを一覧するには、-P オプションとそのプロバイダ名を DTrace に指定します。
# dtrace -l -P lockstat ID PROVIDER MODULE FUNCTION NAME 469 lockstat genunix mutex_enter adaptive-acquire 470 lockstat genunix mutex_enter adaptive-block 471 lockstat genunix mutex_enter adaptive-spin 472 lockstat genunix mutex_exit adaptive-release 473 lockstat genunix mutex_destroy adaptive-release 474 lockstat genunix mutex_tryenter adaptive-acquire ... |
一部の関数またはモジュールは、次の例のように、複数のプロバイダでサポートされることがあります。
# dtrace -l -f read ID PROVIDER MODULE FUNCTION NAME 10 syscall read entry 11 syscall read return 4036 sysinfo genunix read readch 4040 sysinfo genunix read sysread 7885 fbt genunix read entry 7886 fbt genunix read return |
これまでの例が示すように、プローブ一覧の出力内容は次のとおりです。
プローブに一意に割り当てられたプローブ ID (整数値)
プローブ ID の一意性は、Solaris オペレーティングシステムの同じリリース内または同じパッチレベル内でのみ確保されます。
プロバイダ名
モジュール名 (該当する場合)
関数名 (該当する場合)
プローブ名
プローブを一意に識別する 4 つの要素を指定することにより、プローブを完全指定できます。プローブは次の形式で指定します。provider:module:function:name。プローブの要素の指定を省略すると、任意の要素を指定したことになります。たとえば、fbt::alloc:entry は、次の属性のプローブを指定しています。
fbt プロバイダから提供されたプローブでなければならない
任意のモジュールに含まれるプローブでかまわない
alloc 関数に含まれるプローブでなければならない
プローブ名は entry でなければならない
4 つの要素のうち、前半は省略可能です。::open:entry と指定した場合、open:entry と指定したのと同じことになります。どちらも、すべてのプロバイダおよびカーネルモジュールからの、関数名が open、プローブ名が entry であるプローブを指定したことになります。
# dtrace -l -n open:entry ID PROVIDER MODULE FUNCTION NAME 14 syscall open entry 7386 fbt genunix open entry |
sh(1) のマニュアルページの「ファイル名の生成」のセクションに記載されている構文と同様のパターンマッチング構文を使って、プローブを指定することもできます。この構文では、特殊文字 *、?、[、および ] を使用できます。プローブ記述 syscall::open*:entry は、open と open64 の両方のシステムコールを意味します。? は、名前に含まれる任意の 1 文字を表します。[ と ] 文字は、名前に含まれる特定の文字列を指定するために使用します。
プローブを有効にするには、-l オプションを付けずにプローブを指定して、dtrace コマンドを実行します。指定のプローブが起動すると、DTrace はデフォルトのアクションを実行します。特別な指示は不要です。デフォルトのプローブアクションでは、指定のプローブが起動したことだけが示されます。それ以外のデータは記録されません。次に示すのは、sd モジュールに含まれるすべてのプローブを有効にするコード例です。
# dtrace -m sd CPU ID FUNCTION:NAME 0 17329 sd_media_watch_cb:entry 0 17330 sd_media_watch_cb:return 0 17167 sdinfo:entry 0 17168 sdinfo:return 0 17151 sdstrategy:entry 0 17152 sdstrategy:return 0 17661 ddi_xbuf_qstrategy:entry 0 17662 ddi_xbuf_qstrategy:return 0 17649 xbuf_iostart:entry 0 17341 sd_xbuf_strategy:entry 0 17385 sd_xbuf_init:entry 0 17386 sd_xbuf_init:return 0 17342 sd_xbuf_strategy:return 0 17177 sd_mapblockaddr_iostart:entry 0 17178 sd_mapblockaddr_iostart:return 0 17179 sd_pm_iostart:entry 0 17365 sd_pm_entry:entry 0 17366 sd_pm_entry:return 0 17180 sd_pm_iostart:return 0 17181 sd_core_iostart:entry 0 17407 sd_add_buf_to_waitq:entry ... |
この例の出力では、デフォルトアクションによって、プローブが起動した CPU、DTrace によって割り当てられたプローブ ID (整数値)、プローブが起動した関数、およびプローブ名が表示されています。
# dtrace -P syscall dtrace: description 'syscall' matched 452 probes CPU ID FUNCTION:NAME 0 99 ioctl:return 0 98 ioctl:entry 0 99 ioctl:return 0 98 ioctl:entry 0 99 ioctl:return 0 234 sysconfig:entry 0 235 sysconfig:return 0 234 sysconfig:entry 0 235 sysconfig:return 0 168 sigaction:entry 0 169 sigaction:return 0 168 sigaction:entry 0 169 sigaction:return 0 98 ioctl:entry 0 99 ioctl:return 0 234 sysconfig:entry 0 235 sysconfig:return 0 38 brk:entry 0 39 brk:return ... |
# dtrace -n zfod dtrace: description 'zfod' matched 3 probes CPU ID FUNCTION:NAME 0 4080 anon_zero:zfod 0 4080 anon_zero:zfod ^C |
# dtrace -n clock:entry dtrace: description 'clock:entry' matched 1 probe CPU ID FUNCTION:NAME 0 4198 clock:entry ^C |
DTrace は、アクションによって、DTrace フレームワーク外部のシステムと対話します。もっとも一般的なアクションは、DTrace バッファーへデータを記録するアクションです。そのほかに、現在のプロセスを停止するアクション、現在のプロセス内で特定のシグナルを発生させるアクション、トレースを中断するアクションなどがあります。システム状態を変更するアクションは、「破壊アクション」と見なされます。データ記録アクションは、デフォルトで、「主バッファー」にデータを記録します。主バッファーは、DTrace の呼び出し時に必ず使用されます。また、常に CPU 単位で割り当てられます。-cpu オプションを指定することにより、トレースとバッファーの割り当てを単一 CPU に制限できます。DTrace のバッファリングの詳細については、『Solaris 動的トレースガイド』の第 11 章「バッファーとバッファリング」 を参照してください。
ここからは、組み込み D 変数を使用する D 式の例を紹介していきます。次に示すのは、もっとも頻繁に使用する D 変数の一部です。
現在のプロセス ID を表す変数。
現在の実行可能ファイル名を表す変数。
起動時からの経過時間をナノ秒単位で表す変数。
現在のスレッドを示す kthread_t 構造体へのポインタを表す変数。
現在のプローブのモジュール名を表す変数。
現在のプローブの関数名を表す変数。
現在のプローブの名前を表す変数。
D スクリプト言語のすべての組み込み変数については、「DTrace の組み込み変数」を参照してください。
D スクリプト言語には、特定のアクションを実行する組み込み関数も用意されています。すべての組み込み関数については、『Solaris 動的トレースガイド』の第 10 章「アクションとサブルーチン」を参照してください。trace() 関数は、D 式の結果をトレースバッファーに記録します。次に例を示します。
trace(pid) - 現在のプロセス ID をトレースする
trace(execname) - 現在の実行可能ファイルの名前をトレースする
trace(curthread->t_pri) - 現在のスレッドの t_pri フィールドをトレースする
trace(probefunc) - プローブの関数名をトレースする
プローブに特定のアクションを実行させるときは、次の例のように、アクション名を {} 文字で囲んで指定します。
# dtrace -n 'readch {trace(pid)}' dtrace: description 'readch ' matched 4 probes CPU ID FUNCTION:NAME 0 4036 read:readch 2040 0 4036 read:readch 2177 0 4036 read:readch 2177 0 4036 read:readch 2040 0 4036 read:readch 2181 0 4036 read:readch 2181 0 4036 read:readch 7 ... |
この例で要求されるアクションは、trace(pid) です。したがって、一番右の欄にプロセス ID 番号 (PID) が出力されています。
# dtrace -m 'ufs {trace(execname)}' dtrace: description 'ufs ' matched 889 probes CPU ID FUNCTION:NAME 0 14977 ufs_lookup:entry ls 0 15748 ufs_iaccess:entry ls 0 15749 ufs_iaccess:return ls 0 14978 ufs_lookup:return ls ... 0 15007 ufs_seek:entry utmpd 0 15008 ufs_seek:return utmpd 0 14963 ufs_close:entry utmpd ^C |
# dtrace -n 'syscall:::entry {trace(timestamp)}' dtrace: description 'syscall:::entry ' matched 226 probes CPU ID FUNCTION:NAME 0 312 portfs:entry 157088479572713 0 98 ioctl:entry 157088479637542 0 98 ioctl:entry 157088479674339 0 234 sysconfig:entry 157088479767243 ... 0 98 ioctl:entry 157088481033225 0 60 fstat:entry 157088481050686 0 60 fstat:entry 157088481074680 ^C |
複数のアクションを指定する場合は、各アクションを ; 文字で区切って指定します。
# dtrace -n 'zfod {trace(pid);trace(execname)}' dtrace: description 'zfod ' matched 3 probes CPU ID FUNCTION:NAME 0 4080 anon_zero:zfod 2195 dtrace 0 4080 anon_zero:zfod 2195 dtrace 0 4080 anon_zero:zfod 2195 dtrace 0 4080 anon_zero:zfod 2195 dtrace 0 4080 anon_zero:zfod 2195 dtrace 0 4080 anon_zero:zfod 2197 bash 0 4080 anon_zero:zfod 2207 vi 0 4080 anon_zero:zfod 2207 vi ... |
この節では、デフォルトで主バッファーにデータを記録するアクションを紹介します。これらのアクションを使って、投機バッファーにデータを記録することもできます。投機バッファーについては、「投機トレース」を参照してください。
void trace(expression)
もっとも基本的なアクションは、D 式 expression を引数とし、指定バッファーに結果をトレースする trace() アクションです。
void tracemem(address, size_t nbytes)
tracemem() アクションは、メモリー内のアドレスからバッファーにデータをコピーします。nbytes には、このアクションによってコピーされるバイト数を指定します。address には、コピーされるデータのアドレスを D 式で指定します。指定バッファーにコピーします。
void printf(string format, ...)
printf() アクションは、trace() アクションと同じように D 式をトレースします。ただし、printf() アクションでは、printf(3C) 関数と同様の方法で書式を制御できます。printf 関数の場合と同じく、パラメータは format 文字列と任意の数の引数です。デフォルトでは、これらの引数が指定バッファーにトレースされます。その後、指定された書式設定文字列に従って、これらの引数に dtrace コマンドの出力書式が設定されます。
printf() アクションの詳細については、『Solaris 動的トレースガイド』の第 12 章「出力書式」を参照してください。
void printa(aggregation) void printa(string format, aggregation)
printa() アクションでは、集積体に書式を設定して表示できます。集積体の詳細については、『Solaris 動的トレースガイド』の第 9 章「集積体」を参照してください。format 値を省略した場合、printa() アクションは DTrace コンシューマへの指令だけをトレースします。その指令を受け取ったコンシューマは、集積体をデフォルトの書式に編集して表示します。printa() の書式文字列については、『Solaris 動的トレースガイド』の第 12 章「出力書式」を参照してください。
void stack(int nframes) void stack(void)
stack() アクションは、カーネルスタックトレースを指定バッファーに記録します。nframes には、カーネルスタックの深さを指定します。nframes 値を省略した場合、stack() アクションは、stackframes オプションで指定された数のスタックフレームを記録します。
void ustack(int nframes, int strsize) void ustack(int nframes) void ustack(void)
ustack() アクションは、指定バッファーにユーザースタックトレースを記録します。nframes には、ユーザースタックの深さを指定します。nframes 値を省略した場合、ustack アクションは、ustackframes オプションで指定された数のスタックフレームを記録します。ustack() アクションは、プローブが起動するときに、呼び出しフレームのアドレスを特定します。スタックフレームは、DTrace コンシューマがユーザーレベルで ustack() アクションを処理したときに、シンボルに翻訳されます。strsize にゼロ以外の値を指定した場合、ustack() アクションは指定された容量の文字列空間を割り当て、これを使ってカーネルから直接、アドレスからシンボルへの翻訳を行います。
void jstack(int nframes, int strsize) void jstack(int nframes) void jstack(void)
jstack() アクションは、ustack() アクションの別名で、スタックフレーム数については jstackframes オプションに指定されている値を使用します。jstackアクションは、jstackstrsize オプションに指定された値を使って、文字列空間のサイズを決定します。デフォルトでは、jstacksize アクションはゼロ以外の値になります。
破壊アクションを使用するためには、明示的な方法で有効にする必要があります。-w オプションを使用すれば、破壊アクションを有効にできます。破壊アクションを明示的に有効にしないまま、dtrace 内でその使用を試みると、dtrace は失敗し、次のようなメッセージが表示されます。
dtrace: failed to enable 'syscall': destructive actions not allowed
破壊アクションをはじめとする DTrace アクションについては、『Solaris 動的トレースガイド』の第 10 章「アクションとサブルーチン」を参照してください。
一部の破壊アクションは、特定のプロセスだけに影響を及ぼします。こうしたアクションを実行できるのは、dtrace_proc 権限か dtrace_user 権限を持つユーザーだけです。DTrace のセキュリティー権限については、『Solaris 動的トレースガイド』の第 35 章「セキュリティ」を参照してください。
プローブの起動によって stop() アクションが有効にされると、そのプローブを起動したプロセスはカーネルを出るときに停止します。このプロセスは、proc(4) アクションを使用してプロセスを停止したときと同じように停止します。
void raise(int signal)
raise() アクションは、現在実行中のプロセスに、指定されたシグナルを送信します。
void copyout(void *buf, uintptr_t addr, size_t nbytes)
copyout() アクションは、バッファーからメモリー内のアドレスへデータをコピーします。nbytes には、このアクションによってコピーされるバイト数を指定します。buf には、データのコピー元バッファーを指定します。addr には、データのコピー先のアドレスを指定します。現在のスレッドに関連付けられたプロセスのアドレス空間内にあるアドレスを指定してください。
void copyoutstr(string str, uintptr_t addr, size_t maxlen)
copyoutstr() アクションは、文字列をメモリー内のアドレスにコピーします。str には、コピーする文字列を指定します。addr には、文字列のコピー先のアドレスを指定します。現在のスレッドに関連付けられたプロセスのアドレス空間内にあるアドレスを指定してください。
void system(string program, ...)
system() アクションは、program で指定されたプログラムを、シェルに入力として渡されたときのようにして実行します。
システム全体に影響を及ぼす破壊アクションもあります。これらのアクションは慎重に使用してください。これらのアクションは、システムで実行中のすべてのプロセスに影響を及ぼします。さらに、そのシステムのネットワークサービスを使用しているその他のシステムに影響を及ぼすこともあります。
void breakpoint(void)
breakpoint() アクションは、カーネルブレークポイントを設定して、システムを停止し、カーネルデバッガに制御を移します。カーネルデバッガは、アクションを引き起こした DTrace プローブを表す文字列を発行します。
void panic(void)
panic() アクションが指定されているプローブが起動すると、カーネルパニックが発生します。このアクションを実行すると、必要に応じて強制的にシステムのクラッシュダンプを出力できます。このアクションをリングバッファリングや事後分析と組み合わせることで、 システムの問題を診断できます。詳細は、『Solaris 動的トレースガイド』の第 11 章「バッファーとバッファリング」と『Solaris 動的トレースガイド』の第 37 章「事後トレース」を参照してください。
void chill(int nanoseconds)
chill() アクションが指定されているプローブが起動すると、指定された時間 (ナノ秒) だけ DTrace が実行され続けます。chill() アクションは、タイミング関連の問題の調査に役立ちます。DTrace プローブコンテキストでは、割り込みは無効になります。このため、chill() を使用すると、割り込み遅延、スケジュール遅延、ディスパッチ遅延が発生します。
パフォーマンス関連の問題を調査するときは、通常、個々のデータポイントではなく、集積データを調べるほうが効果的です。DTrace には、いくつかの組み込みの集積関数が用意されています。データ集合のサブセットに集積関数を適用し、これらのサブセットの分析結果に再度集積関数を適用すると、データ集合全体に集積関数を適用した場合と同じ結果になります。
DTrace 機能は、集積のため、データ項目のランニングカウントを格納します。集積関数は、現在の中間結果と、関数の適用先の新規要素のみを格納します。中間結果は、CPU 単位で割り当てられます。この割り当て方式では、ロックは必要ありません。したがって、実装は本質的にスケーラブルです。
DTrace 集積体の一般構文は、次のとおりです。
@name[ keys ] = aggfunc( args );
この一般構文では、変数は次のように定義されています。
集積体の名前。先頭に @ 文字が付きます。
D 式をコンマで区切って指定します。
DTrace 集積関数のいずれか。
その集積関数に対応する引数をコンマで区切って指定します。
関数名 |
引数 |
結果 |
---|---|---|
count |
なし |
count 関数が呼び出される回数。 |
sum |
スカラー式 |
指定された式の合計値。 |
avg |
スカラー式 |
指定された式の算術平均。 |
min |
スカラー式 |
指定された式のうちもっとも小さい値。 |
max |
スカラー式 |
指定された式のうちもっとも大きい値。 |
lquantize |
スカラー式、下限値、上限値、ステップ値 |
指定された式の値から成る、指定された範囲の線形度数分布。この集積関数は、指定された式より小さい、最大バケット内の値を増分します。 |
quantize |
スカラー式 |
指定された式の値の二乗度数分布。この集積関数は、指定された式より小さい、2 のべき乗の最大バケット内の値を増分します。 |
次に示すのは、count 集積関数を使って、プロセスごとに write(2) システムコールの数をカウントする例です。この集積体は、dtrace コマンドが終了するまで、一切のデータを出力しません。出力される内容は、dtrace コマンドがアクティブであったときに収集されたデータの概要です。
# cat writes.d #!/usr/sbin/dtrace -s syscall::write:entry] { @numWrites[execname] = count(); } # ./writes.d dtrace: script 'writes.d' matched 1 probe ^C dtrace 1 date 1 bash 3 grep 20 file 197 ls 201 |