5 バッファおよびバッファリング

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

主バッファ

デフォルトでは、主バッファは、トレース・アクションがデータを記録するバッファであり、DTraceの呼出し時に必ず使用されます。これらのアクションには、printaprintfstacktraceおよびtracememがあります。

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

主バッファのポリシー

DTraceでは、カーネル内の高度に制約されたコンテキストでトレースを実行できます。特に、カーネル・ソフトウェアが確実にメモリーを割り当てられないような状況でトレースできます。このように、コンテキストに柔軟性があるため、使用できる空間がないときでも、データのトレースが試行される可能性があります。DTraceには、そのような状況の発生時に対処するためのポリシーが必要です。ただし、特定の実行文のニーズに基づいてポリシーをチューニングすることもできます。ときには、新しいデータを破棄するポリシーが必要になる場合もあります。また、最も古いデータが記録されている空間を再利用して、新しいデータのトレースを有効化する必要が生じることもあります。ほとんどの場合、必要とされるのは、使用できる空間にできるかぎり不足が生じないようにするポリシーです。このような様々な要求に対応するため、DTraceでは、複数の異なるバッファ・ポリシーを使用できます。このためには、bufpolicyオプションを実装し、コンシューマ単位で設定できるようにします。詳細は、「オプションおよびチューニング可能パラメータ」を参照してください。

switchポリシー

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

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

dtrace: 11 drops on CPU 0

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

switchポリシーでは、DTraceサブルーチンに対するスクラッチ・メモリーがアクティブなバッファから割り当てられます。

fillポリシー

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

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

# 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は次のエラー・メッセージを出力します。

dtrace: END enablings exceed size of principal buffer

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

ringポリシー

DTraceのringバッファ・ポリシーは、障害を引き起こすイベントをトレースする場合に役立ちます。障害の再現に時間がかかるときは、最新のデータのみを保存したい場合があります。主バッファがいっぱいになると、トレースは最初のエントリに戻り、最も古いトレース・データが上書きされます。ringバッファを使用するには、次のようにbufpolicy=ringを指定します。

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

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

次の例では、#pragma optionディレクティブを使用してringバッファリングを有効にします。

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

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

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

その他のバッファ

DTraceの有効化では、必ず主バッファを使用します。一部のDTraceコンシューマは、主バッファ以外に、集積体バッファや1つ以上の投機バッファなど、追加のカーネル内データ・バッファを持つ場合があります。詳細は、「集積体」および「投機トレース」を参照してください。

バッファ・サイズ

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

バッファ サイズ・オプション

集積体

aggsize

bufsize

投機

specsize

これらのオプションには、サイズを表す値を設定します。その他のサイズ・オプションと同じく、値にはサイズ接尾辞が付けられる場合があります。詳細は、「オプションおよびチューニング可能パラメータ」を参照してください。

たとえば、次のようにして、dtraceのコマンドラインからバッファ・サイズを10MBに設定します。

# dtrace -P syscall -x bufsize=10m

または、-bオプションをdtraceコマンドに指定して使用できます。

# dtrace -P syscall -b 10m

また、次のように、pragmaを使用してbufsizeを設定することもできます。

#pragma D option bufsize=10m

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

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

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

# 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オプションで指定します。