2 DTraceの概念
この項のトピックでは、概念レベルでDTraceを調べ上げて、コンポーネントと用語について説明します。各トピックは汎用的であり、DTraceの内容とその仕組みの理解に役立ちます。
DTraceについて
DTraceは、Oracle LinuxのUnbreakable Enterprise Kernel (UEK)で使用できる強力なトレース・ツールです。DTraceは、オーバーヘッドが小さく、システムの動作内容をリアルタイムで分析するために本番システムで安全に使用できます。
DTraceにより、ユーザー・プログラムとOSの動作を検査して、システムの動作状況を把握し、パフォーマンスの問題を検出し、異常な動作の原因を特定できるようになります。DTraceは、実行時イベントまたはソースコードの場所のプローブを使用して、スタック・トレース、関数の引数、タイムスタンプおよび統計集計を収集または出力できます。
多くのトレース・ツールとは異なり、DTraceは完全にプログラム可能です。あるイベントのデータを収集して、別のイベントがトリガーされたときに使用するために格納できます。収集する情報と、その報告方法を選択できます。DTraceプログラムの構文は、Cプログラミング言語を利用した使い慣れた構文ものです。
DTrace v2は、DTraceが最初にLinuxに移植されたときには存在していなかった、eBPFなどの既存のLinuxカーネル・トレース機能を使用するDTraceの再実装です。この新しい実装では、特殊なカーネル・パッチに対するDTraceの依存性が取り除かれていますが、以前のDTraceの実装との構文互換性は維持されていて、最新のテクノロジに基づいた成熟したトレース・ツールが提供されます。さらに、DTrace v2は、以前のDTraceの実装との機能互換性を維持しているため、どちらのバージョンのDTraceを使用しても同じアクションを実行できます。
DTrace v2は、UEK R6以降のカーネルで使用可能で、Oracle Linux 8とOracle Linux 9のユーザー空間アプリケーションとして実装されます。
DTraceは、Universal Permissive License (UPL)バージョン1.0の下で使用可能なオープン・ソース・プロジェクトとして開発されています。ソース・コードおよび詳細は、https://github.com/oracle/dtrace-utilsを参照してください。
DTraceのコンポーネントと用語
プローブ
DTraceは、プローブを使用することで動作します。これには、カーネルまたはユーザー空間アプリケーション内の特定のインストゥルメンテーションを識別するものや、間隔カウンタやパフォーマンス・イベント・カウンタを識別するために使用できるものがあります。プローブは、特定のコードの実行時や特定のカウンタの増分時などのイベントによって起動し、DTraceはプログラムやスクリプトでイベントにバインドされた関数を実行できます。たとえば、プローブは特定のファイルが開かれたときに起動でき、DTraceプログラムは問題のデバッグや解決に役立つイベントに関連する情報を出力できます。同様に、DTraceがトレース・アクティビティを開始または終了した時点で、それらのアクション専用のBEGINプローブとENDプローブが常に起動されます。
システムで使用可能なすべてのプローブは、次のコマンドを入力することでリストできます。
sudo dtrace -l
出力には、プローブを正しく参照するために使用する各値が表示されます。
ID PROVIDER MODULE FUNCTION NAME
1 dtrace BEGIN
2 dtrace END
3 dtrace ERROR
4 syscall vmlinux read entry
5 syscall vmlinux read return
6 syscall vmlinux write entry
7 syscall vmlinux write return
...
特定のプローブをリストして有効にする方法の詳細は、「プローブのリストと有効化」を参照してください。
プローブは、特定の種類のインストゥルメンテーションをグループにまとめるプロバイダによって使用できるようになります。プロバイダがソースコードに関連している場合、そのプローブには、モジュールと関数の識別子でプローブが関連しているコード部分についての情報も含まれることがあります。そのため、プローブはプルーブ記述で識別され、次の4つのフィールドにグループ化されます:
- provider
-
プローブが属するDTraceプロバイダの名前。
- module
-
プローブが特定のプログラムの場所に対応している場合は、そのプローブがあるカーネル・モジュール、ライブラリまたはユーザー空間プログラムの名前。一部のプローブは、より抽象的なトレース・ポイントに関連する場合、特定のソースの場所に拘束されないモジュール名に関連付けられていることがあります。
- function
-
プローブが特定のプログラムの場所に対応している場合は、そのプローブがあるプログラム関数の名前。
- name
-
プローブのセマンティックな意味がわかる名前(
BEGIN
やEND
など)。
プローブを参照するときには、プローブ記述の4つの部分のすべてをコロンで区切って記述します:
provider:module:function:name
一部のプローブは、リストされるときにモジュールまたは関数の識別子がないことに注意してください。こうしたプローブの完全なプローブ記述を指定するときには、空のフィールドも含める必要があります:
dtrace:::BEGIN
プローブにはモジュールと関数は必要ありません。dtraceのBEGIN
、END
およびERROR
プローブは、特定のインストゥルメントされるプログラムの関数または場所に対応していないため、この好例になります。かわりに、こうしたプローブは、トレース・リクエストの終了のような、より抽象的な概念に使用されます。その他のプロファイル・プロバイダやCPCプロバイダなどによって使用可能になるプローブも、その記述にモジュールや関数の識別子は含まれません。
Dプログラム
1つ以上のDTraceプローブに文と呼ばれる一連の処理命令をバインドできるため、プローブの起動時に指定の文を実行することで所要の機能を実行できます。有効化されたプローブのセット、文、およびプローブの起動時に評価される可能性のある条件は、すべてDプログラムにまとめることができます。
プログラムは、どのプローブがDプログラム内の機能をトリガーできるかを決定する複数のプローブ記述で構成できます。プローブ記述の後には、節と呼ばれる一連の処理命令が続きます。節には、選択したプローブの起動時に実行する内容を記述します。述語と呼ばれる条件式は、プローブ記述と節の間に挿入することで、節内のアクションを実行する条件を制御できます。たとえば、すべてのシステム・コールで起動して、特定のアプリケーションのシステム・コールをカウントするようにプログラムを設計できます。このプログラムは、syscall:::entry
プローブのプローブ記述、プロセスIDまたは実行可能ファイルの名前と一致するように処理を制限する述語、および各システム・コール関数に関する情報を収集するためにcount()
関数を実行した節で構成されます。その結果のDプログラムは、次のようになります:
/* Probe descriptions */
syscall:::entry
/* Predicate */
/execname=='date'/
/* Clause */
{
@reads[probefunc]=count();
}
このスクリプトを実行すると、次のように、dateコマンドによって行われた各システム・コールが表示され、それぞれのカウント値が示されます。
dtrace: description 'syscall:::entry ' matched 344 probes
Wed 22 Feb 11:54:51 GMT 2023
exit_group 1
lseek 1
mmap 1
write 1
openat 2
read 2
brk 3
close 4
newfstat 4
プログラムのプローブ記述は、エントリ・ポイントにあるすべてのシステム・コール関数と一致します。プログラム述語は、演算子を使用して文字列に対して組込み変数のexecname
を評価します。この節には、起動するプローブに関するデータの収集に使用される集積体の@reads
が含まれます。この場合、集積体には、プローブが起動され、述語が解決されるたびに増分するカウンタが格納されます。カウンタは、count()
関数によって実装され、システム・コール・プローブ関数ごとのカウント値を格納します。プログラムの構造と構文の詳細は、「Dプログラム構文のリファレンス」を参照してください。
集積体
集積体を使用すると、大量のデータを、より小さく意味のある統計メトリックに縮小できます。データ・セット関連の情報を得るときに使用する関数の多くは、集積関数です。こうした関数を次に示します。
-
セット内の要素数をカウントします。
-
セットの最小値を計算します。
-
セットの最大値を計算します。
-
セット内のすべての要素の合計を計算します。
-
特定のビンに量子化されるように、セット内の値のヒストグラムを作成します。
データのセットに対して集計を計算するようにアプリケーションをコーディングすることもできますが、多数のプローブが同時に起動すると、集積変数に対する更新を相互に上書きすることや、計算がシリアル・ボトルネックになることがあります。
DTraceの集積関数は、トレース時にデータに適用されるため、データセットの格納が不要で、イベントの発生時にいつでも集積体が使用できます。このようにすることで、集積関数はより効率的で正確なものになり、上書きを回避できます。詳細は、「集積体」を参照してください。
投機
述語は対象外のイベントをフィルタ処理するために使用できますが、フィルタする必要があるイベントを事前に知っている場合にのみ役立ちます。通常、DTraceは特定のシステム動作のデバッグに利用するため、DTraceにはデータの投機的なトレースに使用できる一連の投機関数が含まれています。
投機は、特定の情報が判明するまで一時的に定量をトレースするために使用され、その場合はデータを破棄することもコミットすることもできます。投機トレースを実行することで、有用かどうかが判明するまでデータをトレースできます。たとえば、特定のリターン・コードまたはエラーをトリガーする可能性のあるイベントに関するデータをトレースするために、すべてのイベントを投機的にトレースして、対象とするリターン・コードと一致しない場合はトレース・データを破棄できます。詳細は、「投機」を参照してください。
バッファ
DTraceプローブが起動すると、カーネルは各種のバッファにデータを書き込みます。このバッファは、リクエストされたデータを出力するdtrace
ユーザー空間ユーティリティで読み取ります。
カーネルによるトレース・データの生成と、そのデータのdtrace
ユーティリティによる処理が非同期に実行されます。トレース・データの処理は、バッファ・オプションとリフレッシュ率の設定で調整できます。バッファ・サイズは、aggsize
、bufsize
、nspec
などのオプションで調整できます。
バッファ・サイズとポリシーを制御する各種のオプションについては、「DTraceの実行時オプションとコンパイル時オプションのリファレンス」を参照してください。
安定性
DTraceは、時間の経過によって変化する可能性のあるコードに含まれたプローブを利用するトレース・ツールです。DTraceとDコンパイラには、作成するDプログラムの安定性を動的に計算して説明する機能があります。こうしたDTraceの安定性機能を使用すると、Dプログラムの安定性属性を確認したり、プログラムに不適切なインタフェース依存関係があるときにコンパイル時エラーを生成できます。
DTraceには、組込み変数、関数、プローブなどのエンティティについて2種類の安定性属性が用意されています。その1つは安定性レベル、もう1つはアーキテクチャの依存クラスです。DTraceの安定性レベルは、将来のリリースやパッチでインタフェースやDTraceエンティティが変更される可能性を示すことで、DTraceに基づいたスクリプトやツールの開発時にリスクを評価する際に役立ちます。DTraceの依存クラスは、あるインタフェースがすべてのOracle Linuxプラットフォームとプロセッサに共通であるかどうか、あるいは特定のアーキテクチャに関連付けられいているかどうかを示します。インタフェースを記述するこの2種類の属性は、相互に依存することはありません。
安定のインタフェースにのみ依存するアプリケーションは、今後のマイナー・リリースでも確実に機能を維持する可能性が高く、個別パッチによって破損する可能性は低くなります。安定性の低いインタフェースは、現在のシステムでの実験、プロトタイプ作成、チューニングおよびデバッグに使用できます。安定していないインタフェースは、将来のマイナー・リリースで変更されることや、互換性のない状態になること、削除されること、代替のインタフェースに置き換えられることを理解して使用してください。
インタフェースは、すべてのOracle Linuxプラットフォームとプロセッサに共通にすることも、特定のシステム・アーキテクチャに関連付けることもできます。依存クラスは、アーキテクチャの依存関係を示すために役立ち、安定性レベルとは関係しません。たとえば、DTraceインタフェースは安定であっても、x86_64マイクロプロセッサでのみ使用可能なこともあります。また、インタフェースが不安定であっても、すべてのOracle Linuxプラットフォームに共通になることもあります。
ぞれぞれの安定性レベルと依存性クラスの詳細は、「DTrace安定性のリファレンス」を参照してください。