はじめに
Dtrace は Solaris 10 に導入された機能で、OS やアプリケーションなどの様々な情報がトレースできる機能です。Dtrace の概要や使い方に関する記事はウェブ上でたくさん紹介されておりますので、本記事では少し実用的な例を 2つ紹介したいと思います。
1.ユーザープログラムにプローブ埋め込みトレース
プログラムのデバッグ方法として#ifdef
と共にprintf()
を埋め込み、各所の変数の値を表示することがあげられると思います。ただこの方法だとデバッグ情報を出力させるかさせないかを切り替える際に、リコンパイルが必要となります。
Dtrace を利用すればリコンパイルすること無しに、必要なときだけデバッグ情報を表示させることができます。以降ではプログラムにプローブを埋め込んだ簡単な例を紹介します。
準備として、プログラム内の観測したいポイントにプローブを埋め込むことと、独自のプロバイダを定義することの 2つが必要です。プローブはDTRACE_PROBE,DTRACE_PROBE1, DTRACE_PROBE2 … などを使用します。これらはでマクロ定義されています。
以下の sample.c では、v1, v2 という 2つの変数の値を 3箇所でトレースできるようにプローブを埋め込んでいます。myprovider.d ではプロバイダを定義しています。myprovider がプロバイダ名で、probe_v1 や probe_v2 がプローブ名となります。DTRACE_PROBE2 を使用すると引数が 2つ渡せるので、変数名も引数に含めれば定義するプローブを一つで済ますこともできます。
sample.c
#include <sys/sdt.h>
int v1 = 1;
int main(void)
{
int v2 = 1;
v1 = func(v2);
DTRACE_PROBE1(myprovider, probe_v1, v1);
DTRACE_PROBE1(myprovider, probe_v2, v2);
}
int func(int v)
{
DTRACE_PROBE1(myprovider, probe_v1, v1);
return (v1 + v);
}
myprovider.d
provider myprovider {
probe probe_v1(int);
probe probe_v2(int);
};
コンパイルは以下のように行います。sample.c と myprovider.dをコンパイルして、最後にリンクさせます。
# gcc -c sample.c # dtrace -G -32 -s myprovider.d sample.o # gcc -o sample myprovider.o sample.o
これで準備は整いました。sample を実行しただけではデバッグ情報は出力されません。
Dtace で埋め込んだプローブの情報を確認したい場合は、従来と同様にスクリプトを作成してトレースします。
以下がサンプルスクリプトとなります。プロバイダ名には pidプロバイダと同様にプロセスID を付ける必要があります。本記事の例では、dtrace の -c オプションと$target を使用することでプロセスID を渡しています。
trace_sample.d
myprovider$target:::probe_v1
{
printf("v1 = %dn", arg0);
}
myprovider$target:::probe_v2
{
printf("v2 = %dn", arg0);
}
dtrace を実行すると、以下のようにプローブポイントでの変数の値が確認できます。
# dtrace -s trace_sample.d -c sample dtrace: script 'trace_sample.d' matched 3 probes CPU ID FUNCTION:NAME 0 76570 func:probe_v1 v1 = 1 0 76571 main:probe_v1 v1 = 2 0 76572 main:probe_v2 v2 = 1 dtrace: pid 6538 exited with status 24 #