DESCRIPTION

The devstat subsystem is an interface for recording device statistics, as
its name implies. The idea is to keep reasonably detailed statistics
while utilizing a minimum amount of CPU time to record them. Thus, no
statistical calculations are actually performed in the kernel portion of
the devstat code. Instead, that is left for user programs to handle.
devstat_add_entry() registers a device with the devstat subsystem. The
caller is expected to have already allocated andzeroed the devstat
structure before calling this function. devstat_add_entry() takes
several arguments:
ds The devstat structure, allocated and zeroed by the client.
dev_name The device name, e.g. da, cd, sa.
unit_number Device unit number.
block_size Block size of the device, if supported. If the device does
not support a block size, or if the blocksize is unknown at
the time the device is added to the devstat list, it should
be set to 0.
flags Flags indicating operations supported or not supported by
the device. See below for details.
device_type The device type. This is broken into three sections: base
device type (e.g. direct access, CDROM, sequential access),
interface type (IDE, SCSI or other) and a pass-through flag
to indicate pas-through devices. See below for a complete
list of types.
priority The device priority. The priority is used to determine how
devices are sorted within devstat’s list of devices.
Devices are sorted first by priority (highest to lowest),
and then by attach order. See below for a complete list of
available priorities.
devstat_remove_entry() removes a device from the devstat subsystem. It
takes the devstat structure for the device in question as an argument.
The devstat generation number is incremented and the number of devices is
decremented.
devstat_start_transaction() registers the start of a transaction with the
devstat subsystem. The busy count is incremented with each transaction
start. When a device goes from idle to busy, the system uptime is
recorded in the start_time field of the devstat structure.
devstat_end_transaction() registers the end of a transaction with the
devstat subsystem. It takes four arguments:
ds The devstat structure for the device in question.
bytes The number of bytes transferred in this transaction.
tag_type Transaction tag type. See below for tag types.
flags Transaction flags indicating whether the transaction was a
read, write, or whether no data was transferred.
devstat_end_transaction_bio() is a wrapper for devstat_end_transaction()
which pulls all the information from a structbio which is ready for
biodone().
The devstat structure is composed of the following fields:
dev_links Each devstat structure is placed in a linked list when
it is registered. The dev_links field contains a
pointer to the next entry in the list of devstat
structures.
device_number The device number is a unique identifier for each
device. The device number is incremented for each new
device that is registered. The device number is
currently only a 32-bit integer, but it could be
enlarged if someone has a system with more than four
billion device arrival events.
device_name The device name is a text string given by the
registering driver to identify itself. (e.g. “da”,
“cd”, “sa”, etc.)
unit_number The unit number identifies the particular instance of
the peripheral driver in question.
bytes_written This is the number of bytes that have been written to
the device. This number is currently an unsigned 64
bit integer. This will hopefully eliminate the
counter wrap that would come very quickly on some
systems if 32 bit integers were used.
bytes_read This is the number of bytes that have been read from
the device.
bytes_freed This is the number of bytes that have been
freed/erased on the device.
num_reads This is the number of reads from the device.
num_writes This is the number of writes to the device.
num_frees This is the number of free/erase operations on the
device.
num_other This is the number of transactions to the device which
are neither reads or writes. For instance, SCSI
drivers often send a test unit ready command to SCSI
devices. The test unit ready command does not read or
write any data. It merely causes the device to return
its status.
busy_count This is the current number of outstanding transactions
for the device. This should never go below zero, and
on an idle device it should be zero. If either one of
these conditions is not true, it indicates a problem
in the way devstat_start_transaction() and
devstat_end_transaction() are being called in client
code. There should be one and only one transaction
start event and one transaction end event for each
transaction.
block_size This is the block size of the device, if the device
has a block size.
tag_types This is an array of counters to record the number of
various tag types that are sent to a device. See
below for a list of tag types.
dev_creation_time This is the time, as reported by getmicrotime() that
the device was registered.
busy_time This is the amount of time that the device busy count
has been greater than zero. This is only updated when
the busy count returns to zero.
start_time This is the time, as reported by getmicrouptime() that
the device busy count went from zero to one.
last_comp_time This is the time as reported by getmicrouptime() that
a transaction last completed. It is used along with
start_time to calculate the device busy time.
flags These flags indicate which statistics measurements are
supported by a particular device. These flags are
primarily intended to serve as an aid to userland
programs that decipher the statistics.
device_type This is the device type. It consists of three parts:
the device type (e.g. direct access, CDROM, sequential
access, etc.), the interface (IDE, SCSI or other) and
whether or not the device in question is a pass-
through driver. See below for a complete list of
device types.
priority This is the priority. This is the first parameter
used to determine where to insert a device in the
devstat list. The second parameter is attach order.
See below for a list of available priorities.
Each device is given a device type. Pass-through devices have the same
underlying device type and interface as the device they provide an
interface for, but they also have the pass-through flag set. The base
device types are identical to the SCSI device type numbers, so with SCSI
peripherals, the device type returned from an inquiry is usually ORed
with the SCSI interface type and the pass-through flag if appropriate.
The device type flags are as follows:
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;
Devices have a priority associated with them, which controls roughly
where they are placed in the devstat list. The priorities are as
follows:
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;
Each device has associated with it flags to indicate what operations are
supported or not supported. The devstat_support_flags values are as
follows:
DEVSTAT_ALL_SUPPORTED Every statistic type is supported by the device.
DEVSTAT_NO_BLOCKSIZE This device does not have a blocksize.
DEVSTAT_NO_ORDERED_TAGS This device does not support ordered tags.
DEVSTAT_BS_UNAVAILABLE This device supports a blocksize, but it is
currently unavailable. This flag is most often
used with removable media drives.
Transactions to a device fall into one of three categories, which are
represented in the flags passed into devstat_end_transaction(). The
transaction types are as follows:
typedef enum {
DEVSTAT_NO_DATA = 0x00,
DEVSTAT_READ = 0x01,
DEVSTAT_WRITE = 0x02,
DEVSTAT_FREE = 0x03
} devstat_trans_flags;
There are four possible values for the tag_type argument to
devstat_end_transaction():
DEVSTAT_TAG_SIMPLE The transaction had a simple tag.
DEVSTAT_TAG_HEAD The transaction had a head of queue tag.
DEVSTAT_TAG_ORDERED The transaction had an ordered tag.
DEVSTAT_TAG_NONE The device does not support tags.
The tag type values correspond to the lower four bits of the SCSI tag
definitions. In CAM, for instance, the tag_action from the CCB is ORed
with 0xf to determine the tag type to pass in to
devstat_end_transaction().
There is a macro, DEVSTAT_VERSION that is defined in This is the current
version of the devstat subsystem, and it should be incremented each time
a change is made that would require recompilation of userland programs
that access devstat statistics. Userland programs use this version, via
the kern.devstat.versionsysctl variable to determine whether they are in
sync with the kernel devstat structures.

SEEALSO

HISTORY

AUTHORS

BUGS

There may be a need for spl() protection around some of the devstat list
manipulation code to insure, for example, that the list of devices is not
changed while someone is fetching the kern.devstat.allsysctl variable.
It is impossible with the current devstat architecture to accurately
measure time per transaction. The only feasible way to accurately
measure time per transaction would be to record a timestamp for every
transaction. This measurement is probably not worthwhile for most people
as it would adversely affect the performance of the system and cost space
to store the timestamps for individual transactions.