3 集積体
システム・パフォーマンス関連の問題に当たるためシステムをインストゥルメントする場合は、個々のプローブによって収集されたデータについて考えるよりも、データをどのように集積できるかについて考えた方が、明確な答えを得やすくなります。たとえば、ユーザーIDごとにシステム・コールの回数を把握する場合、それぞれのシステム・コールで収集されたデータについて考慮する必要はありません。この場合、ユーザーIDとシステム・コールの表を確認できれば、それで十分です。従来、このような調査が必要な場合は、システム・コールごとにデータを収集し、awkやperlなどのツールを使用して、データの後処理を行っていました。一方、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式のカンマ区切りリストです。キーは、stack
、func
、sym
、mod
、ustack
、uaddr
、usym
など、void
以外の戻り値を使用したアクションでもかまいません。
aggfuncはDTrace集積関数の1つであり、argsは、その関数に適した引数のカンマ区切りリストです。次の表では、DTrace集積関数について説明します。ほとんどの集積関数は、新規のデータを表す1つの引数のみをとります。
表3-1 DTrace集積関数
関数名 | 引数 | 結果 |
---|---|---|
|
なし |
コールされた回数。 |
|
スカラー式 |
指定された式の合計値。 |
|
スカラー式 |
指定された式の算術平均。 |
|
スカラー式 |
指定された式のうち最も小さい値。 |
|
スカラー式 |
指定された式のうち最も大きい値。 |
|
スカラー式 |
指定された式の標準偏差。 |
|
スカラー式 [, インクリメント] |
指定された式の値の二乗度数分布(ヒストグラム)。オプションの増分(重み)を指定できます。 |
|
スカラー, 下限値, 上限値 [, ステップ値 [, インクリメント]] |
指定された範囲の、指定された式の値の線形度数分布。
デフォルトのステップ値が |
|
スカラー式, 底, 指数の下限, 指数の上限, ステップ数の桁 [, インクリメント] |
対数線形度数分布。対数の底は、指数の下限、指数の上限およびステップ数の桁とともに指定されます。 |
集積体の例
次に、集積体の一連の例を示します。
基本的な集積体
システム内の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()
に対する最初の引数です。次の例では、execname
とarg0
の両方で構成されるタプルであるキーを使用します。
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
プローブ節に追加しても、同様の結果が得られます。avg
、count
、min
、max
、およびsum
集積関数のデフォルトの出力フォーマットでは、それぞれのタプルの集積値に対応する10進整数値が表示されます。quantize
、lquantize
および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
オプションの詳細は、「オプションおよびチューニング可能パラメータ」を参照してください。