DEVSTAT(9)

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

書式
<sys/devicestat.h> void devstat_add_entry(struct devstat *ds, const char *dev_name, int unit_number, u_int32_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, u_int32_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 変数を通してこのバージョンを使用します。

関連項目
systat(1), devstat(3), iostat(8), rpc.rstatd(8), vmstat(8)

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

作者
Kenneth Merry <ken@FreeBSD.org>

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

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