Solaris 動的トレースガイド

第 11 章 バッファーとバッファリング

データのバッファリングと管理は、dtrace(1M) のように、DTrace フレームワークがクライアントに提供する主要なサービスです。この章では、データのバッファリングの詳細と、DTrace のバッファー管理ポリシーを変更するための各種オプションについて説明します。

主バッファー

主バッファー」は、トレースアクションがデータを記録するデフォルトのバッファーであり、DTrace の呼び出し時に必ず使用されます。トレースアクションに該当するアクションには、以下のものがあります。

exit()

printf()

trace()

ustack()

printa()

stack()

tracemem()

 

主バッファーは、常に CPU 単位で割り当てられます。このポリシーはチューニングできません。ただし、cpu オプションを使って、トレースやバッファー割り当てが単一の CPU で行われるようにすることは可能です。

主バッファーのポリシー

DTrace では、カーネル内の高度に制約されたコンテキストでトレースを行うことができます。特に、カーネルソフトウェアが確実にメモリーを割り当てることができないような状況で、トレースを行うことができます。このように、コンテキストに柔軟性があるので、使用できる空間がないときでも、データのトレースが試行される可能性があります。DTrace には、こうした状況に対処するためのポリシーが必要ですが、測定する内容に応じてポリシーを変更したい場合もあります。ときには、新しいデータを破棄するポリシーが必要になることもあります。また、一番古いデータが記録されている空間を再利用して、新しいデータをトレースするポリシーが必要になることもあります。ほとんどの場合、必要とされるのは、使用できる空間がなるべく不足しないようにするポリシーです。こうしたさまざまな要求に対応するため、DTrace では、複数の異なったバッファーポリシーを使用できます。このためには、bufpolicy オプションを指定します。このオプションは、コンシューマ単位で設定できます。オプションの設定の詳細については、第 16 章オプションとチューニング可能パラメータを参照してください。

switch ポリシー

主バッファーには、デフォルトで、switch バッファーポリシーが設定されています。このポリシーでは、CPU 単位のバッファーのペアが割り当てられます。 ペアの一方はアクティブなバッファー、もう一方はアクティブでないバッファーです。DTrace コンシューマがバッファーを読み取ろうとすると、カーネルはまず、アクティブでないバッファーとアクティブなバッファーの切り替えを行います。バッファーの切り替えは、ウィンドウ内のトレースデータが失われる可能性がない状態で行われます。バッファーの切り替えが完了すると、新たにアクティブでなくなったバッファーが DTrace コンシューマにコピーされます。このポリシーにより、コンシューマは常に、自己矛盾のないバッファーを認識するようになります。 1 つのバッファーのトレースとコピーが同時に行われることはありません。この方法で、ウィンドウ内でのトレースの一時停止や、トレース不能状態の発生を回避することもできます。バッファーの切り替えと読み取りのレートは、switchrate オプションにより、コンシューマ側で制御します。 switchrate では、その他のレートオプションと同じく、任意の時間接尾辞を指定できます。デフォルトでは、秒当たりのレートが設定されます。switchrate とその他のオプションの詳細については、第 16 章オプションとチューニング可能パラメータを参照してください。


注 –

主バッファーをユーザーレベルでデフォルトのレート (1 秒に 1 回) より速いレートで処理するときは、switchrate の値を調整してください。主バッファー内の対応するレコードが処理されるときに、ユーザーレベルのアクティビティーを引き起こすアクション (printa()system() など) が処理されます。switchrate の値によって、そのようなアクションが処理されるレートが決まります。


switch ポリシーでは、指定の有効なプローブがアクティブな主バッファー内の使用可能な空間に収まりきらない量のデータをトレースしようとした場合、そのデータが落とされ、CPU 単位の欠落カウントが増分されます。1 回以上欠落が発生すると、dtrace(1M) により、次のようなメッセージが表示されます。


dtrace: 11 drops on CPU 0

合計バッファーサイズより大きいレコードは、バッファーポリシーに関係なく落とされます。欠落の発生を予防するには、bufsize オプションで主バッファーのサイズを大きくするか、switchrate オプションで切り替えレートを上げます。

switch ポリシーでは、アクティブなバッファーから copyin()copyinstr()alloca() にスクラッチ空間が割り当てられます。

fill ポリシー

単一のカーネル内バッファーを使用したい場合もあります。これは、switch ポリシーと適切な D 構造体を使って、D の変数を増分し exit() アクションを適切な述語に付加すれば、実現可能です。しかしこの方法では、欠落が発生する可能性が残ります。単一の大きいカーネル内バッファーを使用し、CPU 単位のバッファーが 1 つ以上占有されるまでトレースを続行するには、fill バッファーポリシーを使用します。このポリシーでは、有効なプローブが主バッファーの残りの空間に収まり切らない量のデータをトレースしようとするまで、トレースが続行されます。空間が足りなくなると、バッファーがいっぱいになったと見なされ、コンシューマに、CPU 単位のバッファーが少なくとも 1 つが占有されたという通知が送られます。dtrace(1M) がいっぱいになったバッファーを検出すると、トレースは停止し、すべてのバッファーが処理されたあと、dtrace は終了します。たとえバッファーに入るデータがあっても、いっぱいになったバッファーにはそれ以上トレースされません。

fill ポリシーを使用するには、bufpolicy オプションに fill を設定します。たとえば、次のコマンドは、バッファーポリシーを fill に設定し、CPU 単位の 2K のバッファーに、すべてのシステムコールエントリをトレースします。


# dtrace -n syscall:::entry -b 2k -x bufpolicy=fill

fill ポリシーと END プローブ

END プローブは、通常、DTrace コンシューマによってトレースが明示的に停止されるまで起動しません。END プローブは必ず、単一の CPU 上でのみ起動します。ただし、プローブが起動する CPU は未定義です。fill バッファーを使用しているときは、CPU 単位の主バッファーの少なくとも 1 つがいっぱいになったと見なされた時点で、明示的にトレースが停止します。fill ポリシーを選択した場合、END プローブは、いっぱいになったバッファーがある CPU 上でも起動します。fill バッファーへの END のトレースを可能にするため、DTrace は、END プローブが消費する見込みの空間の量を計算し、主バッファーのサイズからこの空間の量を引きます。結果が負の数になった場合、DTrace は起動せず、dtrace(1M) は対応するエラーメッセージを出力します。


dtrace: END enablings exceed size of principal buffer

予約機構により、いっぱいになったバッファーにも、END プローブ用の空間は必ず残されています。

ring ポリシー

DTrace の ring バッファーポリシーは、障害を引き起こすイベントをトレースするときに役立ちます。障害の再現に時間がかかるときは、最新のデータだけを保存したい場合があります。主バッファーがいっぱいになると、トレースは最初のエントリに戻り、一番古いトレースデータが上書きされます。リングバッファーを使用するには、bufpolicy オプションに文字列 ring を設定します。


# dtrace -s foo.d -x bufpolicy=ring

dtrace(1M) でリングバッファーを作成する場合は、処理が終了するまで何も出力されません。リングバッファーはその時点で消費され、処理されます。dtrace は、リングバッファーを CPU 順に処理します。CPU のバッファー内のトレースレコードは、古いものから順に並んでいます。switch バッファリングポリシーの場合と同じく、CPU の異なるレコード間の順序付けは行われません。こうした順序付けが必要な場合は、トレース要求の一部として、timestamp 変数をトレースする必要があります。

以下は、#pragma option 指令を使ってリングバッファリングを有効にする例です。

#pragma D option bufpolicy=ring
#pragma D option bufsize=16k

syscall:::entry
/execname == $1/
{
	trace(timestamp);
}

syscall::rexit:entry
{
	exit(0);
}

その他のバッファー

DTrace の有効化では、必ず主バッファーを使用します。一部の DTrace コンシューマは、主バッファーのほかに、カーネル内データバッファーも使用します。この内訳は、「集積体バッファー」 (第 9 章集積体を参照) と、1 個以上の「投機バッファー」 (第 13 章投機トレースを参照) です。

バッファーサイズ

各バッファーのサイズは、コンシューマ単位でチューニングできます。以下の表に示すように、バッファーサイズのチューニング用オプションが別途用意されています。

バッファー 

サイズオプション 

主体 

bufsize

投機 

specsize

集積体 

aggsize

これらのオプションには、サイズを表す値を設定します。その他のサイズオプションと同じく、値にはサイズ接尾辞 (オプション) を付けることができます。詳細については、第 16 章オプションとチューニング可能パラメータを参照してください。たとえば、dtrace のコマンド行からバッファーサイズを 1M バイトに設定するには、-x を使ってオプションを設定します。


# dtrace -P syscall -x bufsize=1m

-dtraceb オプションを指定する方法もあります。


# dtrace -P syscall -b 1m

また、#pragma D option を使って bufsize を設定することもできます。

#pragma D option bufsize=1m

選択したバッファーサイズは、 CPU 上のバッファーのサイズを表します。switch バッファーポリシーでは、bufsize は、 CPU 上の各バッファーのサイズを表します。デフォルトのバッファーサイズは 4M バイトです。

バッファーのサイズ変更ポリシー

システムのカーネルの空きメモリー容量が不足していて、使用可能なメモリー容量が足りないため、または DTrace コンシューマがチューニング可能な制限値 (第 16 章オプションとチューニング可能パラメータを参照) を超えてしまったため、必要なサイズのバッファーを割り当てられないことがあります。バッファー割り当てエラーのポリシーは、bufresize オプション (デフォルト値は auto) で設定できます。auto バッファーサイズ変更ポリシーでは、正常に割り当てが行われるまで、バッファーのサイズが二等分されます。割り当てバッファーのサイズが要求されたサイズより小さい場合、dtrace(1M) はメッセージを生成します。


# dtrace -P syscall -b 4g
dtrace: description 'syscall' matched 430 probes
dtrace: buffer size lowered to 128m
...

または


# dtrace -P syscall'{@a[probefunc] = count()}' -x aggsize=1g
dtrace: description 'syscall' matched 430 probes
dtrace: aggregation size lowered to 128m
...

バッファーの割り当てエラーの発生後、bufresizemanual を設定して、手動での調整を要求することもできます。このポリシーでは、割り当てエラーが発生すると、DTrace の起動に失敗します。


# dtrace -P syscall -x bufsize=1g -x bufresize=manual
dtrace: description 'syscall' matched 430 probes
dtrace: could not enable tracing: Not enough space
#

主バッファー、投機バッファー、集積体バッファーを含むすべてのバッファーのサイズ変更ポリシーは、bufresize オプションで指定します。