3.2. SystemTap スクリプト
SystemTap スクリプトはそのほとんどにおいて、各 SystemTap セッションのベースになっています。SystemTap スクリプトが SystemTap に対してどのタイプの情報を収集するか、収集後に何をするかを指示します。
「3章SystemTap の作動方法」の説明にあるように、SystemTap スクリプトは イベント と ハンドラー という 2 つのコンポーネントで構成されています。SystemTap セッションが開始されたら、SystemTap はオペレーティングシステムで指定されたイベントを監視し、イベントが発生したらハンドラーを実行します。
注記
イベントとそれに対応するハンドラーは、まとめて プローブ と呼ばれます。SystemTap スクリプトには複数のプローブを備えることができます。
プローブのハンドラーは一般的に プローブボディー と呼ばれます。
アプリケーションの開発という面では、イベントとハンドラーの使用は診断プリントステートメントをコマンドのプログラムシーケンスに挿入するというコードのインストルメント化に似ています。診断プリントステートメントを使用すると、プログラムの実行後に発行されたコマンドの履歴をみることができます。
SystemTap スクリプトでは、コードを再コンパイルすることなくインストルメンテーションコードの挿入が可能で、ハンドラーに関する柔軟性が広がります。イベントは、ハンドラー実行の引き金となります。ハンドラーは指定されたデータを記録して、特定の方法でプリントするよう指定できます。
probe event {statements}
SystemTap は 1 つのプローブにつき複数のイベントをサポートしており、複数イベントはコンマ (
,
) で区切ります。1 つのプローブで複数のイベントが指定された場合、SystemTap は指定されたイベントが発生するとそのハンドラーを実行します。
プローブにはそれぞれ、対応する ステートメントブロック があります。このステートメントブロックは中括弧 (
{ }
) で囲まれており、イベントごとに実行されるステートメントが含まれています。SystemTap はこれらのステートメントを順番に実行し、通常は複数のステートメントを分ける特別なセパレーターやターミネーターは必要ありません。
注記
SystemTap スクリプト内のステートメントブロックは、C プログラミング言語と同じ構文とセマンティクスを使用します。ステートメントブロックは、別のステートメントブロック内の入れ子状態にすることができます。
Systemtap では、多くのプローブが使用するコードを外に括り出して関数を作成することができます。つまり、複数のプローブで同じステートメントを何度も繰り返し書くのではなく、以下のように function 内に指示を配置することができます。
function function_name(arguments) {statements} probe event {function_name(arguments)}
statements
in function_name は、event のプローブの実行時に実行されます。arguments は、function に渡されるオプションの値です。
重要
「SystemTap スクリプト」 では、SystemTap スクリプトの基本を説明します。SystemTap スクリプトの理解を深めるには、「4章便利な SystemTap スクリプト」を参照してください。この章の各セクションでは、スクリプト、イベント、ハンドラー、および予測される出力を詳細に説明しています。
3.2.1. イベント
SystemTap のイベントは大まかに、同期 と 非同期 に分けられます。
同期イベントの例には以下のようなものがあります。
- syscall.system_call
- システムコール system_call へのエントリー。システムコールの終了を希望する場合は、
.return
をイベントに追加すると、システムコールの終了を監視するようになります。たとえば、システムコールclose
のエントリーと終了を指定するには、syscall.close
およびsyscall.close.return
をそれぞれ使用します。 - vfs.file_operation
- 仮想ファイルシステム (VFS) の file_operation イベントへのエントリー。
syscall
イベントと同様に、イベントに.return
を追加すると、file_operation 動作の終了を監視します。 - kernel.function("function")
- カーネル関数 function へのエントリー。たとえば、
kernel.function("sys_open")
は、カーネル関数sys_open
がシステム内のスレッドによって呼び出される際に発生する「イベント」を参照します。カーネル関数sys_open
の return を指定するには、kernel.function("sys_open").return
のように、return
文字列をイベントステートメントに追加します。プローブイベントを定義する際には、アスタリスク (*
) をワイルドカードに使用できます。また、カーネルソースファイル内の関数のエントリーまたは終了も追跡可能です。以下の例を見てみましょう。例3.1 wildcards.stp
probe kernel.function("*@net/socket.c") { } probe kernel.function("*@net/socket.c").return { }
この例では、最初のプローブのイベントはnet/socket.c
カーネルソースファイル内の全関数のエントリーを指定しています。2 つ目のプローブでは、これら全関数の終了を指定しています。この例では、ハンドラーにステートメントがないことに注意してください。このため、情報が収集されず、表示されることもありません。 - kernel.trace("tracepoint")
- tracepoint の静的プローブ。最近のカーネル (2.6.30 以降) には、カーネル内の特定イベント用のインストルメンテーションが含まれています。これらのイベントは、トレースポイントで静的にマークが付けられています。SystemTap で利用可能なトレースポイントの例としては、
kernel.trace("kfree_skb")
があります。これは、カーネル内でネットワークバッファーが解放されると合図します。 - module("module").function("function")
- モジュール内の関数のプローブを可能にします。以下に例を示します。
例3.2 moduleprobe.stp
probe module("ext3").function("*") { } probe module("ext3").function("*").return { }
例3.2「moduleprobe.stp」 の最初のプローブは、ext3
モジュールの 全 関数のエントリーを指しています。2 つ目のプローブは、同じモジュールの全関数の終了を指しています。.return
の接尾辞の使用は、kernel.function()
と類似します。例3.2「moduleprobe.stp」 のプローブは、プローブハンドラーにステートメントがないことに注意してください。このため、有用なデータは表示されません (例3.1「wildcards.stp」 の場合と同様)。システムのカーネルモジュールは通常/lib/modules/kernel_version
にあります。ここでの kernel_version は、現在読み込まれているカーネルのバージョンを指します。モジュールは、ファイル名拡張子.ko
を使用します。
非同期イベントの例には以下のようなものがあります。
- begin
- SystemTap スクリプトの実行と同時に、SystemTap セッションが起動します。
- end
- SystemTap セッションが終了します。
- timer イベント
- ハンドラーの定期実行を指定するイベントです。以下に例を示します。
例3.3 timer-s.stp
probe timer.s(4) { printf("hello world\n") }
例3.3「timer-s.stp」 は、4 秒ごとにhello world
をプリントするプローブの例です。以下のような timer イベントも使用できます。timer.ms(milliseconds)
timer.us(microseconds)
timer.ns(nanoseconds)
timer.hz(hertz)
timer.jiffies(jiffies)
情報を収集する他のプローブと併せて timer イベントを使用すると、定期的な更新が表示でき、その情報の変遷が分かります。
重要
SystemTap では、多数のプローブイベントの使用をサポートしています。サポートされるイベントの詳細は、
man stapprobes
を参照してください。man stapprobes
の 『SEE ALSO』 セクションには、特定のサブシステムやコンポーネントでサポートされているイベントについて説明している他の man
ページへのリンクも含まれています。