3.2. SystemTap スクリプト
注記
probe event {statements},) で区切ります。1 つのプローブで複数のイベントが指定された場合、SystemTap は指定されたイベントが発生するとそのハンドラーを実行します。
{ }) で囲まれており、イベントごとに実行されるステートメントが含まれています。SystemTap はこれらのステートメントを順番に実行し、通常は複数のステートメントを分ける特別なセパレーターやターミネーターは必要ありません。
注記
function function_name(arguments){statements}
probe event {function_name(arguments)}重要
3.2.1. イベント
- 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(ミリ秒)timer.us(マイクロ秒)timer.ns(ナノ秒)timer.hz(ヘルツ)timer.jiffies(jiffies)
timer イベントを情報を収集する他のプローブと併せて使用すると、定期的な更新が表示でき、その情報の変遷が分かります。
重要
3.2.2. Systemtap ハンドラー/ボディ
例3.4 helloworld.stp
probe begin
{
printf ("hello world\n")
exit ()
}
begin イベント (セッションの開始) が { } で囲まれているハンドラーを始動させます。これは単に hello world をプリントして改行し、終了するものです。
printf() ステートメントは、データをプリントする最も簡単な関数の 1 つです。printf() を以下の書式で使用すると、多くの SystemTap 関数を使用するデータを表示できます。
printf ("format string\n", arguments)
hello world のプリントを指示するだけで、書式は指定していません。
%s (文字列用) や %d (数字用) といった書式指定子を format string に使用することもできます。format string には複数の書式指定子を使用することが可能で、それぞれを対応する引数に一致させます。複数の引数はコンマ (,) で区切ります。
注記
例3.5 variables-in-printf-statements.stp
probe syscall.open
{
printf ("%s(%d) open\n", execname(), pid())
}
open への全エントリーをプローブするように指示しています。各イベントでは、現行の execname() (実行可能ファイル名の付いた文字列) と pid() (現行のプロセス ID 番号) に続けて open という単語をプリントします。このプローブ出力の抜粋は以下のようになります。
vmware-guestd(2206) open hald(2360) open hald(2360) open hald(2360) open df(3433) open df(3433) open df(3433) open hald(2360) open
SystemTap は、printf() 引数として使用可能な多くの関数をサポートしています。例3.5「variables-in-printf-statements.stp」では、SystemTap 関数 execname() (カーネル関数を呼び出した、またはシステムコールを実行したプロセス名) および pid() (現行プロセス ID) を使用しています。
- tid()
- 現行スレッドの ID。
- uid()
- 現行ユーザーの ID。
- cpu()
- 現行の CPU 番号。
- gettimeofday_s()
- Unix epoch (1970 年 1 月 1 日) からの秒数。
- ctime()
- UNIX epoch からの秒数を日にちに換算。
- pp()
- 現在処理されているプローブポイントを記述する文字列。
- thread_indent()
- この関数はプリント結果をうまく整理するので、便利なものです。この関数はインデント差分の引数を取ります。これは、スレッドの「インデントカウンター」に追加する、またはそこから取り除くスペースの数を示すものです。その後、適切なインデントスペースの数と一般的な追跡データの文字列を返します。ここで返される一般的なデータに含まれるのは、タイムスタンプ (スレッドの
thread_indent()への最初のコールからのマイクロ秒)、プロセス名、およびスレッド ID です。これによりどの関数がコールされたか、誰がコールしたか、各関数コールの長さが特定できます。各コールが終わり次第、次のコールが始まれば、エントリーと終了の一致は容易ですが、ほとんどの場合では最初の関数コールのエントリーがなされた後、これが終了する前に他の複数のコールが開始、終了したりすることがあります。インデントカウンターがあることで、最初のコールが終了していない場合、次の関数コールをインデントして、エントリーとそれに対応する終了が一致しやすくなります。以下でthread_indent()の使用例を見てみましょう。例3.6 thread_indent.stp
probe kernel.function("*@net/socket.c") { printf ("%s -> %s\n", thread_indent(1), probefunc()) } probe kernel.function("*@net/socket.c").return { printf ("%s <- %s\n", thread_indent(-1), probefunc()) }0 ftp(7223): -> sys_socketcall 1159 ftp(7223): -> sys_socket 2173 ftp(7223): -> __sock_create 2286 ftp(7223): -> sock_alloc_inode 2737 ftp(7223): <- sock_alloc_inode 3349 ftp(7223): -> sock_alloc 3389 ftp(7223): <- sock_alloc 3417 ftp(7223): <- __sock_create 4117 ftp(7223): -> sock_create 4160 ftp(7223): <- sock_create 4301 ftp(7223): -> sock_map_fd 4644 ftp(7223): -> sock_map_file 4699 ftp(7223): <- sock_map_file 4715 ftp(7223): <- sock_map_fd 4732 ftp(7223): <- sys_socket 4775 ftp(7223): <- sys_socketcall
このサンプル出力には、以下の情報が含まれています。- スレッドの最初の
thread_indent()コールからの時間 (マイクロ秒単位)。 - 関数コールを実施したプロセス名 (およびその対応 ID)。
- コールがエントリー (
<-) か終了 (->) かを示す矢印。インデントがあることで、コールのエントリーと終了が一致しやすくなります。 - プロセスが呼び出した関数名。
- name
- 特定のシステムコールの名前を識別します。この変数は、イベント
syscall.system_callを使用するプローブでのみ、使用可能です。 - target()
- 以下の 2 つのコマンドのいずれかと併せて使用します。
stap script -x process IDstap script -c commandプロセス ID またはコマンドの引数を取るスクリプトを指定したい場合、スクリプト内で参照先となる変数としてtarget()を使用します。例を示します。例3.7 targetexample.stp
probe syscall.* { if (pid() == target()) printf("%s/n", name) }例3.7「targetexample.stp」 を引数-x process IDと実行すると、(syscall.*イベントで指定された) すべてのシステムコールを監視し、指定されたプロセスで実行された全システムコールの名前をプリントします。これは、特定のプロセスをターゲットとしたい場合に毎回if (pid() == process ID)と指定することと同様の効果があります。ただし、target()を使用するとスクリプトの再利用が容易になり、スクリプトの実行時に引数としてプロセス ID を渡すだけで済みます。例を示します。stap targetexample.stp -x process ID

Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.