Solaris 動的トレースガイド

第 22 章 sdt プロバイダ

静的定義トレース (Statically Defined Tracing、SDT) プロバイダは、ソフトウェアプログラマが正式に指定した位置でプローブを作成します。プログラマは、SDT 機構を利用して、DTrace ユーザーにとって重要な箇所をプローブの設定位置として意識的に選択できます。さらに、このプローブに、その位置についてよくわかるようなプローブ名を付けることができます。Solaris カーネルにも少数の SDT プローブが定義されており、将来はさらに追加される予定です。DTrace はまた、ユーザーアプリケーション開発者を対象に、静的プローブを定義する機構を提供しています。これについては、第 34 章ユーザーアプリケーション向けの静的に定義されたトレースで説明します。

プローブ

表 22–1 は、Solaris カーネルに定義されている SDT プローブです。これらのプローブの名前の安定性とデータの安定性は、どちらも「非公開」です。これは、ここでの記述がカーネルの実装を反映しているため、確約されたインタフェースとして推測されるべきでないからです。DTrace の安定性機構の詳細については、「安定性」を参照してください。

表 22–1 SDT プローブ

プローブ名 

説明 

arg0

callout-start

コールアウトの実行直前に起動するプローブ (<sys/callo.h> を参照)。コールアウトは、timeout(9F) の実装を表すものであり、システムクロックによって定期的に実行されます。

実行されるコールアウトを表す callout_t のポインタ (<sys/callo.h> を参照)。

callout-end

コールアウトの実行直後に起動するプローブ (<sys/callo.h> を参照)。

直前に実行されたコールアウトを表す callout_t のポインタ (<sys/callo.h> を参照)。

interrupt-start

デバイスの割り込みハンドラを呼び出す直前に起動するプローブ。 

割り込みデバイスを表す dev_info 構造体のポインタ (<sys/ddi_impldefs.h> を参照)。

interrupt-complete

デバイスの割り込みハンドラから復帰した直後に起動するプローブ。 

割り込みデバイスを表す dev_info 構造体のポインタ (<sys/ddi_impldefs.h> を参照)。

以下は、1 秒に 1 回のペースでコールアウトの動作を調べるスクリプトです。

#pragma D option quiet

sdt:::callout-start
{
	@callouts[((callout_t *)arg0)->c_func] = count();
}

tick-1sec
{
	printa("%40a %10@d\n", @callouts);
	clear(@callouts);
}

この例を実行すると、そのシステム内で timeout(9F) をよく使用するユーザーがわかります。次の出力例を参照してください。


# dtrace -s ./callout.d
                                    FUNC      COUNT
                            TS`ts_update          1
              uhci`uhci_cmd_timeout_hdlr          3
                          genunix`setrun          5
                     genunix`schedpaging          5
                         ata`ghd_timeout         10
 uhci`uhci_handle_root_hub_status_change        309

                                    FUNC      COUNT
              ip`tcp_time_wait_collector          1
                            TS`ts_update          1
              uhci`uhci_cmd_timeout_hdlr          3
                     genunix`schedpaging          4
                          genunix`setrun          8
                         ata`ghd_timeout         10
 uhci`uhci_handle_root_hub_status_change        300

                                    FUNC      COUNT
              ip`tcp_time_wait_collector          0
                        iprb`mii_portmon          1
                            TS`ts_update          1
              uhci`uhci_cmd_timeout_hdlr          3
                     genunix`schedpaging          4
                          genunix`setrun          7
                         ata`ghd_timeout         10
 uhci`uhci_handle_root_hub_status_change        300

timeout(9F) インタフェースは、単一のタイマーの有効期限を出力するだけです。timeout() のインターバルタイマー機能を利用する場合、通常 timeout() ハンドラから timeout を再インストールします。以下に例を示します。

#pragma D option quiet

sdt:::callout-start
{
	self->callout = ((callout_t *)arg0)->c_func;
}

fbt::timeout:entry
/self->callout && arg2 <= 100/
{
	/*
	 * In this case, we are most interested in interval timeout(9F)s that
	 * are short.  We therefore do a linear quantization from 0 ticks to
	 * 100 ticks.  The system clock's frequency — set by the variable
	 * "hz" — defaults to 100, so 100 system clock ticks is one second. 
	 */
	@callout[self->callout] = lquantize(arg2, 0, 100);
}

sdt:::callout-end
{
	self->callout = NULL;
}

END
{
	printa("%a\n%@d\n\n", @callout);
}

このスクリプトを実行し、しばらく待ってから Control-C キーを押すと、次のような出力が得られます。


# dtrace -s ./interval.d
^C
genunix`schedpaging

           value  ------------- Distribution ------------- count    
              24 |                                         0        
              25 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 20       
              26 |                                         0        


ata`ghd_timeout

           value  ------------- Distribution ------------- count    
               9 |                                         0        
              10 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 51       
              11 |                                         0        


uhci`uhci_handle_root_hub_status_change

           value  ------------- Distribution ------------- count    
               0 |                                         0        
               1 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1515     
               2 |                                         0

この出力からわかるように、uhci(7D) ドライバ内の uhci_handle_root_hub_status_change() は、このシステム上のもっとも短い間隔で呼び出されるインターバルタイマー (システムクロック刻みに合わせて呼び出される) です。

割り込みアクティビティに関する情報は、interrupt-start プローブから得ることができます。次の例では、ドライバ名を指定して、割り込みハンドラの実行にかかった時間を調べています。

interrupt-start
{
	self->ts = vtimestamp;
}

interrupt-complete
/self->ts/
{
	this->devi = (struct dev_info *)arg0;
	@[stringof(`devnamesp[this->devi->devi_major].dn_name),
	    this->devi->devi_instance] = quantize(vtimestamp - self->ts);
}

このスクリプトを実行すると、次のような出力が得られます。


# dtrace -s ./intr.d
dtrace: script './intr.d' matched 2 probes
^C
 isp                                                       0
           value  ------------- Distribution ------------- count    
            8192 |                                         0        
           16384 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1        
           32768 |                                         0        

  pcf8584                                                   0
           value  ------------- Distribution ------------- count    
              64 |                                         0        
             128 |                                         2        
             256 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@         157      
             512 |@@@@@@                                   31       
            1024 |                                         3        
            2048 |                                         0        

  pcf8584                                                   1
           value  ------------- Distribution ------------- count    
            2048 |                                         0        
            4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@          154      
            8192 |@@@@@@@                                  37       
           16384 |                                         2        
           32768 |                                         0        

  qlc                                                       0
           value  ------------- Distribution ------------- count    
           16384 |                                         0        
           32768 |@@                                       9        
           65536 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@      126      
          131072 |@                                        5        
          262144 |                                         2        
          524288 |                                         0        

  hme                                                       0
           value  ------------- Distribution ------------- count    
            1024 |                                         0        
            2048 |                                         6        
            4096 |                                         2        
            8192 |@@@@                                     89       
           16384 |@@@@@@@@@@@@@                            262      
           32768 |@                                        37       
           65536 |@@@@@@@                                  139      
          131072 |@@@@@@@@                                 161      
          262144 |@@@                                      73       
          524288 |                                         4        
         1048576 |                                         0        
         2097152 |                                         1        
         4194304 |                                         0        

  ohci                                                      0
           value  ------------- Distribution ------------- count    
            8192 |                                         0        
           16384 |                                         3        
           32768 |                                         1        
           65536 |@@@                                      143      
          131072 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@     1368     
          262144 |                                         0 

SDT プローブの作成

デバイスドライバの開発者は、Solaris ドライバ内に独自の SDT プローブを作成したいと思うことがあるかもしれません。SDT プローブが無効にされている状態は、無操作マシン命令がいくつかある状態と実質的に同じです。したがって、必要に応じて SDT プローブをデバイスドライバに追加してかまいません。これらのプローブがパフォーマンスに悪影響を及ぼさないかぎり、出荷コード内に残しておいてもかまいません。

プローブの宣言

SDT プローブを宣言するときは、<sys/sdt.h> のマクロ DTRACE_PROBE DTRACE_PROBE1DTRACE_PROBE2 DTRACE_PROBE3DTRACE_PROBE4 を使用します。SDT ベースのプローブのモジュール名は、カーネルモジュール名を反映しています。また、関数名は、そのプローブの関数を表しています。プローブ名は、DTRACE_PROBEn マクロで指定された名前によって決まります。この名前に 2 つの連続する下線 (__) が含まれていない場合、マクロに指定されたとおりのプローブ名になります。この名前に 2 つの連続する下線が含まれている場合、プローブ名では、この下線部分がダッシュ 1 個 (-) に変換されます。たとえば、DTRACE_PROBE マクロに transaction__start と指定されている場合、SDT プローブ名は transaction-start になります。このような置き換えが行われるので、C コード内のマクロ名が有効な C 識別子でなくても、文字列を指定しないで使用できます。

カーネルモジュール名と関数名は、DTrace によって、プローブを識別する組に含められます。したがって、名前空間の衝突を避けるためにプローブ名にこの情報を指定する必要性は特にありません。インストール済みのプローブと、DTrace ユーザーが確認できるフルネームを一覧するには、ドライバ上で dtrace -l -P sdt -m module (module はドライバ) を実行します。

プローブ引数

各 SDT プローブの引数は、対応する DTRACE_PROBEn マクロ参照に指定された引数になります。引数の数は、どのマクロを使ってプローブを作成したかによって異なります。 たとえば、DTRACE_PROBE1 は引数を 1 つ、DTRACE_PROBE2 は 2 つ (以下同様) 指定します。SDT プローブを宣言するときは、ポインタを間接参照せず、プローブ引数内の大域変数からロードしないようにすれば、無効時のプローブの影響を最小限に抑えることができます。ポインタの間接参照も、大域変数のロードも、D のプローブ有効化アクション内で安全に実行できます。こうしたアクションが必要なときには要求してかまいません。

安定性

以下の表に、SDT プロバイダの安定性を DTrace の安定性機構に従って示します。安定性機構の詳細については、第 39 章安定性を参照してください。

要素 

名前の安定性 

データの安定性 

依存クラス 

プロバイダ 

発展中 

発展中 

ISA

モジュール 

非公開 

非公開 

不明 

機能 

非公開 

非公開 

不明 

名前 

非公開 

非公開 

ISA

引数 

非公開 

非公開 

ISA