aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJustin T. Gibbs <gibbs@FreeBSD.org>1998-09-15 08:16:17 +0000
committerJustin T. Gibbs <gibbs@FreeBSD.org>1998-09-15 08:16:17 +0000
commit7a59208d92931fdf3673fdf276b374bd220e3afe (patch)
treeb5d696c84ab3308f8f0be51f3a01033970d0148f /sys
parentb2dfb1f906d8c8e59539eef1c054963dab103cd5 (diff)
downloadsrc-7a59208d92931fdf3673fdf276b374bd220e3afe.tar.gz
src-7a59208d92931fdf3673fdf276b374bd220e3afe.zip
New Kernel device statistics code.
Submitted by: "Kenneth D. Merry" <ken@plutotech.com>
Notes
Notes: svn path=/head/; revision=39229
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/subr_devstat.c245
-rw-r--r--sys/sys/devicestat.h196
-rw-r--r--sys/sys/dkstat.h12
3 files changed, 442 insertions, 11 deletions
diff --git a/sys/kern/subr_devstat.c b/sys/kern/subr_devstat.c
new file mode 100644
index 000000000000..fe1f832e1a2d
--- /dev/null
+++ b/sys/kern/subr_devstat.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 1997, 1998 Kenneth D. Merry.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <sys/devicestat.h>
+
+static int devstat_num_devs;
+static int devstat_generation;
+static int devstat_version = DEVSTAT_VERSION;
+static int devstat_current_devnumber;
+
+STAILQ_HEAD(devstatlist, devstat) device_statq;
+
+/*
+ * Take a malloced and zeroed devstat structure given to us, fill it in
+ * and add it to the queue of devices.
+ */
+void
+devstat_add_entry(struct devstat *ds, char *dev_name,
+ int unit_number, u_int32_t block_size,
+ devstat_support_flags flags,
+ devstat_type_flags device_type)
+{
+ int s;
+ struct devstatlist *devstat_head;
+
+ if (ds == NULL)
+ return;
+
+ if (devstat_num_devs == 0)
+ STAILQ_INIT(&device_statq);
+
+ devstat_generation++;
+ devstat_num_devs++;
+
+ devstat_head = &device_statq;
+
+ STAILQ_INSERT_TAIL(devstat_head, ds, dev_links);
+
+ ds->device_number = devstat_current_devnumber++;
+ ds->unit_number = unit_number;
+ strncpy(ds->device_name, dev_name, DEVSTAT_NAME_LEN);
+ ds->block_size = block_size;
+ ds->flags = flags;
+ ds->device_type = device_type;
+
+ s = splclock();
+ getmicrotime(&ds->dev_creation_time);
+ splx(s);
+}
+
+/*
+ * Remove a devstat structure from the list of devices.
+ */
+void
+devstat_remove_entry(struct devstat *ds)
+{
+ struct devstatlist *devstat_head;
+
+ if (ds == NULL)
+ return;
+
+ devstat_generation++;
+ devstat_num_devs--;
+
+ devstat_head = &device_statq;
+
+ /* Remove this entry from the devstat queue */
+ STAILQ_REMOVE(devstat_head, ds, devstat, dev_links);
+}
+
+/*
+ * Record a transaction start.
+ */
+void
+devstat_start_transaction(struct devstat *ds)
+{
+ int s;
+
+ /* sanity check */
+ if (ds == NULL)
+ return;
+
+ /*
+ * We only want to set the start time when we are going from idle
+ * to busy. The start time is really the start of the latest busy
+ * period.
+ */
+ if (ds->busy_count == 0) {
+ s = splclock();
+ getmicrouptime(&ds->start_time);
+ splx(s);
+ }
+ ds->busy_count++;
+}
+
+/*
+ * Record the ending of a transaction, and incrment the various counters.
+ */
+void
+devstat_end_transaction(struct devstat *ds, u_int32_t bytes,
+ devstat_tag_type tag_type, devstat_trans_flags flags)
+{
+ int s;
+ struct timeval busy_time;
+
+ /* sanity check */
+ if (ds == NULL)
+ return;
+
+ s = splclock();
+ getmicrouptime(&ds->last_comp_time);
+ splx(s);
+
+ ds->busy_count--;
+
+ /*
+ * There might be some transactions (DEVSTAT_NO_DATA) that don't
+ * transfer any data.
+ */
+ if (flags == DEVSTAT_READ) {
+ ds->bytes_read += bytes;
+ ds->num_reads++;
+ } else if (flags == DEVSTAT_WRITE) {
+ ds->bytes_written += bytes;
+ ds->num_writes++;
+ } else
+ ds->num_other++;
+
+ /*
+ * Keep a count of the various tag types sent.
+ */
+ if (tag_type != DEVSTAT_TAG_NONE)
+ ds->tag_types[tag_type]++;
+
+ /*
+ * We only update the busy time when we go idle. Otherwise, this
+ * calculation would require many more clock cycles.
+ */
+ if (ds->busy_count == 0) {
+ /* Calculate how long we were busy */
+ busy_time = ds->last_comp_time;
+ timevalsub(&busy_time, &ds->start_time);
+
+ /* Add our busy time to the total busy time. */
+ timevaladd(&ds->busy_time, &busy_time);
+ } else if (ds->busy_count < 0)
+ printf("devstat_end_transaction: HELP!! busy_count is < 0!\n");
+}
+
+/*
+ * This is the sysctl handler for the devstat package. The data pushed out
+ * on the kern.devstat.all sysctl variable consists of the current devstat
+ * generation number, and then an array of devstat structures, one for each
+ * device in the system.
+ *
+ * I'm really not too fond of this method of doing things, but there really
+ * aren't that many alternatives. We must have some method of making sure
+ * that the generation number the user gets corresponds with the data the
+ * user gets. If the user makes a separate sysctl call to get the
+ * generation, and then a sysctl call to get the device statistics, the
+ * device list could have changed in that brief period of time. By
+ * supplying the generation number along with the statistics output, we can
+ * guarantee that the generation number and the statistics match up.
+ */
+static int
+sysctl_devstat SYSCTL_HANDLER_ARGS
+{
+ int error, i;
+ struct devstat *nds;
+ struct devstatlist *devstat_head;
+
+ if (devstat_num_devs == 0)
+ return(EINVAL);
+
+ error = 0;
+ devstat_head = &device_statq;
+
+ /*
+ * First push out the generation number.
+ */
+ error = SYSCTL_OUT(req, &devstat_generation, sizeof(int));
+
+ /*
+ * Now push out all the devices.
+ */
+ for (i = 0, nds = devstat_head->stqh_first;
+ (nds != NULL) && (i < devstat_num_devs) && (error == 0);
+ nds = nds->dev_links.stqe_next, i++)
+ error = SYSCTL_OUT(req, nds, sizeof(struct devstat));
+
+ return(error);
+}
+
+/*
+ * Sysctl entries for devstat. The first one is a node that all the rest
+ * hang off of.
+ */
+SYSCTL_NODE(_kern, OID_AUTO, devstat, CTLFLAG_RD, 0, "Device Statistics");
+
+SYSCTL_PROC(_kern_devstat, OID_AUTO, all, CTLFLAG_RD|CTLTYPE_OPAQUE,
+ 0, 0, sysctl_devstat, "S,devstat", "All Devices");
+/*
+ * Export the number of devices in the system so that userland utilities
+ * can determine how much memory to allocate to hold all the devices.
+ */
+SYSCTL_INT(_kern_devstat, OID_AUTO, numdevs, CTLFLAG_RD, &devstat_num_devs,
+ 0, "Number of devices in the devstat list");
+SYSCTL_INT(_kern_devstat, OID_AUTO, generation, CTLFLAG_RD, &devstat_generation,
+ 0, "Devstat list generation");
+SYSCTL_INT(_kern_devstat, OID_AUTO, version, CTLFLAG_RD, &devstat_version,
+ 0, "Devstat list version number");
diff --git a/sys/sys/devicestat.h b/sys/sys/devicestat.h
new file mode 100644
index 000000000000..7a52b5307db4
--- /dev/null
+++ b/sys/sys/devicestat.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 1997, 1998 Kenneth D. Merry.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef _DEVICESTAT_H
+#define _DEVICESTAT_H
+
+#include <sys/queue.h>
+#include <sys/time.h>
+
+#define DEVSTAT_NAME_LEN 16
+
+/*
+ * ATTENTION: The devstat version below should be incremented any time a
+ * change is made in struct devstat, or any time a change is made in the
+ * enumerated types that struct devstat uses. (Only if those changes
+ * would require a recompile -- i.e. re-arranging the order of an
+ * enumerated type or something like that.) This version number is used by
+ * userland utilities to determine whether or not they are in sync with the
+ * kernel.
+ */
+#define DEVSTAT_VERSION 1
+
+/*
+ * These flags specify which statistics features are supported or not
+ * supported by a particular device. The default is all statistics are
+ * supported.
+ */
+typedef enum {
+ DEVSTAT_ALL_SUPPORTED = 0x00,
+ DEVSTAT_NO_BLOCKSIZE = 0x01,
+ DEVSTAT_NO_ORDERED_TAGS = 0x02,
+ DEVSTAT_BS_UNAVAILABLE = 0x04
+} devstat_support_flags;
+
+typedef enum {
+ DEVSTAT_NO_DATA = 0x00,
+ DEVSTAT_READ = 0x01,
+ DEVSTAT_WRITE = 0x02
+} devstat_trans_flags;
+
+typedef enum {
+ DEVSTAT_TAG_SIMPLE = 0x00,
+ DEVSTAT_TAG_HEAD = 0x01,
+ DEVSTAT_TAG_ORDERED = 0x02,
+ DEVSTAT_TAG_NONE = 0x03
+} devstat_tag_type;
+
+/*
+ * These types are intended to aid statistics gathering/display programs.
+ * The first 13 types (up to the 'target' flag) are identical numerically
+ * to the SCSI device type numbers. The next 3 types designate the device
+ * interface. Currently the choices are IDE, SCSI, and 'other'. The last
+ * flag specifies whether or not the given device is a passthrough device
+ * or not. If it is a passthrough device, the lower 4 bits specify which
+ * type of physical device lies under the passthrough device, and the next
+ * 4 bits specify the interface.
+ */
+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;
+
+struct devstat {
+ STAILQ_ENTRY(devstat) dev_links;
+ u_int32_t device_number; /*
+ * Devstat device
+ * number.
+ */
+ char device_name[DEVSTAT_NAME_LEN];
+ int unit_number;
+ u_int64_t bytes_written; /*
+ * Total bytes written
+ * to a device.
+ */
+ u_int64_t bytes_read; /*
+ * Total bytes read
+ * from a device.
+ */
+ u_int64_t num_reads; /*
+ * Total number of
+ * read requests to
+ * the device.
+ */
+ u_int64_t num_writes; /*
+ * Total number of
+ * write requests to
+ * the device.
+ */
+ u_int64_t num_other; /*
+ * Total number of
+ * transactions that
+ * don't read or write
+ * data.
+ */
+ int32_t busy_count; /*
+ * Total number of
+ * transactions
+ * outstanding for
+ * the device.
+ */
+ u_int32_t block_size; /* Block size, bytes */
+ u_int64_t tag_types[3]; /*
+ * The number of
+ * simple, ordered,
+ * and head of queue
+ * tags sent.
+ */
+ struct timeval dev_creation_time; /*
+ * Time the device was
+ * created.
+ */
+ struct timeval busy_time; /*
+ * Total amount of
+ * time drive has spent
+ * processing requests.
+ */
+ struct timeval start_time; /*
+ * The time when
+ * busy_count was
+ * last == 0. Or, the
+ * start of the latest
+ * busy period.
+ */
+ struct timeval last_comp_time; /*
+ * Last time a
+ * transaction was
+ * completed.
+ */
+
+ devstat_support_flags flags; /*
+ * Which statistics
+ * are supported by a
+ * given device.
+ */
+ devstat_type_flags device_type; /* Device type */
+};
+
+#ifdef KERNEL
+void devstat_add_entry(struct devstat *ds, char *dev_name,
+ int unit_number, u_int32_t block_size,
+ devstat_support_flags flags,
+ devstat_type_flags device_type);
+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);
+#endif
+
+#endif /* _DEVICESTAT_H */
diff --git a/sys/sys/dkstat.h b/sys/sys/dkstat.h
index edec8ce605c6..d7abbb19244d 100644
--- a/sys/sys/dkstat.h
+++ b/sys/sys/dkstat.h
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)dkstat.h 8.2 (Berkeley) 1/21/94
- * $Id: dkstat.h,v 1.8 1997/02/22 09:45:08 peter Exp $
+ * $Id: dkstat.h,v 1.9 1997/09/07 05:27:05 bde Exp $
*/
#ifndef _SYS_DKSTAT_H_
@@ -49,17 +49,7 @@
#define CP_IDLE 4
#define CPUSTATES 5
-#define DK_NDRIVE 8
-#define DK_NAMELEN 8
#ifdef KERNEL
-extern long dk_seek[DK_NDRIVE]; /* # seeks */
-extern long dk_wds[DK_NDRIVE]; /* # blocks of 32*16-bit words transferred */
-extern long dk_wpms[DK_NDRIVE]; /* transfer rate in 16-bit words per second */
-extern long dk_xfer[DK_NDRIVE]; /* # transfers */
-extern char dk_names[DK_NDRIVE][DK_NAMELEN]; /* name of drive */
-
-extern int dk_busy; /* bit field of busy drives */
-extern int dk_ndrive; /* number of installed drives */
extern long tk_cancc;
extern long tk_nin;