1 DTraceの紹介
この章では、Oracle Linuxの動的トレース(DTrace)機能を紹介します。DTraceを使用すると、オペレーティング・システムの動作、およびDTraceのプローブが備えられているユーザー・スペース・プログラムの動作を調査できます。DTraceを実行するために、Unbreakable Enterprise Kernel (UEK)ビルドが有効化されています。UEKは、Oracle Linuxで使用するためにコンパイルされたカーネルです。UEKはOracle Linuxに組み込まれたカーネルであるため、Oracle LinuxでUEK以外のLinuxカーネルを実行することはできますが、その場合、DTraceは有効化されず使用できない可能性が高くなります。
最新バージョンのUEKでは、多くの場合、以前のバージョンよりもDTrace機能が改善されています。DTraceの機能および改善の最大セットは、最新のDTrace対応カーネルで使用できます。
このチュートリアルでは、x86_64アーキテクチャでUEKを使用していることを前提としています。他のアーキテクチャのUEKリリースには、このチュートリアルで説明するすべてのプロバイダのサポートが含まれているわけではない可能性があります。
このチュートリアルについて
このチュートリアルには、様々なDTraceスクリプトが含まれており、DTraceを使用できる様々な方法が説明されています。いくつかの例には、DTraceの使用方法をさらに練習できる追加の演習があります。各演習には、演習を完了するために必要な予想時間が示されています。プログラミング知識のレベルによっては、必要な時間が異なる場合があります。Linux管理およびシステム・プログラミングをよく理解していて、プログラム言語(C、C++など)およびスクリプト言語(Pythonなど)を使用した幅広い経験をすでに持っている必要があります。システム・コール、タイプ、キャスト、シグナル、構造体、ポインタなどの用語に馴染みがない場合は、このチュートリアルの一部の例を理解すること、または一部の演習を完了することが難しい可能性があります。ただし、各演習には困ったときのために回答例が提供されています。例の方法を試してみて、DTraceスクリプトを作成するスキルを身に付けることをお薦めします。
注意:
このチュートリアルで例を実行したり、演習を行ったりするには、システムにroot
としてアクセスする必要があります。dtraceユーティリティを使用できるのは、root
ユーザー、またはroot
としてコマンドを実行できるsudoアクセスを持っているユーザーのみです。root
にはシステムに対する完全な権限があるため、システムに対するすべての責任を持つことになります。DTraceは、オペレーティング・システムまたはその他のプロセスに損傷を与えることを心配せずに安全に使用できるよう設計されていますが、組み込まれている安全対策では対処されない場合があることに注意してください。
リスクを最小限に抑えるには、このチュートリアルの例および演習は、本番システムではないシステムで実行してください。
このチュートリアルの例では、システムの動的トレースを実行できる様々な方法が示されています。すなわち、コマンドラインでdtraceの引数として簡単なDプログラムを入力するか、dtraceコマンドを使用してDプログラムが含まれているスクリプトを実行するか、dtraceのhashbang (#!
またはshebang)の呼出しが含まれている実行可能なDスクリプトを使用します。独自のDプログラムを作成するときに、ニーズに最も適した方法を選択できます。
DTraceについて
DTraceは、最初にSolarisオペレーティング・システム(現在のOracle Solaris)で使用するために開発され、後にOracle Linuxに移植された包括的な動的トレース機能です。DTraceによって、システムの動作を調査し、その動作状況のよりよい把握、ソフトウェアの多くのレイヤー全体にわたるパフォーマンス問題の検出、または異常な動作の原因の特定を行うことができます。
DTraceを使用すると、カーネルおよびユーザー・スペース・プログラム内のあらかじめ用意された対象の場所(プローブと呼ばれる)で、データを記録できます。プローブは、DTraceがアクションのセット(スタック・トレース、タイムスタンプまたは関数の引数の記録など)を実行するためのリクエストをバインドできる場所です。プローブは、情報を記録できるプログラム可能なセンサーのように動作します。プローブが起動されると、DTraceによってDスクリプトで指定したデータが収集され、ユーザーにデータがレポートされます。
DTraceのDプログラミング言語を使用すると、システムのプローブに問い合せて、ユーザーが定式化できる任意の数の質問に即座に簡潔な回答を得ることができます。
Dプログラムには、1つ以上の指定されたプローブがトリガーされた場合に行われるアクションを記述します。プローブは、プローブを公開したDTraceプロバイダの名前、プローブが存在するモジュール(またはライブラリ、ユーザー・スペース・プログラム)の名前、プローブが存在する関数の名前、およびプローブ自体の名前(通常、トレースできる操作または機能を示しています)によって一意に指定します。プローブは厳密に指定する必要がないため、DTraceでは、複数の異なるプローブに対して同じアクションを実行できます。D言語における1つのプローブの完全かつ明示的な表現の形式は次のとおりです。
PROVIDER:MODULE:FUNCTION:NAME
dtraceコマンドを使用してDプログラムを実行する場合は、D言語のコンパイラを起動します。DTraceによってDプログラムが安全な中間フォームにコンパイルされると、実行のためにオペレーティング・システム・カーネルのDTraceモジュールに送信されます。DTraceモジュールは、プログラムで指定されているプローブをアクティブ化し、プローブが実行されたときに、関連付けられているアクションを実行します。DTraceでは、Dプログラムの実行中に発生する可能性のあるランタイム・エラー(0による除算や無効なメモリーの間接参照など)も処理され、これらがレポートされます。
ノート:
モジュール・プライマー
Oracle LinuxでのDTraceについて詳しく説明する際に、すべてではないまでもほとんどの場合に頻繁に取り上げられる2種類のモジュールがあります。混同しないようにするためには、モジュールが言及されるたびに、説明されているモジュールの種類を特定する必要があります。これらの種類のモジュールについて知識がある場合、通常はコンテキストから多くのヒントを得られます。
PROVIDER:MODULE:FUNCTION:NAMEという順序で記述されているモジュールは、コードの領域を参照および表現するためにDTraceで使用される、順序が明確な個別のコンポーネントであるという意味でのモジュールを指します。このようなDTraceモジュールの参照ポイントDTraceは、コードまたは機能のなんらかのセットに対して指定できます。dtraceコマンドからの出力では、MODULEを使用して、カーネルまたはユーザー・スペース・プログラム内のこのようなコード領域でなんらかのアクティビティが発生したことを伝えます。このタイプのモジュールは、単にDTraceモジュールと呼ばれます。
モジュールという用語の非常に異なる2番目の意味は、Linuxカーネル・モジュールです。Linuxカーネルは、モジュールと呼ばれる異なる機能コンポーネントに分割されており、これらのモジュールは、相互に別々にロードおよびアンロードできます。lsmodコマンドの出力には、システムにロードされているLinuxカーネル・モジュールが表示されます。これらのモジュールは、Linuxカーネル・モジュール、またはLinuxについてのみ説明しているコンテキストでは、単にカーネル・モジュールと呼ばれます。
その他のモジュール参照には、さらに次の2つのバリエーションがあります。
-
LinuxシステムでDTraceを使用するには、DTraceに固有のなんらかのLinuxカーネル・モジュールが存在する必要があります。これらの特定のカーネル・モジュールは、特にdtraceカーネル・モジュールと呼ばれます。特定の
dtrace
カーネル・モジュールから使用可能なプロバイダのリストについては、「DTraceのプロバイダについて」の表を参照してください。 -
DTraceでカーネル・モジュール内のアクティビティをモニターするには、DTraceプローブを任意のカーネル・モジュールにコンパイルする必要があります。ただし、DTraceプローブを使用するカーネル・モジュールは
dtrace
カーネル・モジュールではなく、DTrace対応カーネル・モジュールと呼ばれます。DTraceによって暗黙的にトレース可能なカーネル・モジュールはすべてDTrace対応カーネル・モジュールであるため、通常、明示的にDTrace対応カーネル・モジュールと呼ばれるのではなく、短縮形のカーネル・モジュールと呼ばれます。
潜在的に危険なアクションの実行をDTraceに明示的に許可する場合を除き、オペレーティング・システムまたはシステムで実行されているプロセスに対して、DTraceが意図せずに損傷を与える可能性がある危険なプログラムを作成することはできません。これらの安全機能により、システムのクラッシュや破損を懸念することなく、本番環境でDTraceを使用できます。プログラミング上の間違いがあると、DTraceによってエラーがレポートされ、プログラムのプローブが非アクティブ化されます。その後、プログラムを修正して再試行できます。
DTraceの使用の詳細は、Oracle Linux: DTraceリファレンス・ガイドを参照してください。
DTraceのプロバイダについて
プロバイダ | dtraceカーネル・モジュール | 説明 |
---|---|---|
|
|
DTrace自体に関連するプローブを提供します( |
|
|
カーネル関数の開始および終了時の関数境界トレース(FBT)プローブをサポートします。 |
|
|
DTrace対応のアプリケーションによるユーザー・スペース・トレースをサポートします。 |
|
|
データの入力および出力に関連するプローブを提供します。 |
|
|
IPプロトコル(IPv4とIPv6の両方)のプローブを提供します。 |
|
|
mutexロック、読取り/書込みロック、スピンロックなど、ロック・イベント用のプローブを提供します。 |
|
|
型付き引数を含む、各 |
|
|
プロセスの作成と終了の監視、LWPの作成と終了の監視、新しいプログラムの実行、およびシグナルの処理を行うためのプローブを提供します。 |
|
|
特定の実行ポイントではなく、固定および指定された時間間隔で起動する非同期割込みイベントに関連付けられたプローブを提供します。これらのプローブを使用して、各種のシステム状態をサンプリングできます。 |
|
|
CPUスケジューリングに関連するプローブを提供します。CPUは、すべてのスレッドが必ず使用する単一のリソースであるため、 |
|
|
すべてのシステム・コールのエントリ・ポイントおよびリターン・ポイントにプローブを提供します。システム・コールはユーザー・レベル・アプリケーションとオペレーティング・システム・カーネルとの間の主要なインタフェースであるため、これらのプローブによって、アプリケーションとシステム間の相互作用を把握できます。 |
|
|
IPv4とIPv6の両方について、TCPプロトコルを実装するコード内のプローブを提供します。 |
|
|
IPv4とIPv6の両方について、UDPプロトコルを実装するコード内のプローブを提供します。 |
SDTは、同じプロバイダの下で複数のプロバイダを実装するという点において、マルチプロバイダです。
fasttrap
プロバイダはメタプロバイダとみなされます。つまり、これはプロバイダ・フレームワークです。fasttrap
メタプロバイダを使用すると、ユーザー・スペース・プロセス用にインスタンス化されたプロバイダを簡単に作成できます。
プロバイダおよびそのプローブの詳細は、Oracle Linux: DTraceリファレンス・ガイドのDTraceプロバイダに関する項を参照してください。
DTraceのインストールおよび構成の準備
ノート:
DTraceパッケージ(dtrace-utils
)はULNから入手できます。最良の結果を得るには、システムをULNに登録し、最新のOracle Linuxリリースとともにインストールするか、または最新のOracle Linuxリリースに更新する必要があります。
-
システムで最新のUEKバージョンをまだ実行していない場合は、次のようにします。
-
システムを最新のUEKリリースに更新します。
# yum update
-
システムを再起動し、ブート・メニューで使用可能な最新のUEKバージョンを選択します。通常、これはデフォルトのカーネルです。
-
-
DTraceユーティリティ・パッケージをインストールします。
# yum install dtrace-utils
自動的にロードされるDTraceモジュールの使用
ノート:
自動的にロードされるDTraceカーネル・モジュールを使用するためのクイック・スタートの方法を次に示します。DTraceカーネル・モジュールを手動でロードする場合は、「DTraceモジュールの手動ロード」の指示を参照してください。
DTraceでは、dtraceコマンドでdtrace
カーネル・モジュールに関連付けられているプローブを参照する場合、一部のdtrace
カーネル・モジュールが自動的にロードされます。dtrace
モジュールを手動でロードするかわりに、この便利な方法を使用してロードできます。
この方法で自動的にロードされるモジュールを確認するには、次のコマンドを使用します。
# cat /etc/dtrace-modules sdt systrace profile fasttrap
完全にテストされたことが確認された後で、さらにこのリストにモジュールを追加できます。
特定のモジュールがLinuxカーネルにロードされているかどうかを確認するには、lsmod
コマンドを使用します。たとえば、次のコマンドを実行して、sdt
モジュールがロードされているかどうかを確認します。
# lsmod | grep sdt
モジュールがロードされていない場合、コマンドが出力されない可能性が高くなります。モジュールがロードされている場合、出力は次のようになります。
sdt 20480 0 dtrace 151552 4 sdt,fasttrap,systrace,profile
DTraceモジュールの手動ロード
ノート:
次の情報では、DTraceカーネル・モジュールを手動でロードする方法について説明します。自動的にロードされるDTraceカーネル・モジュールを使用する場合は、チュートリアルのこの項をスキップできます。「自動的にロードされるDTraceモジュールの使用」を参照してください。
DTraceプロバイダを使用するには、カーネルがブートされるたびに、そのサポートされているカーネル・モジュールをロードする必要があります。
dtrace
カーネル・モジュールがまだロードされていない場合、dtraceコマンドを実行すると、dtrace
モジュールおよび/etc/dtrace-modules
に一覧表示されているすべてのモジュールが自動的にロードされます。ただし、dtrace
カーネル・モジュールがすでにロードされている場合、自動カーネル・モジュール・ロード・メカニズムはトリガーされません。
モジュールは、modprobeコマンドを使用して手動でロードできます。たとえば、デフォルト・リストにfbt
カーネル・モジュールがない場合にこのモジュールを使用するには、次のコマンドを実行します。
# modprobe fbt
modprobeアクションでは、dtrace
カーネル・モジュールも依存関係としてロードされるため、dtrace
カーネル・モジュールがロードされなくなるまで、後続のdtraceコマンドにより他のdtrace
モジュールの自動ロードが実行されることはありません。drace
カーネル・モジュールは、システムの別のブート時またはdtrace
カーネル・モジュールの手動削除後にロードされなくなります。
推奨される方法は、dtrace -lコマンドを使用して自動モジュール・ロードをトリガーし、これにより、基本的なdtrace
機能も確認することです。その後、modprobeコマンドを使用して、デフォルト・リストに存在しない追加のモジュール(fbt
など)を必要に応じてロードします。
例: プロバイダのプローブの表示
次の例は、dtraceコマンドを使用して、proc
などのプロバイダのプローブを表示する方法を示しています。
# dtrace -l -P proc ID PROVIDER MODULE FUNCTION NAME 855 proc vmlinux _do_fork lwp-create 856 proc vmlinux _do_fork create 883 proc vmlinux do_exit lwp-exit 884 proc vmlinux do_exit exit 931 proc vmlinux do_sigtimedwait signal-clear 932 proc vmlinux __send_signal signal-send 933 proc vmlinux __send_signal signal-discard 941 proc vmlinux send_sigqueue signal-send 944 proc vmlinux get_signal signal-handle 1044 proc vmlinux schedule_tail start 1045 proc vmlinux schedule_tail lwp-start 1866 proc vmlinux do_execveat_common exec-failure 1868 proc vmlinux do_execveat_common exec 1870 proc vmlinux do_execveat_common exec-success
出力には、プローブの数値識別子、プローブ・プロバイダの名前、プローブ・モジュール名、プローブが含まれている関数の名前、およびプローブ自体の名前が表示されます。
プローブの完全な名前は、PROVIDER:MODULE:FUNCTION:NAME
です。たとえば、proc:vmlinux:_do_fork:create
です。同じプロバイダの他のプローブが明確である場合は、通常、プローブを指定するときにMODULE
要素とFUNCTION
要素を省略できます。たとえば、proc:vmlinux:_do_fork:create
は、proc::_do_fork:create
またはproc:::create
として参照できます。Dプログラムに指定したプローブと複数のプローブが一致する場合は、各プローブに関連付けられているアクションが実行されます。
これらのプローブを使用すると、システムによるプロセスの作成、プログラムの実行、およびシグナルの処理の状態をモニターできます。
以前にチェックし、sdt
モジュールがロードされていなかった場合は、再度チェックして、dtraceコマンドによってそのモジュールがロードされているかどうかを確認します。
dtrace -l -P procコマンドの実行後に(前の例の出力に類似した出力ではなく)次のメッセージが表示された場合は、モジュールがロードされていないことを示しています。
No probe matches description
DTraceが正しくインストールされているシステムでsdt
モジュールが自動的にロードされない場合、これは、modprobeコマンドを使用して別のDTraceモジュールが手動でロードされたためです。この方法でDTraceモジュールを手動でロードすると、システムが再起動されるまで、dtraceコマンドによって他のモジュールが自動的にロードされることを効率的に防ぎます。この例では、1つの回避策として、modprodコマンドを使用してsdt
モジュールを手動でロードする方法があります。モジュールが正常にロードされた場合、dtraceコマンドを再発行すると、「例: プロバイダのプローブの表示」の出力に類似したプローブ・リストが表示されます。
演習: DTraceのプローブの有効化および一覧表示
syscall
プロバイダのプローブを一覧表示してみます。entry
プローブおよびreturn
プローブの両方が、各システム・コールに提供されています。
(予想完了時間: 3分)
演習の回答: DTraceのプローブの有効化および一覧表示
# dtrace -l -P syscall ID PROVIDER MODULE FUNCTION NAME 4 syscall vmlinux read entry 5 syscall vmlinux read return 6 syscall vmlinux write entry 7 syscall vmlinux write return 8 syscall vmlinux open entry 9 syscall vmlinux open return 10 syscall vmlinux close entry 11 syscall vmlinux close return ... 646 syscall vmlinux pkey_mprotect entry 647 syscall vmlinux pkey_mprotect return 648 syscall vmlinux pkey_alloc entry 649 syscall vmlinux pkey_alloc return 650 syscall vmlinux pkey_free entry 651 syscall vmlinux pkey_free return 652 syscall vmlinux statx entry 653 syscall vmlinux statx return 654 syscall vmlinux waitfd entry 655 syscall vmlinux waitfd return
ノート:
ロードされているその他のプロバイダに応じて、システムでのプローブID番号が異なる場合があります。
簡単なDTraceプログラムの実行
次の例は、テキスト・エディタを使用してhello.d
という新しいファイルを作成してから、単純なDプログラムを入力する方法を示しています。
例: BEGINプローブを使用した簡単なDプログラム(hello.d)
/* hello.d -- A simple D program that uses the BEGIN probe */ BEGIN { /* This is a C-style comment */ trace("hello, world"); exit(0); }
Dプログラムは、有効にする1つ以上のプローブについて記述する一連の節およびプローブの起動時に実行するオプションの一連のアクションで構成されています。これらのアクションは、中カッコ{}
で囲まれた一連の文としてプローブ名の後にリストされます。各文は、セミコロン(;
)で終わります。
この例では、関数trace
は、BEGIN
プローブが起動したときに、指定された引数(文字列hello, world)を記録して出力するようにDTraceに指示しています。関数exit()
は、トレースを中止してdtraceコマンドを終了するようにDTraceに指示します。
BEGIN
プローブの完全名はdtrace:::BEGIN
です。dtrace
には、3つのプローブ(dtrace:::BEGIN
、dtrace:::END
およびdtrace:::ERROR
)が用意されています。これらのプローブ名は、dtrace
プロバイダに対して一意であるため、BEGIN
、END
およびERROR
に短縮できます。
プログラムを保存したら、Dプログラムが含まれているファイルの名前を指定する-sオプションを指定して、dtraceコマンドを使用することによって実行できます。
# dtrace -s hello.d dtrace: script 'hello.d' matched 1 probe CPU ID FUNCTION:NAME 0 1 :BEGIN hello, world
DTraceによって、スクリプトが解釈されて実行されます。文字列"hello,world"
に加えて、DTraceのデフォルトの動作により、プローブの実行時にスクリプトが実行されていたCPUに関する情報、プローブのID、プローブが含まれている関数の名前およびプローブ自体の名前が表示されます。BEGIN
,の場合、DTraceによってこのプローブが提供されるため、関数名は空白として表示されます。
プローブの情報は多くの方法で抑制できます。たとえば、-qオプションを指定します。
# dtrace -q -s hello.d hello, world
演習: ENDプローブの使用
hello.d
プログラムをファイルgoodbye.d
にコピーします。文字列"goodbye, world"をトレースするように、およびBEGIN
のかわりにEND
プローブを使用するように、このファイルを編集してください。この新しいスクリプトを実行するには、[Ctrl]+[C]
を押して、プローブを実行し、dtraceを終了させる必要があります。
(予想完了時間: 5分)