3 集積体

システム・パフォーマンス関連の問題に当たるためシステムをインストゥルメントする場合は、個々のプローブによって収集されたデータについて考えるよりも、データをどのように集積できるかについて考えた方が、明確な答えを得やすくなります。たとえば、ユーザーIDごとにシステム・コールの回数を把握する場合、それぞれのシステム・コールで収集されたデータについて考慮する必要はありません。この場合、ユーザーIDとシステム・コールの表を確認できれば、それで十分です。従来、このような調査が必要な場合は、システム・コールごとにデータを収集し、awkperlなどのツールを使用して、データの後処理を行っていました。一方、DTraceでは、データの収集が最も重要な操作になります。この章では、DTraceの集積体操作の機能について説明します。

集積体の概念

次のようなプロパティを持つ関数を集積関数と呼びます。

func(func(x0) U func(x1) U ... U func(xn)) = func(x0 U x1 U ... U xn)

ここで、xn は任意の一連のデータです。つまり、データのサブセットに集積関数を適用し、その結果に再度集積関数を適用すると、データ全体に集積関数を適用した場合と同じ結果になります。たとえば、指定のデータ・セットの合計を計算するSUM関数について考えてみます。RAWデータが{2, 1, 2, 5, 4, 3, 6, 4, 2}の場合、SUMをこのセット全体に適用した結果は{29}になります。同様に、最初の3つの要素で構成されるサブセットにSUMを適用した結果は{5}、次の3つの要素で構成されるセットにSUMを適用した結果は{12}、残りの3つの要素にSUMを適用した結果も{12}になります。これらの結果である{5, 12, 12}にSUMを適用すると、元のデータに適用したときと同じ結果である{29}になるため、このSUMは集積関数と呼ばれます。

すべての関数が集積関数になるわけではありません。非集積関数の例は、MEDIAN関数です。この関数は、セットの中央値要素を決定します。中央値とは、セット内の要素を大きさ順に並べたとき、ちょうど真ん中にくる要素のことです。MEDIANを得るには、セットをソートして、その中央の要素を選択します。元のRAWデータに戻ります。MEDIANを最初の3つの要素のセットに適用すると、その結果は{2}になります。ソート済セットが{1, 2, 2}で、{2}が中央の要素になります。同様に、次の3つの要素にMEDIANを適用した結果は{4}、最後の3つの要素にMEDIANを適用した結果は{4}になります。したがって、それぞれのサブセットにMEDIANを適用した結果は{2, 4, 4}というセットになります。このセットにMEDIANを適用すると、結果は{4}になります。ただし、元のセットをソートすると、結果は{1, 2, 2, 2, 3, 4, 4, 5, 6}になります。したがって、このセットにMEDIANを適用すると、結果は{3}になります。このように結果が一致しないため、MEDIANは集積関数ではありません。MODE (セットの最も一般的な要素)も同様です。

データ・セット関連の情報を得るときに使用する関数の多くは、集積関数です。こうした関数を次に示します。

  • セット内の要素数をカウントします。

  • セットの最小値を計算します。

  • セットの最大値を計算します。

  • セット内のすべての要素の合計を計算します。

  • 特定のビンに量子化されるように、セット内の値をヒストグラム化します。

さらに、厳密には集積関数自体ではない関数の中にも、そのように構成できるものがあります。たとえば、平均(算術平均)を構成するには、セット内の要素の数値の数とセット内のすべての要素の合計を集積し、最終結果として2つの集積の比率を報告します。もう1つの重要な例は、標準偏差です。

データのトレース時に集積関数を適用すると、次のような多数のメリットがあります。

  • データ・セット全体を格納する必要がありません。セットに新しい要素が追加されるたびに、現在の中間結果と新しい要素から構成されるセットが作成され、集積関数が計算されます。新しい結果が計算されたら、新しい要素は破棄してかまいません。この処理により、データ・ポイント数が大幅に増えても、記憶域の消費量を少なく抑えることができます。

  • データ収集が原因で、スケーラビリティに問題が起こることはありません。集積関数は、中間結果を共有のデータ構造に格納せず、CPU単位で保存できます。その後、DTraceでは、このCPU単位の中間結果のセットに集積関数が適用され、システム全体の最終的な結果が得られます。

基本的な集積体の文

DTraceは集積関数の結果を、集積体と呼ばれるオブジェクトに格納します。Dでは、集積体の構文は次のとおりです。

@name[ keys ] = aggfunc( args );

集積体のnameは特殊文字@で始まるD識別子です。Dプログラムで名前が付けられたすべての集積体は、グローバル変数です。スレッド・ローカル集積体または節ローカル集積体はありません。集積体名は、その他のDグローバル変数とは別の識別子用の名前空間に格納されます。名前を再利用する場合、a@aは同じ変数ではないことに注意してください。単純なDプログラム内で匿名の集積体を指定する場合は、特殊な集積体名@が使用されます。Dコンパイラは、この名前を集積体名@_の別名として扱います。

集積体はキーで索引付けされます。keysは、連想配列に使用される式のタプルと同様に、D式のカンマ区切りリストです。キーは、stackfuncsymmodustackuaddrusymなど、void以外の戻り値を使用したアクションでもかまいません。

aggfuncはDTrace集積関数の1つであり、argsは、その関数に適した引数のカンマ区切りリストです。次の表では、DTrace集積関数について説明します。ほとんどの集積関数は、新規のデータを表す1つの引数のみをとります。

表3-1 DTrace集積関数

関数名 引数 結果

count

なし

コールされた回数。

sum

スカラー式

指定された式の合計値。

avg

スカラー式

指定された式の算術平均。

min

スカラー式

指定された式のうち最も小さい値。

max

スカラー式

指定された式のうち最も大きい値。

stddev

スカラー式

指定された式の標準偏差。

quantize

スカラー式 [, インクリメント]

指定された式の値の二乗度数分布(ヒストグラム)。オプションの増分(重み)を指定できます。

lquantize

スカラー, 下限値, 上限値 [, ステップ値 [, インクリメント]]

指定された範囲の、指定された式の値の線形度数分布。

デフォルトのステップ値が1であることに注意してください。

llquantize

スカラー式, 底, 指数の下限, 指数の上限, ステップ数の桁 [, インクリメント]

対数線形度数分布。対数の底は、指数の下限、指数の上限およびステップ数の桁とともに指定されます。

集積体の例

次に、集積体の一連の例を示します。

基本的な集積体

システム内のwrite()システム・コールの回数をカウントする場合、通知文字列をキーに指定して、集積関数countを使用し、writes.dという名前のファイルに保存します。

syscall::write:entry
{
  @counts["write system calls"] = count();
}

デフォルトでは、dtraceコマンドによって、プロセス終了時にそれが明示的なENDアクションの結果として、またはユーザーが[Ctrl]キーを押しながら[C]キーを押したためかに関係なく、集積体の結果が出力されます。次の例では、このコマンドを実行し、数秒待ってから[Ctrl]キーを押しながら[C]キーを押した結果を示します。

# dtrace -s writes.d
dtrace: script './writes.d' matched 1 probe
^C
write system calls                               179
#

キーの使用

プロセス名ごとのシステム・コールをカウントするには、集積体のキーとしてexecname変数を指定し、それをwritesbycmd.dという名前のファイルに保存します。

syscall::write:entry
{
  @counts[execname] = count();
}

次の例では、このコマンドを実行し、数秒待ってから[Ctrl]キーを押しながら[C]キーを押した結果の出力を示します。

# dtrace -s writesbycmd.d
dtrace: script 'writesbycmd.d' matched 1 probe
^C
  dirname                                                           1
  dtrace                                                            1
  gnome-panel                                                       1
  mozilla-xremote                                                   1
  ps                                                                1
  avahi-daemon                                                      2
  basename                                                          2
  gconfd-2                                                          2
  java                                                              2
  pickup                                                            2
  qmgr                                                              2
  sed                                                               2
  dbus-daemon                                                       3
  rtkit-daemon                                                      3
  uname                                                             3
  w                                                                 5
  bash                                                              9
  cat                                                               9
  gnome-session                                                     9
  Xorg                                                             21
  firefox                                                         149
  gnome-terminal                                                 9421
#

また、書込みの編成を実行可能ファイルの名前とファイル記述子の両方で調査することもできます。ファイル記述子は、write()に対する最初の引数です。次の例では、execnamearg0の両方で構成されるタプルであるキーを使用します。

syscall::write:entry
{
  @counts[execname, arg0] = count();
}

このコマンドを実行すると、実行可能ファイルの名前とファイル記述子を含む、次の例のような表が出力されます。

# dtrace -s writesbycmdfd.d
dtrace: script 'writesbycmdfd.d' matched 1 probe
^C

  basename                                                  1        1
  dbus-daemon                                              70        1
  dircolors                                                 1        1
  dtrace                                                    1        1
  gnome-panel                                              35        1
  gnome-terminal                                           16        1
  gnome-terminal                                           18        1
  init                                                      4        1
  ps                                                        1        1
  pulseaudio                                               20        1
  tput                                                      1        1
  Xorg                                                      2        2
#

限定されたアクション・セットを集積体キーとして使用できます。次のmod()アクションおよびstack()アクションの使用を検討してください。

profile-10
{
  @hotmod[mod(arg0)] = count();
  @hotstack[stack()] = count();
}

ここでは、hotmod集積体は、profileプローブのarg0を使用してカーネル・プログラム・カウンタを判別し、モジュールごとのプローブ起動をカウントします。hotstack集積体は、スタックごとのプローブ起動をカウントします。集積体の出力には、最もホットなモジュールおよびカーネル・コール・スタックが表示されます。

avg関数の使用

次の例では、write()システム・コールにかかった時間の平均が、プロセス名ごとに表示されます。この例では、平均を求める式を引数として指定する集積関数avgを使用します。この例は、システム・コールにかかった時計時間の平均を求め、writetime.dという名前のファイルに保存されます。

syscall::write:entry
{
  self->ts = timestamp;
}

syscall::write:return
/self->ts/
{
  @time[execname] = avg(timestamp - self->ts);
  self->ts = 0;
}

次の出力では、このコマンドを実行し、数秒待ってから[Ctrl]キーを押しながら[C]キーを押した結果を示します。

# dtrace -s writetime.d 
dtrace: script 'writetime.d' matched 2 probes
^C

  gnome-session                                                  8260
  udisks-part-id                                                 9279
  gnome-terminal                                                 9378
  mozilla-xremote                                               10061
  abrt-handle-eve                                               13414
  vgdisplay                                                     13459
  avahi-daemon                                                  14043
  vgscan                                                        14190
  uptime                                                        14533
  lsof                                                          14903
  ip                                                            15075
  date                                                          15371
  ...
  ps                                                            91792
  sestatus                                                      98374
  pstree                                                       102566
  sysctl                                                       175427
  iptables                                                     192835
  udisks-daemon                                                250405
  python                                                       282544
  dbus-daemon                                                  491069
  lsblk                                                        582138
  Xorg                                                        2337328
  gconfd-2                                                   17880523
  cat                                                        59752284
#

stddev関数の使用

一方で、stddev集積関数を使用して、データ・ポイントの分布を明確にできます。次の例では、execプロセスに必要な時間の平均と標準偏差を示します。stddev.dという名前のファイルに保存します。

syscall::execve:entry
{
 self->ts = timestamp;
}

syscall::execve:return
/ self->ts /
{
  t = timestamp - self->ts;
  @execavg[probefunc] = avg(t);
  @execsd[probefunc] = stddev(t);
  self->ts = 0;
}

END
{
  printf("AVERAGE:");
  printa(@execavg);
  printf("\nSTDDEV:");
  printa(@execsd);
}

次に出力の例を示します。

# dtrace -q -s stddev.d
^C
AVERAGE:
  execve                                                       253839

STDDEV:
  execve                                                       260226

ノート:

標準偏差は√((Σ(x2)/N)-(Σx/N)2)で概算されます。これは不正確な近似ですが、DTraceを適用するほとんどの目的で十分です。

quantize関数の使用

平均と標準偏差は、大まかな特性評価に有用ですが、多くの場合、データ・ポイントの分布を理解するための十分な詳細は示されません。分布の詳細を確認する場合は、次の例のように、wrquantize.dという名前のファイルに保存される集積関数quantizeを使用します。

syscall::write:entry
{
  self->ts = timestamp;
}

syscall::write:return
/self->ts/
{
  @time[execname] = quantize(timestamp - self->ts);
  self->ts = 0;
}

このスクリプトの出力は、先ほどのスクリプトの出力よりも長くなります。1行で出力されていた内容が、度数分布表になるためです。次の例は、出力の抜粋を示しています。

# dtrace -s wrquantize.d 
dtrace: script 'wrquantize.d' matched 2 probes
^C
...
  bash                                              
           value  ------------- Distribution ------------- count    
            8192 |                                         0        
           16384 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@         4        
           32768 |                                         0        
           65536 |                                         0        
          131072 |@@@@@@@@                                 1        
          262144 |                                         0        

  gnome-terminal                                    
           value  ------------- Distribution ------------- count    
            4096 |                                         0        
            8192 |@@@@@@@@@@@@@                            5        
           16384 |@@@@@@@@@@@@@                            5        
           32768 |@@@@@@@@@@@                              4        
           65536 |@@@                                      1        
          131072 |                                         0        

  Xorg                                              
           value  ------------- Distribution ------------- count    
            2048 |                                         0        
            4096 |@@@@@@@                                  4        
            8192 |@@@@@@@@@@@@@                            8        
           16384 |@@@@@@@@@@@@                             7        
           32768 |@@@                                      2        
           65536 |@@                                       1        
          131072 |                                         0        
          262144 |                                         0        
          524288 |                                         0        
         1048576 |                                         0        
         2097152 |@@@                                      2        
         4194304 |                                         0        

  firefox                                           
           value  ------------- Distribution ------------- count    
            2048 |                                         0        
            4096 |@@@                                      22       
            8192 |@@@@@@@@@@@                              90       
           16384 |@@@@@@@@@@@@@                            107      
           32768 |@@@@@@@@@                                72       
           65536 |@@@                                      28       
          131072 |                                         3        
          262144 |                                         0        
          524288 |                                         1        
         1048576 |                                         1        
         2097152 |                                         0

度数分布は常に2のべき乗の値です。各行はそれに該当する値以上かつ次の行の値未満の要素のカウント数を示します。たとえば、前述の出力では、firefoxが16,384ナノ秒から32,767ナノ秒の間に107回の書込みを行っていることを示します。

前述の例は、書込み回数の分布を示しています。実行時間全体に最も関連する書込み回数を把握することに関心がある場合もあります。この目的のためにquantize関数とともにincrement引数をオプションで使用できます。デフォルト値は1ですが、この引数はD式になる可能性があり、負の値になる可能性もあることに注意してください。

次の例は変更されたスクリプトです。

 syscall::write:entry
{
  self->ts = timestamp;
}

syscall::write:return
/self->ts/
{
  self->delta = timestamp - self->ts;
  @time[execname] = quantize(self->delta, self->delta);
  self->ts = 0;
}

lquantize関数の使用

quantizeは、データの内容を簡単に把握するには有用ですが、線形値の分布を調査する必要がある場合もあります。線形値の分布を表示するには、lquantize集積関数を使用します。lquantize関数は、D式に加え、3つの引数(下限、上限、およびオプションのステップ)をとります。デフォルトのステップ値が1であることに注意してください。

たとえば、ファイル記述子別に書込みの分布を調査する場合、2のべき乗の量子化では効率がよくありません。かわりに、次の例のように、wrlquantize.dという名前のファイルに保存される、狭い範囲の線形量子化を使用できます。

syscall::write:entry
{
  @fds[execname] = lquantize(arg0, 0, 100, 1);
}

1がデフォルトのステップ値であるため、最後の引数を省略できる可能性もあります。

このスクリプトは、数秒間の実行で大量の情報を出力します。次の例は、一般的な出力の抜粋を示しています。

# dtrace -s wrlquantize.d
dtrace: script 'wrlquantize.d' matched 1 probe
^C
 ...
  gnome-session                                     
           value  ------------- Distribution ------------- count    
              25 |                                         0        
              26 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 9        
              27 |                                         0        

  gnome-terminal                                    
           value  ------------- Distribution ------------- count    
              15 |                                         0        
              16 |@@                                       1        
              17 |                                         0        
              18 |                                         0        
              19 |                                         0        
              20 |                                         0        
              21 |@@@@@@@@                                 4        
              22 |@@                                       1        
              23 |@@                                       1        
              24 |                                         0        
              25 |                                         0        
              26 |                                         0        
              27 |                                         0        
              28 |                                         0        
              29 |@@@@@@@@@@@@@                            6        
              30 |@@@@@@@@@@@@@                            6        
              31 |                                         0        
 ...

また、lquantize集積関数では、過去のある時点からデータを集積することもできます。この技術を使用して、時間の経過とともに変化する動作を監視できます。

次の例では、dateコマンドを実行しているプロセスの間の、システム・コールの動作の変化を示します。dateprof.dという名前のファイルに保存します。

syscall::execve:return
/execname == "date"/
{
  self->start = timestamp;
}

syscall:::entry
/self->start/
{
  /*
   * We linearly quantize on the current virtual time minus our
   * process’s start time. We divide by 1000 to yield microseconds
   * rather than nanoseconds. The range runs from 0 to 10 milliseconds
   * in steps of 100 microseconds; we expect that no date(1) process
   * will take longer than 10 milliseconds to complete.
   */
  @a["system calls over time"] =
  lquantize((timestamp - self->start) / 1000, 0, 10000, 100);
}

syscall::exit:entry
/self->start/
{
  self->start = 0;
}

このスクリプトでは、複数のdateプロセスの実行中の、システム・コールの動作を詳細に調査できます。この結果を表示するには、Dスクリプトの実行中に、別のウィンドウでsh -c 'while true; do date >/dev/null; done'を実行します。スクリプトにより、次のようなdateコマンドのシステム・コールの動作の概要が出力されます。

# dtrace -s dateprof.d 
dtrace: script 'dateprof.d' matched 298 probes
^C

  system calls over time                            
           value  ------------- Distribution ------------- count    
             < 0 |                                         0        
               0 |@@                                       23428    
             100 |@@@@@                                    56263    
             200 |@@@@@                                    61271    
             300 |@@@@@                                    58132    
             400 |@@@@@                                    54617    
             500 |@@@@                                     45545    
             600 |@@                                       26049    
             700 |@@@                                      38859    
             800 |@@@@                                     51569    
             900 |@@@@                                     42553    
            1000 |@                                        11339    
            1100 |                                         4020     
            1200 |                                         2236     
            1300 |                                         1264     
            1400 |                                         812      
            1500 |                                         706      
            1600 |                                         764      
            1700 |                                         586      
            1800 |                                         266      
            1900 |                                         155      
            2000 |                                         118      
            2100 |                                         86       
            2200 |                                         93       
            2300 |                                         66       
            2400 |                                         32       
            2500 |                                         32       
            2600 |                                         18       
            2700 |                                         23       
            2800 |                                         26       
            2900 |                                         30       
            3000 |                                         26       
            3100 |                                         1        
            3200 |                                         7        
            3300 |                                         9        
            3400 |                                         3        
            3500 |                                         5        
            3600 |                                         1        
            3700 |                                         6        
            3800 |                                         8        
            3900 |                                         8        
            4000 |                                         8        
            4100 |                                         1        
            4200 |                                         1        
            4300 |                                         6        
            4400 |                                         0

前述の出力は、カーネルを必要とするサービスについて、dateコマンドの様々なフェーズの概略を示します。これらのフェーズをさらに理解するには、いつ、どのシステム・コールが呼び出されたかを把握する必要があります。この場合は、定数文字列ではなくprobefunc変数について集積するようにDスクリプトを変更します。

対数線形集積関数llquantizeは、対数関数と線形関数の両方の機能が組み合されています。単純なquantize関数は2を底とする対数を使用しますが、llquantizeでは底、最小指数および最大指数を指定します。さらに、それぞれの対数の範囲は、指定されたように、多くのステップで直線的に細分化されます。

集積体の出力

デフォルトの設定では、複数の集積体が、Dプログラムに記述された順番で表示されます。この設定を変更するには、集積体を出力するprinta関数を使用します。「出力フォーマット」で説明するように、printa関数は、集積体データのフォーマットをフォーマット文字列を使用して正確に設定する場合にも使用します。

Dプログラム内のprinta文で集積体のフォーマットが設定されていない場合、dtraceコマンドを実行すると、集積体データのスナップショットが生成され、その結果はトレースの完了後、デフォルトの集積体のフォーマットで出力されます。printa文で集積体のフォーマットが設定されている場合、デフォルトの動作は無効になります。printa(@aggregation-name)文をプログラムのENDプローブ節に追加しても、同様の結果が得られます。avgcountminmax、およびsum集積関数のデフォルトの出力フォーマットでは、それぞれのタプルの集積値に対応する10進整数値が表示されます。quantizelquantizeおよびllquantize集積関数のデフォルトの出力フォーマットでは、結果を含むASCIIテーブルが表示されます。集積体タプルの出力は、個々のタプル要素にtraceを適用した場合と同じになります。

データの正規化

一定期間のデータを集積する際、定数係数を使用してデータを正規化できます。この技術を使用すると、ばらばらのデータをより簡単に比較できます。たとえば、システム・コールを集積する場合、システム・コールを実行の過程の絶対値ではなく、秒当たりのレートとして出力します。DTraceのnormalizeアクションでは、この方法でデータを正規化できます。normalizeのパラメータは、集積体と正規化の係数になります。集積体の結果としては、個々の値を正規化係数で割った値が出力されます。

次の例は、データをシステム・コールごとに集積する方法を示しています。

#pragma D option quiet

BEGIN
{
  /*
   * Get the start time, in nanoseconds.
   */
  start = timestamp;
}

syscall:::entry
{
  @func[execname] = count();
}

END
{
  /*
   * Normalize the aggregation based on the number of seconds we have
   * been running. (There are 1,000,000,000 nanoseconds in one second.)
   */
  normalize(@func, (timestamp - start) / 1000000000);
}

このスクリプトをしばらく実行すると、次のような結果が出力されます。

# dtrace -s normalize.d
^C
  memballoon                                                        1
  udisks-daemon                                                     1
  vmstats                                                           1
  rtkit-daemon                                                      2
  automount                                                         2
  gnome-panel                                                       3
  gnome-settings-                                                   5
  NetworkManager                                                    6
  gvfs-afc-volume                                                   6
  metacity                                                          6
  qpidd                                                             9
  hald-addon-inpu                                                  14
  gnome-terminal                                                   19
  Xorg                                                             35
  VBoxClient                                                       52
  X11-NOTIFY                                                      104
  java                                                            143
  dtrace                                                          309
  sh                                                            36467
  date                                                          68142

normalizeアクションでは、指定された集積体の正規化係数を設定しますが、このアクションでは基礎となるデータは変更されません。denormalizeアクションでは、集積体のみをとります。この例にdenormalizeアクションを追加すると、RAWシステム・コール・カウントと秒当たりのレートの両方が出力されます。次のソース・コードを入力し、denorm.dという名前のファイルに保存します。

#pragma D option quiet

BEGIN
{
  start = timestamp;
}

syscall:::entry
{
  @func[execname] = count();
}

END
{
  this->seconds = (timestamp - start) / 1000000000;
  printf("Ran for %d seconds.\n", this->seconds);
  printf("Per-second rate:\n");
  normalize(@func, this->seconds);
  printa(@func);
  printf("\nRaw counts:\n");
  denormalize(@func);
  printa(@func);
}

前述のスクリプトをしばらく実行すると、次のような出力が得られます。

# dtrace -s denorm.d
^C
Ran for 7 seconds.
Per-second rate:

  audispd                                                           0
  auditd                                                            0
  memballoon                                                        0
  rtkit-daemon                                                      0
  timesync                                                          1
  gnome-power-man                                                   1
  vmstats                                                           1
  automount                                                         2
  udisks-daemon                                                     2
  gnome-panel                                                       2
  metacity                                                          2
  gnome-settings-                                                   3
  qpidd                                                             4
  clock-applet                                                      4
  gvfs-afc-volume                                                   5
  crond                                                             6
  gnome-terminal                                                    7
  vminfo                                                           15
  hald-addon-inpu                                                  32
  VBoxClient                                                       45
  Xorg                                                             63
  X11-NOTIFY                                                       90
  java                                                            126
  dtrace                                                          315
  sh                                                            31430
  date                                                          58724

Raw counts:

  audispd                                                           1
  auditd                                                            4
  memballoon                                                        4
  rtkit-daemon                                                      6
  timesync                                                          8
  gnome-power-man                                                   9
  vmstats                                                          12
  automount                                                        16
  udisks-daemon                                                    16
  gnome-panel                                                      20
  metacity                                                         20
  gnome-settings-                                                  22
  qpidd                                                            28
  clock-applet                                                     34
  gvfs-afc-volume                                                  40
  crond                                                            42
  gnome-terminal                                                   54
  vminfo                                                          105
  hald-addon-inpu                                                 225
  VBoxClient                                                      318
  Xorg                                                            444
  X11-NOTIFY                                                      634
  java                                                            883
  dtrace                                                         2207
  sh                                                           220016
  date                                                         411073

集積体は、再正規化も可能です。同じ集積体に対して複数回normalizeをコールするおと、直前のコールで指定された係数が正規化係数になります。次の例では、10秒間での上位10個のシステム呼出しアプリケーションについて秒当たりのシステム・コール・レートのみが出力されます。次のソース・コードを入力し、truncagg.dという名前のファイルに保存します。

#pragma D option quiet

BEGIN
{
  start = timestamp;
}

syscall:::entry
{
  @func[execname] = count();
}

tick-10sec
{
  normalize(@func, (timestamp - start) / 1000000000);
  printa(@func);
}

集積体のクリア

簡単な監視スクリプトの構築にDTraceを使用している場合、clear関数を使用して、集積体内の値を定期的に消去できます。この関数では、パラメータとして集積体のみをとります。clear関数は、集積体の値のみを消去するため、集積体のキーは保持されます。したがって、集積体内の値がゼロのキーは、このキーの値は以前はゼロではなかったが、clearによってゼロに設定されたことを意味します。集積体の値とそのキーを破棄する場合は、trunc関数を使用します。「集積体の切捨て」を参照してください。

次の例では、最新の10秒当たりのシステム・コール・レートを示すため、clearを使用しています。

#pragma D option quiet

BEGIN
{
  last = timestamp;
}

syscall:::entry
{
  @func[execname] = count();
}

tick-10sec
{
  normalize(@func, (timestamp - last) / 1000000000);
  printa(@func);
  clear(@func);
  last = timestamp;
}

集積体の切捨て

集積体の結果を調べるときは、通常、上位結果の数行のみに注目します。上位の値以外に関連付けられたキーや値は、あまり重要ではありません。また、キーと値の両方を削除して、集積体の結果全体を破棄する場合もあります。DTraceのtrunc関数は、このような状況で使用します。

truncのパラメータは、集積体と切捨て値(オプション)です。truncで切捨て値を使用しない場合、集積体全体で集積体値と集積体キーの両方が破棄されます。切捨て値nを指定した場合、truncは、上位n個の値に関連付けられている集積体値と集積体キー以外の値とキーを破棄します。つまり、trunc(@foo)では集積体全体が破棄されるのに対して、trunc(@foo, 10)ではfooという名前の集積体の上位10個の値以外が切り捨てられます。切捨て値として0を指定した場合も、集積体全体が破棄されます。

上位n個の値ではなく下位n個の値を参照する場合は、truncに負の切捨て値を指定します。たとえば、trunc(@foo, -10)では、fooという名前の集積の下位10個の値が保持され、それ以外が切り捨てられます。

次の例では、10秒間での上位10個のシステム呼出しアプリケーションについて秒当たりのシステム・コール・レートのみが出力されます。

#pragma D option quiet

BEGIN
{
  last = timestamp;
}

syscall:::entry
{
  @func[execname] = count();
}

tick-10sec
{
  trunc(@func, 10);
  normalize(@func, (timestamp - last) / 1000000000);
  printa(@func);
  clear(@func);
  last = timestamp;
}

次の例は、負荷の少ないシステムでこのスクリプトを実行したときの出力を示しています。

# dtrace -s truncagg.d 

  dbus-daemon                                                       0
  NetworkManager                                                    1
  gmain                                                             1
  systemd-logind                                                    1
  sendmail                                                          1
  systemd                                                           1
  httpd                                                             2
  tuned                                                             5
  dtrace                                                           44

  rpcbind                                                           0
  dbus-daemon                                                       0
  gmain                                                             0
  sshd                                                              1
  systemd-logind                                                    1
  sendmail                                                          1
  systemd                                                           1
  httpd                                                             2
  tuned                                                             5
  dtrace                                                           41

  dbus-daemon                                                       0
  gmain                                                             1
  sshd                                                              1
  systemd-logind                                                    1
  sendmail                                                          1
  systemd                                                           1
  httpd                                                             2
  tuned                                                             5
  automount                                                         7
  dtrace                                                           41
^C

#

欠落の最小化

DTraceは、カーネルに集積体データの一部を格納するため、集積体に新しいキーを追加したとき、容量が不足することがあります。この場合、カウンタの値は大きくなりますが、データは欠落し、dtraceから集積体の欠落を示すメッセージが表示されます。DTraceは、容量が動的に増加する場合のユーザー・レベルで、集積体キーと中間結果で構成される状態の情報を保存します。このため、集積体欠落はほとんど発生しません。それでも集積体の欠落が発生する場合は、aggsizeオプションを使用して集積体バッファ・サイズを大きくすることにより、欠落が発生する確率を低減できます。

このオプションは、DTraceのメモリー・フットプリントを最小化するときにも使用できます。aggsizeは、他のサイズ・オプションと同じく、任意のサイズの接尾辞とともに指定できます。このバッファのサイズ変更ポリシーはbufresizeオプションで指定します。バッファリングの詳細は、「バッファおよびバッファリング」を参照してください。

集積体の欠落を抑える他の方法としては、ユーザー・レベルで集積体データが消費されるレートを増やす方法があります。デフォルトでは、このレートは毎秒1回ですが、この値は、aggrateオプションを指定して明示的にチューニングできます。aggrateは、その他のレート・オプションと同様に、任意の時間接尾辞とともに指定できますが、デフォルトは秒当たりのレートです。aggsizeオプションの詳細は、「オプションおよびチューニング可能パラメータ」を参照してください。