Red Hat Training

A Red Hat training course is available for Red Hat Enterprise Linux

3.2. SystemTap スクリプト

SystemTap スクリプトはそのほとんどにおいて、各 SystemTap セッションのベースになっています。SystemTap スクリプトが SystemTap に対してどのタイプの情報を収集するか、収集後に何をするかを指示します。
3章SystemTap の作動方法 の説明にあるように、SystemTap スクリプトは イベントハンドラー という 2 つのコンポーネントで設定されています。SystemTap セッションが開始されたら、SystemTap はオペレーティングシステムで指定されたイベントを監視し、イベントが発生したらハンドラーを実行します。
注記
イベントとそれに対応するハンドラーは、まとめて プローブ と呼ばれます。SystemTap スクリプトには複数のプローブを備えることができます。プローブのハンドラーは一般的に プローブボディー と呼ばれます。
アプリケーションの開発という面では、イベントとハンドラーの使用は診断出力ステートメントをコマンドのプログラムシーケンスに挿入するというコードのインストルメント化に似ています。診断出力ステートメントを使用すると、プログラムの実行後に発行されたコマンドの履歴をみることができます。
SystemTap スクリプトでは、コードを再コンパイルすることなくインストルメンテーションコードの挿入が可能で、ハンドラーに関する柔軟性が広がります。イベントは、ハンドラー実行の引き金となります。ハンドラーは指定されたデータを記録して、特定の方法で出力するよう指定できます。

形式

SystemTap スクリプトは、ファイル拡張子 .stp を使用し、以下の書式のプローブを含んでいます。

probe event {statements}
SystemTap は 1 つのプローブにつき複数のイベントをサポートしており、複数イベントはコンマ (,) で区切ります。1 つのプローブで複数のイベントが指定された場合、SystemTap は指定されたイベントが発生するとそのハンドラーを実行します。
プローブにはそれぞれ、対応する ステートメントブロック があります。このステートメントブロックは中括弧 ({ }) で囲まれており、イベントごとに実行されるステートメントが含まれています。SystemTap はこれらのステートメントを順番に実行し、通常は複数のステートメントを分ける特別なセパレーターやターミネーターは必要ありません。
注記
SystemTap スクリプト内のステートメントブロックは、C プログラミング言語と同じ構文とセマンティクスを使用します。ステートメントブロックは、別のステートメントブロック内の入れ子状態にすることができます。
Systemtap では、多くのプローブが使用するコードを外に括り出して関数を作成することができます。つまり、複数のプローブで同じステートメントを何度も繰り返し書くのではなく、以下のように function 内に指示を配置することができます。
function function_name(arguments){statements}
probe event {function_name(arguments)}
function_namestatements は、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_openreturn を指定するには、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 では、多数のプローブイベントの使用をサポートしています。サポートされているイベントの詳細については、stapprobes(3) man ページを参照してください。stapprobes(3) の 『SEE ALSO』 セクションには、特定のサブシステムやコンポーネントでサポートされているイベントについて説明している他の man ページへのリンクも含まれています。