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プログラムが含まれているスクリプトを実行するか、dtracehashbang (#!または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のOracle Linux実装に含まれているプロバイダ、およびプロバイダが含まれているカーネル・モジュールを示します。
プロバイダ dtraceカーネル・モジュール 説明

dtrace

dtrace

DTrace自体に関連するプローブを提供します(BEGINERRORENDなど)。これらのプローブを使用して、トレースの開始前にDTraceの状態を初期化し、トレースの完了後にその状態を処理して、他のプローブでの予期しない実行エラーを処理できます。

fbt

fbt

カーネル関数の開始および終了時の関数境界トレース(FBT)プローブをサポートします。

fasttrap

fasttrap

DTrace対応のアプリケーションによるユーザー・スペース・トレースをサポートします。

io

sdt

データの入力および出力に関連するプローブを提供します。ioプロバイダによって、I/Oモニタリングを通じて監視された動作を迅速に調査できます。

IP

sdt

IPプロトコル(IPv4とIPv6の両方)のプローブを提供します。

lockstat

sdt

mutexロック、読取り/書込みロック、スピンロックなど、ロック・イベント用のプローブを提供します。

perf

sdt

型付き引数を含む、各perfトレース・ポイントに対応するプローブを提供します。

proc

sdt

プロセスの作成と終了の監視、LWPの作成と終了の監視、新しいプログラムの実行、およびシグナルの処理を行うためのプローブを提供します。

profile

profile

特定の実行ポイントではなく、固定および指定された時間間隔で起動する非同期割込みイベントに関連付けられたプローブを提供します。これらのプローブを使用して、各種のシステム状態をサンプリングできます。

sched

sdt

CPUスケジューリングに関連するプローブを提供します。CPUは、すべてのスレッドが必ず使用する単一のリソースであるため、schedプロバイダは、体系的な動作を把握するために非常に役立ちます。

syscall

systrace

すべてのシステム・コールのエントリ・ポイントおよびリターン・ポイントにプローブを提供します。システム・コールはユーザー・レベル・アプリケーションとオペレーティング・システム・カーネルとの間の主要なインタフェースであるため、これらのプローブによって、アプリケーションとシステム間の相互作用を把握できます。

TCP

sdt

IPv4とIPv6の両方について、TCPプロトコルを実装するコード内のプローブを提供します。

UDP

sdt

IPv4とIPv6の両方について、UDPプロトコルを実装するコード内のプローブを提供します。

SDTは、同じプロバイダの下で複数のプロバイダを実装するという点において、マルチプロバイダです。

fasttrapプロバイダはメタプロバイダとみなされます。つまり、これはプロバイダ・フレームワークです。fasttrapメタプロバイダを使用すると、ユーザー・スペース・プロセス用にインスタンス化されたプロバイダを簡単に作成できます。

プロバイダおよびそのプローブの詳細は、Oracle Linux: DTraceリファレンス・ガイドDTraceプロバイダに関する項を参照してください。

DTraceのインストールおよび構成の準備

ノート:

DTraceパッケージ(dtrace-utils)はULNから入手できます。最良の結果を得るには、システムをULNに登録し、最新のOracle Linuxリリースとともにインストールするか、または最新のOracle Linuxリリースに更新する必要があります。

DTraceをインストールして構成するには、次のステップを実行します。
  1. システムで最新のUEKバージョンをまだ実行していない場合は、次のようにします。

    1. システムを最新のUEKリリースに更新します。
      # yum update
    2. システムを再起動し、ブート・メニューで使用可能な最新のUEKバージョンを選択します。通常、これはデフォルトのカーネルです。

  2. 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:::BEGINdtrace:::ENDおよびdtrace:::ERROR)が用意されています。これらのプローブ名は、dtraceプロバイダに対して一意であるため、BEGINENDおよび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分)

演習および例の回答: ENDプローブの使用

次に、ENDプローブの使用を示す単純なDプログラムの例を示します。

/* goodbye.d -- Simple D program that demonstrates the END probe */

END
{
  trace("goodbye, world");
}
# dtrace -s goodbye.d
dtrace: script 'goodbye.d' matched 1 probe
^C
CPU     ID                    FUNCTION:NAME
  3      2                             :END   goodbye, world
# dtrace -q -s ./goodbye.d
                     ^C
goodbye, world