3.3. 基本的な SystemTap ハンドラーコンストラクト

SystemTap は、ハンドラーでいくつかの基本的なコンストラクトの使用をサポートしています。これらハンドラーコンストラクトのほとんどの構文は、 C および awk 構文に基づいています。本セクションでは、SystemTap ハンドラーコンストラクトで最も有用なものをいくつか説明します。これで、簡潔かつ便利な SystemTap スクリプトの作成ができるようになります。

3.3.1. 変数

ハンドラーでは、変数を自由に使うことができます。名前を選択し、関数もしくは式から値を割り当て、式内で値を使用します。SystemTap は、割り当てられた値のタイプに基づいて、自動的に変数が文字列か整数かを識別します。たとえば、変数 vargettimeofday_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_jiffiescount_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 節 (else statement2) はオプションです。statement1statement2 の両方とも、ステートメントブロックとすることができます。

例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 のようにユーザーが入力した順番で複数のコマンドライン引数をスクリプトが受け付けるように指定することもできます。

このページには機械翻訳が使用されている場合があります (詳細はこちら)。