EN JA
DEVSTAT(9)
DEVSTAT(9) FreeBSD Kernel Developer's Manual DEVSTAT(9)

名称

devstat, devstat_add_entry, devstat_end_transaction, devstat_end_transaction_bio, devstat_remove_entry, devstat_start_transactionデバイス統計の記録のためのカーネルインタフェース

書式

#include < sys/devicestat.h>

void
devstat_add_entry( struct devstat *ds, const char *dev_name, int unit_number, uint32_t block_size, devstat_support_flags flags, devstat_type_flags device_type, devstat_priority priority);

void
devstat_remove_entry( struct devstat *ds);

void
devstat_start_transaction( struct devstat *ds);

void
devstat_end_transaction( struct devstat *ds, uint32_t bytes, devstat_tag_type tag_type, devstat_trans_flags flags);

void
devstat_end_transaction_bio( struct devstat *ds, struct bio *bp);

解説

devstat サブシステムは、その名称が暗示する様に、デバイス統計を記録するためのインタフェースです。この目的は、適度に詳細な統計情報を記録しつつ、記録に使用する CPU 時間を最小とするというものです。従って、 devstat のコードのカーネル内の部分では、実際の統計的な計算は行なわれていません。代わりに、これは、ユーザプログラムが取り扱うように残されています。

devstat_add_entry() は、 devstat サブシステムにデバイスを登録します。呼び出し側は、この関数の呼び出しの前に、既に割当てられ 0 でクリアされた devstat 構造体を持っていることを期待されています。 devstat_add_entry() は、幾つかの引数を取ります。

ds
クライアントによって割当てられ 0 でクリアされた、 devstat 構造体です。
dev_name
デバイスの名前です。例えば da, cd, sa です。
unit_number
デバイスユニット番号です。
block_size
サポートされている場合には、デバイスのブロックサイズです。デバイスがブロックサイズをサポートしていない場合、または devstat リストにそのデバイスが追加される時点では、ブロックサイズが判っていない場合には、 0 に設定されるべきです。
flags
デバイスによって操作がサポートされているかサポートされていないかを示すフラグです。詳細は、以下を参照してください。
device_type
デバイスの型です。これは、3 つの部分、基本的なデバイスの型 (例えば、直接アクセス、CDROM、順次アクセス)、インタフェースの型 (IDE, SCSI またはその他) および通過するデバイスを示すためのパススルーフラグに、分割されます。完全な型のリストは、以下を参照してください。
priority
デバイスの優先度です。優先度は、デバイスの devstat リストの中でどのようにデバイスを並び替えるかを決定するために使用されます。デバイスは、最初に優先度 (高い方から低い方) によって、それからアタッチされた順番によって並び替えられます。利用可能な優先度の完全なリストは、以下を参照してください。

devstat_remove_entry() は、 devstat サブシステムからデバイスを削除します。これは、引数として当のデバイスの devstat 構造体を取ります。 devstat 世代番号は、増やされデバイスの数は、減らされます。

devstat_start_transaction() は、 devstat サブシステムに処理の開始を登録します。個々の処理の開始でビジーカウントが増やされます。デバイスがアイドルからビジーに移ったときには、システム uptime が devstat 構造体の start_time フィールドに記録されます。

devstat_end_transaction() は、 devstat サブシステムに処理の終了を登録します。これは、4 つの引数を取ります。

ds
当のデバイスのための devstat 構造体です。
bytes
この処理で転送されたバイト数です。
tag_type
処理のタグの型です。タグの型は、以下を参照してください。
flags
その処理が読み込みだったのか、書み込みだったのか、または転送されたデータがなかったのかを示す処理フラグです。

devstat_end_transaction_bio() は、biodone() の準備が整っている struct bio からすべての情報を引き出すための、 devstat_end_transaction() のためのラッパです。

devstat 構造体は、以下のフィールドで構成されています。

dev_links
個々の devstat は、登録されたときにリンクされたリストに置かれます。 dev_links フィールドには、 devstat 構造体のリストの中の次のエントリへのポインタが入ります。
device_number
デバイス番号は、個々のデバイスのための一意な識別子です。デバイス番号は、個々の新しいデバイスが登録されるごとに増やされます。現在は、デバイス番号は、単なる 32 ビット整数ですが、40 億個を超えるデバイス到着イベントを持つシステムがあれば、拡張するかもしれません。
device_name
デバイス名称は、ドライバ登録によって与えられる文字列であり、自分自身を識別するために使用できます。 (例えば“da”, “cd”, “sa”, など)。
unit_number
ユニット番号は、当の周辺装置のドライバ特有の実体を識別します。
bytes_written
これは、そのデバイスに既に書込まれたバイト数です。この数は、現在は、符号なし 64 ビット整数です。 32 ビットの整数を使った場合には、システムによっては、すぐにカウンタが一回りしてしまうという問題を、これにより回避できると期待しています。
bytes_read
これは、そのデバイスから既に読み込まれたたバイト数です。
bytes_freed
これは、そのデバイス上の既に解放/消去されたバイト数です。
num_reads
これは、そのデバイスからの読み込み回数です。
num_writes
これは、そのデバイスへの書み込み回数です。
num_frees
これは、そのデバイス上の解放/消去操作の回数です。
num_other
これは、そのデバイスへの読み込みでも書み込みでもない処理の回数です。例えば、 SCSI ドライバは、しばしばテストユニットレディコマンドを SCSI デバイスに送ります。そのテストユニットレディコマンドは、データを全く読み込みまたは書み込みません。これは、単にその状態を返させるだけにすぎません。
busy_count
これは、そのデバイスのための現在未解決の処理の数です。これは、0 を決して下回るべきではなく、アイドルのデバイスでは、0 になるべきです。これらの状態のいずれかが真でない場合には、クライアントのコードの devstat_start_transaction() と devstat_end_transaction() の呼び出し方に問題があることを示しています。個々の処理には、ただ 1 つの処理開始イベントがあるべきであり、各処理に対して 1 つの処理終了イベントがあるべきです。
block_size
そのデバイスがブロックサイズを持っている場合には、これは、そのデバイスのブロックサイズです。
tag_types
これは、デバイスに送られた様々なタグの型の数を記録するためのカウンタの配列です。タグの型のリストは、以下を参照してください。
dev_creation_time
これは、そのデバイスが登録されたときの getmicrotime() によって報告される時間です
busy_time
これは、デバイスのビジーカウントが 0 より大きかった時間の量です。これは、ビジーカウントが 0 に戻ったときにのみ更新されます。
start_time
これは、そのデバイスのビジーカウントが 0 から 1 に移ったときの getmicrouptime() によって報告される時間です
last_comp_time
これは、処理が完全に終わったときの getmicrouptime() によって報告される時間です。これは、デバイスビジー時間を計算するために start_time と一緒に使用されます。
flags
これらのフラグは、個々のデバイスによって、どの統計測定がサポートされているのかを示します。これらのフラグは、本来は、統計を解読するユーザ側のプログラムの補助として働くことを意図されています。
device_type
これは、デバイスの型です。これは、3 つの部分から構成されています。デバイスの型 (例えば、直接アクセス、CDROM、順次アクセス、など)、インタフェース (IDE, SCSI またはその他) および当のデバイスがパススルードライバであるかどうか、です。デバイスの型の完全なリストは、以下を参照してください。
priority
これは、優先度です。これは、デバイスを devstat リストの何処に挿入するのかを決定するために使用される最初のパラメータです。 2 番目のパラメータは、アタッチの順番です。利用可能な優先度のリストは、以下を参照してください。

個々のデバイスは、デバイスの型が与えられます。パススルーデバイスは、インタフェースを供給するためのデバイスと同じ基礎的なデバイスの型とインタフェースを持ちますが、パススルーフラグも設定されています。基本のデバイスの型は、 SCSI のデバイス型番号と一致しています。そのため SCSI 周辺装置では、問合せから返されたデバイスの型は、通常、 SCSI インタフェースの型ともし適切であればパススルーフラグで OR されます。デバイスの型のフラグは、以下のとおりです。

typedef enum { 
 DEVSTAT_TYPE_DIRECT = 0x000, 
 DEVSTAT_TYPE_SEQUENTIAL = 0x001, 
 DEVSTAT_TYPE_PRINTER = 0x002, 
 DEVSTAT_TYPE_PROCESSOR = 0x003, 
 DEVSTAT_TYPE_WORM = 0x004, 
 DEVSTAT_TYPE_CDROM = 0x005, 
 DEVSTAT_TYPE_SCANNER = 0x006, 
 DEVSTAT_TYPE_OPTICAL = 0x007, 
 DEVSTAT_TYPE_CHANGER = 0x008, 
 DEVSTAT_TYPE_COMM = 0x009, 
 DEVSTAT_TYPE_ASC0 = 0x00a, 
 DEVSTAT_TYPE_ASC1 = 0x00b, 
 DEVSTAT_TYPE_STORARRAY = 0x00c, 
 DEVSTAT_TYPE_ENCLOSURE = 0x00d, 
 DEVSTAT_TYPE_FLOPPY = 0x00e, 
 DEVSTAT_TYPE_MASK = 0x00f, 
 DEVSTAT_TYPE_IF_SCSI = 0x010, 
 DEVSTAT_TYPE_IF_IDE = 0x020, 
 DEVSTAT_TYPE_IF_OTHER = 0x030, 
 DEVSTAT_TYPE_IF_MASK = 0x0f0, 
 DEVSTAT_TYPE_PASS = 0x100 
} devstat_type_flags;

デバイスは、それらに関連付けられた優先度を持っていて、 devstat リストのおおよそ何処に置かれるのかを制御します。優先度は、以下のとおりです。

typedef enum { 
 DEVSTAT_PRIORITY_MIN = 0x000, 
 DEVSTAT_PRIORITY_OTHER = 0x020, 
 DEVSTAT_PRIORITY_PASS = 0x030, 
 DEVSTAT_PRIORITY_FD = 0x040, 
 DEVSTAT_PRIORITY_WFD = 0x050, 
 DEVSTAT_PRIORITY_TAPE = 0x060, 
 DEVSTAT_PRIORITY_CD = 0x090, 
 DEVSTAT_PRIORITY_DISK = 0x110, 
 DEVSTAT_PRIORITY_ARRAY = 0x120, 
 DEVSTAT_PRIORITY_MAX = 0xfff 
} devstat_priority;

個々のデバイスは、何の操作がサポートされているかサポートされていないのかを示す、それに関連付けられたフラグを持っています。 devstat_support_flags の値は、以下のとおりです。

DEVSTAT_ALL_SUPPORTED
デバイスによって全ての統計の型がサポートされています。
DEVSTAT_NO_BLOCKSIZE
このデバイスは、ブロックサイズを持っていません。
DEVSTAT_NO_ORDERED_TAGS
このデバイスは、順序タグ (ordered tag) をサポートしていません。
DEVSTAT_BS_UNAVAILABLE
このデバイスは、ブロックサイズをサポートしていますが、現在は、利用できません。このフラグは、リムーバブルメディアのドライバでよく使用されます。

デバイスへの処理は、3 つのカテゴリのうちのいずれかに分類されます。これは、 devstat_end_transaction() へ渡される flags に表現されています。処理の型は、以下のとおりです。

typedef enum { 
 DEVSTAT_NO_DATA = 0x00, 
 DEVSTAT_READ = 0x01, 
 DEVSTAT_WRITE = 0x02, 
 DEVSTAT_FREE = 0x03 
} devstat_trans_flags;

devstat_end_transaction() の tag_type 引数には、次の 4 つの値を指定可能です:

DEVSTAT_TAG_SIMPLE
その処理は、単純なタグを持っていました。
DEVSTAT_TAG_HEAD
この処理は、キュータグの先頭を持っていました。
DEVSTAT_TAG_ORDERED
その処理は、順序タグを持っていました。
DEVSTAT_TAG_NONE
そのデバイスは、タグをサポートしません。

タグの型の値は、 SCSI のタグの定義の下位 4 ビットと一致しています。例えば CAM では、 CCB の tag_action が 0xf と OR することにより、 devstat_end_transaction() に渡すタグの型を判定します。

< sys/devicestat.h>DEVSTAT_VERSION マクロが定義されています。これは、 devstat サブシステムの現在のバージョンで、 devstat 統計にアクセスするユーザ側プログラムの再コンパイルが要求される変更のたびに、増やされるべきです。ユーザ側プログラムは、カーネルの devstat 構造体と同期しているかどうかを決定するために、 kern.devstat.version sysctl 変数を通してこのバージョンを使用します。

歴史

devstat 統計システムは、 FreeBSD 3.0 で登場しました。

作者

Kenneth Merry <ken@FreeBSD.org>

バグ

devstat リスト操作コード周りで spl() 保護が必要かもしれません。これは、例えば誰かが kern.devstat.all sysctl 変数を取り出している間に、デバイスのリストが変更されないことを保証するためです。

現在の devstat の構造では、正確に処理毎の時間を測定することが不可能です。唯一の上手くいきそうな処理毎の正確な時間測定の方法は、処理毎にタイムスタンプを記録することです。システムのパフォーマンスおよび各個の処理のためにタイムスタンプを保存するための空間コストに負の影響を与えるため、この測定は、恐らくは殆んどの人々には価値のないことです。

May 22, 1998 FreeBSD