SystemTapの使い方(その2)


1 はじめに

systemtapの使い方の続編です。

インストール方法やその他の使い方は、下記を参照ください。
SystemTapの使い方
SystemTapの使い方(グルモード編)
SystemTapの使い方(User-Space Probing)
SystemTapの使い方(tapset編)

本記事の説明は、説明を簡単にするため、すべてbeginプローブ内でスクリプトを実行しました。
本記事の説明は、begin以外のendプローブ内や本体の部分でも実行できます。

2 環境

VMware Workstation 14 Playerで作成した仮想マシンを使用しました。
仮想マシンのOS版数は以下のとりです。

OS版数
[root@server ~]# cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)

[root@server ~]# uname -r
3.10.0-957.el7.x86_64

3 連想配列(Associative arrays)の使い方

連想配列とは、添え字にスカラー数値以外のデータ型(文字列型等)も使用できる配列のことです。
SystemTapの連想配列の構文は、配列名[インデックス]になります。
さらに、インデックスはカンマ区切りで最大9個までの値を指定できます。
たとえば、test["Hello"]foo[1,2,3,4,5,6,7,8,9]のような配列を定義することができます。

3.1 連想配列への値の代入方法、参照方法

配列testに10、配列fooに20を代入します。
そして、代入した値を表示してみます。

サンプル
[root@server ~]# cat tp.stp
#!/usr/bin/stap
global test
global foo

probe begin
{
  test["Hello"] = 10
  foo[1,2,3,4,5,6,7,8,9] = 20

  printf("test=%d,foo=%d\n",test["Hello"], foo[1,2,3,4,5,6,7,8,9])
  delete test
  exit()
}
実行結果
[root@server ~]# stap tp.stp
test=10,foo=20

3.2 連想値(associated value)のインクリメント、デクリメント

配列testに10、配列fooに20を代入します。
次に、testは1インクリメント、fooは1デクリメントします。
そして、連想値を表示してみます。

サンプル
[root@server ~]# cat tp.stp
#!/usr/bin/stap
global test
global foo

probe begin
{
  test["Hello"] = 10
  foo[1,2,3,4,5,6,7,8,9] = 20
  printf("test=%d,foo=%d\n",test["Hello"], foo[1,2,3,4,5,6,7,8,9])

  test["Hello"] ++
  foo[1,2,3,4,5,6,7,8,9] --
  printf("test=%d,foo=%d\n",test["Hello"], foo[1,2,3,4,5,6,7,8,9])

  delete test
  exit()
}
実行結果
[root@server ~]# stap tp.stp
test=10,foo=20
test=11,foo=19

3.3 繰り返しの使い方(foreach)

サンプル
[root@server ~]# cat tp.stp
#!/usr/bin/stap
global test

probe begin
{
  test[1, "Hello"] = 30
  test[2, "Hello"] = 10
  test[3, "Hello"] = 20

  foreach ([a,b] in test) {
    printf("a=%d,b=%s,test=%d\n",a,b,test[a,b])
  }

  delete test
  exit()
}
実行結果
[root@server ~]# stap tp.stp
a=1,b=Hello,test=30
a=2,b=Hello,test=10
a=3,b=Hello,test=20

3.4 繰り返しの使い方(降順に表示する方法)

配列testの第1インデックスをキーに降順に連想値を表示してみます。
降順に表示するため、[a,b][a-,b]に変更します。

サンプル(その1)
[root@server ~]# cat tp.stp
#!/usr/bin/stap
global test

probe begin
{
  test[1, "Hello"] = 30
  test[2, "Hello"] = 10
  test[3, "Hello"] = 20

  foreach ([a-,b] in test) {
    printf("a=%d,b=%s,test=%d\n",a,b,test[a,b])
  }

  delete test
  exit()
}
実行結果
[root@server ~]# stap tp.stp
a=3,b=Hello,test=20
a=2,b=Hello,test=10
a=1,b=Hello,test=30

今度は、配列testの連想値をキーに降順に連想値を表示してみます。
降順に表示するため、testtest-に変更します。

サンプル(その2)
[root@server ~]# cat tp.stp
#!/usr/bin/stap
global test

probe begin
{
  test[1, "Hello"] = 30
  test[2, "Hello"] = 10
  test[3, "Hello"] = 20

  foreach ([a,b] in test-) {
    printf("a=%d,b=%s,test=%d\n",a,b,test[a,b])
  }

  delete test
  exit()
}
実行結果
[root@server ~]# stap tp.stp
a=1,b=Hello,test=30
a=3,b=Hello,test=20
a=2,b=Hello,test=10

3.5 連想配列がキーを持つかどうかを判定する方法

サンプル
[root@server ~]# cat tp.stp
#!/usr/bin/stap
global test

probe begin
{
  test[1, "Hello"] = 30
  test[2, "Hello"] = 10
  test[3, "Hello"] = 20

  if([1,"Hello"] in test)
    printf("1000\n")
  if([2,"Hello"] in test)
    printf("2000\n")
  if([3,"Hello"] in test)
    printf("3000\n")

  delete test
  exit()
}
実行結果
[root@server ~]# stap tp.stp
1000
2000
3000

4 統計集計 (Statistical Aggregates) の使い方

統計集計に値を追加するには、演算子<<<を使用します。

4.1 個数を求める方法(@count)

配列testに10を代入してみます。

スクリプト(個数が1個の場合)
[root@server ~]# cat tp.stp
#!/usr/bin/stap
global test

probe begin
{
  test[100] <<< 10
  printf("count=%d\n", @count(test[100]))
  delete test
  exit()
}
実行結果
[root@server ~]# stap tp.stp
count=1

配列testに10と20を代入してみます。

スクリプト(個数が2個の場合)
[root@server ~]# cat tp.stp
#!/usr/bin/stap
global test

probe begin
{
  test[100] <<< 10
  test[100] <<< 20
  printf("count=%d\n", @count(test[100]))
  delete test
  exit()
}
実行結果
[root@server ~]# stap tp.stp
count=2

4.2 最小(@min)、最大(@max)、平均(@avg)、合計(@sum)、を求める方法

スクリプト
[root@server ~]# cat tp.stp
#!/usr/bin/stap
global test

probe begin
{
  test["hello"] <<< 10
  test["hello"] <<< 20
  test["hello"] <<< 30

  printf("count=%d,min=%d,max=%d,avg=%d,sum=%d\n",
        @count(test["hello"]),
        @min(test["hello"]),
        @max(test["hello"]),
        @avg(test["hello"]),
        @sum(test["hello"])
  )
  delete test
  exit()
}
実行結果
[root@server ~]# stap tp.stp
count=3,min=10,max=30,avg=20,sum=60

5 ヒストグラフの描き方( Histogram extractors)

ヒストグラムの書き方を以下に示します。

5.1 hist_linearの使い方(@hist_linear)

スクリプト
[root@server ~]# cat tp.stp
#!/usr/bin/stap
global test

probe begin
{
  test <<< 100
  test <<< 110
  test <<< 700
  print(@hist_linear(test, 0, 1000, 50))
  delete test
  exit()
}
実行結果
[root@server ~]# stap tp.stp
value |-------------------------------------------------- count
    0 |                                                   0
   50 |                                                   0
  100 |@@                                                 2
  150 |                                                   0
  200 |                                                   0
      ~
  600 |                                                   0
  650 |                                                   0
  700 |@                                                  1
  750 |                                                   0
  800 |                                                   0

5.2 hist_logの使い方(@hist_log)

スクリプト
[root@server ~]# cat tp.stp
#!/usr/bin/stap
global test

probe begin
{
  test <<< 100
  test <<< 110
  test <<< 700
  print(@hist_log(test))
  delete test
  exit()
}
実行結果
[root@server ~]# stap tp.stp
value |-------------------------------------------------- count
   16 |                                                   0
   32 |                                                   0
   64 |@@                                                 2
  128 |                                                   0
  256 |                                                   0
  512 |@                                                  1
 1024 |                                                   0
 2048 |                                                   0

Z 参考情報

3.5. SYSTEMTAP でのアレイ演算
SystemTap Language Reference
mmitouの日記
SystemTap 3.2 SystemTap Beginners Guide