Show Table of Contents
3.3. 基本的な SystemTap ハンドラーコンストラクト
SystemTap は、ハンドラーでいくつかの基本的なコンストラクトの使用をサポートしています。これらハンドラーコンストラクトのほとんどの構文は、 C および
awk 構文に基づいています。本セクションでは、SystemTap ハンドラーコンストラクトで最も有用なものをいくつか説明します。これで、簡潔かつ便利な SystemTap スクリプトの作成ができるようになります。
3.3.1. 変数
ハンドラーでは、変数を自由に使うことができます。名前を選択し、関数もしくは式から値を割り当て、式内で値を使用します。SystemTap は、割り当てられた値のタイプに基づいて、自動的に変数が文字列か整数かを識別します。たとえば、変数
var を gettimeofday_s() に設定すると (var = gettimeofday_s() として)、すると var は数字として識別され、printf() では整数書式の指定子 (%d) でプリントされます。
ただしデフォルトでは、変数は使用されているプローブのみのローカルとなります。つまり、変数はプローブハンドラーが呼び出されるたびに初期化され、使用され、破棄されます。複数のプローブで変数を共有するには、プローブの外で
global を使用して変数名を宣言する必要があります。以下で例を見てみましょう。
例3.8 timer-jiffies.stp
global count_jiffies, count_ms
probe timer.jiffies(100) { count_jiffies ++ }
probe timer.ms(100) { count_ms ++ }
probe timer.ms(12345)
{
hz=(1000*count_jiffies) / count_ms
printf ("jiffies:ms ratio %d:%d => CONFIG_HZ=%d\n",
count_jiffies, count_ms, hz)
exit ()
}
例3.8「timer-jiffies.stp」 では、jiffies およびミリ秒をカウントするタイマーを使ってカーネルの
CONFIG_HZ 設定を計算し、それに応じて計算しています。global ステートメントにより、スクリプトは変数 count_jiffies と count_ms (各プローブで設定) を probe timer.ms(12345) と共有して使用することができます。
注記
例3.8「timer-jiffies.stp」 の
++ 表記 (count_jiffies ++ および count_ms ++) は、変数の値を 1 増やすために使用されます。以下のプローブでは、100 jiffies ごとに count_jiffies が 1 増えます。
probe timer.jiffies(100) { count_jiffies ++ }
この場合、SystemTap は
count_jiffies が整数であると理解します。count_jiffies には初期値が割り当てられていないことから、デフォルトでは初期値はゼロになります。
3.3.2. 条件付き (conditional) ステートメント
場合によっては、SystemTap script の出力が大きすぎることもあるかもしれません。これに対処するには、スクリプトの論理を細分化して、出力をプローブに関連するもしくは有用なものにする必要があります。
これはハンドラーで 条件 を使うことで実行できます。SystemTap は以下のタイプの条件付きステートメントを受け付けます。
- If/Else ステートメント
- 書式は以下のようになります。
if (condition) statement1 else statement2
statement1は、condition式がゼロ以外の場合に実行されます。statement2は、condition式がゼロの場合に実行されます。else節 (elsestatement2) はオプションです。statement1とstatement2の両方とも、ステートメントブロックとすることができます。例3.9 ifelse.stp
global countread, countnonread probe kernel.function("vfs_read"),kernel.function("vfs_write") { if (probefunc()=="vfs_read") countread ++ else countnonread ++ } probe timer.s(5) { exit() } probe end { printf("VFS reads total %d\n VFS writes total %d\n", countread, countnonread) }例3.9「ifelse.stp」 は、5 秒間にシステムが実行する仮想ファイルシステム読み込み (vfs_read) と書き込み (vfs_write) をカウントするスクリプトです。この実行時には、プローブした関数の名前が (条件if (probefunc()=="vfs_read")の)vfs_readと一致する場合、スクリプトは変数countreadを 1 つ増やします。一致しない場合は、countnonread(else {countnonread ++}) を増やします。 - While ループ
- 書式は以下のようになります。
while (condition) statement
conditionがゼロ以外であれば、statement内のステートメントのブロックは実行されます。statementはステートメントブロックであることが多く、これが値を変更することでconditionが最終的にゼロになる必要があります。 - For ループ
- 書式は以下のようになります。
for (initialization; conditional; increment) statement
forループは、単に while ループの短縮形です。以下が同等のwhileループになります。initialization while (conditional) { statement increment }
- >=
- より大か等しい
- <=
- より小か等しい
- !=
- 等しくない
3.3.3. コマンドラインの引数
SystemTap スクリプトでは、
$ または @ の直後にコマンドライン上の引数の番号を続けることで、単純なコマンドライン引数を受け付けるようにすることができます。コマンドライン引数としてユーザーが整数を入力すると思われる場合は $ を、文字列が予測される場合は @ を使用します。
例3.10 commandlineargs.stp
probe kernel.function(@1) { }
probe kernel.function(@1).return { }
例3.10「commandlineargs.stp」 は 例3.1「wildcards.stp」 と似ていますが、(
stap commandlineargs.stp kernel function のように) プローブするカーネル関数をコマンドライン引数として渡すことができる点が異なります。また、@1、@2 のようにユーザーが入力した順番で複数のコマンドライン引数をスクリプトが受け付けるように指定することもできます。

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.