summaryrefslogtreecommitdiffstats
path: root/usr.bin/vmstat
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>1998-09-15 08:16:45 +0000
committergibbs <gibbs@FreeBSD.org>1998-09-15 08:16:45 +0000
commitb954e9c2642216af00a08bacef1878dbfff8107d (patch)
treecc0e40580a3f167713ca8f61ac0e10a9c27433cc /usr.bin/vmstat
parent78f0dc839b3d746460e6fd2f0ffbb260bf45504c (diff)
downloadFreeBSD-src-b954e9c2642216af00a08bacef1878dbfff8107d.zip
FreeBSD-src-b954e9c2642216af00a08bacef1878dbfff8107d.tar.gz
Update system to new device statistics code.
Submitted by: "Kenneth D. Merry" <ken@plutotech.com>
Diffstat (limited to 'usr.bin/vmstat')
-rw-r--r--usr.bin/vmstat/Makefile5
-rw-r--r--usr.bin/vmstat/vmstat.897
-rw-r--r--usr.bin/vmstat/vmstat.c319
3 files changed, 294 insertions, 127 deletions
diff --git a/usr.bin/vmstat/Makefile b/usr.bin/vmstat/Makefile
index 117c30d..38e45e7 100644
--- a/usr.bin/vmstat/Makefile
+++ b/usr.bin/vmstat/Makefile
@@ -2,10 +2,11 @@
PROG= vmstat
CFLAGS+=-I${.CURDIR}/../../sys
+SRCS= vmstat.c
MAN8= vmstat.8
BINGRP= kmem
BINMODE=2555
-DPADD= ${LIBKVM}
-LDADD= -lkvm
+DPADD= ${LIBKVM} ${LIBDEVSTAT}
+LDADD= -lkvm -ldevstat
.include <bsd.prog.mk>
diff --git a/usr.bin/vmstat/vmstat.8 b/usr.bin/vmstat/vmstat.8
index ec6c323..6c06202 100644
--- a/usr.bin/vmstat/vmstat.8
+++ b/usr.bin/vmstat/vmstat.8
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)vmstat.8 8.1 (Berkeley) 6/6/93
-.\" $Id: vmstat.8,v 1.8 1997/08/23 21:42:46 steve Exp $
+.\" $Id: vmstat.8,v 1.9 1997/08/25 06:40:05 charnier Exp $
.\"
.Dd June 6, 1996
.Dt VMSTAT 8
@@ -46,6 +46,8 @@
.Op Fl M Ar core
.Op Fl N Ar system
.Op Fl w Ar wait
+.Op Fl n Ar devs
+.Op Fl p Ar type,if,pass
.Op Ar disks
.Sh DESCRIPTION
.Nm Vmstat
@@ -86,6 +88,76 @@ instead of the default
.It Fl m
Report on the usage of kernel dynamic memory listed first by size of
allocation and then by type of usage.
+.It Fl n
+Change the maximum number of disks to display from the default of 3.
+.It Fl p
+Specify which types of devices to display. There are three different
+categories of devices:
+
+.Bl -tag -width indent -compact
+.It device type:
+.Bl -tag -width 123456789 -compact
+.It da
+Direct Access devices
+.It sa
+Sequential Access devices
+.It printer
+Printers
+.It proc
+Processor devices
+.It worm
+Write Once Read Multiple devices
+.It cd
+CD devices
+.It scanner
+Scanner devices
+.It optical
+Optical Memory devices
+.It changer
+Medium Changer devices
+.It comm
+Communication devices
+.It array
+Storage Array devices
+.It enclosure
+Enclosure Services devices
+.It floppy
+Floppy devices
+.El
+.Pp
+.It interface:
+.Bl -tag -width 123456789 -compact
+.It IDE
+Integrated Drive Electronics devices
+.It SCSI
+Small Computer System Interface devices
+.It other
+Any other device interface
+.El
+.Pp
+.It passthrough:
+.Bl -tag -width 123456789 -compact
+.It pass
+Passthrough devices
+.El
+.El
+.Pp
+The user must specify at least one device type, and may specify at most
+one device type from each category. Multiple device types in a single
+device type statement must be separated by commas.
+.Pp
+Any number of
+.Fl p
+arguments may be specified on the command line. All
+.Fl p
+arguments are ORed together to form a matching expression against which
+all devices in the system are compared. Any device that fully matches
+any
+.Fl p
+argument will be included in the
+.Nm
+output, up to three devices, or the maximum number of devices specified
+by the user.
.It Fl s
Display the contents of the
.Em sum
@@ -156,14 +228,25 @@ pages scanned by clock algorithm, per-second
.It disks
Disk operations per second (this field is system dependent).
Typically paging will be split across the available drives.
-The header of the field is the first character of the disk name and
+The header of the field is the first two characters of the disk name and
the unit number.
-If more than four disk drives are configured in the system,
+If more than three disk drives are configured in the system,
.Nm
-displays only the first four drives.
+displays only the first three drives, unless the user specifies the
+.Fl n
+argument to increase the number of drives displayed. This will probably
+cause the display to exceed 80 columns, however.
To force
.Nm
to display specific drives, their names may be supplied on the command line.
+.Nm
+defaults to show disks first, and then various other random devices in the
+system to add up to three devices, if there are that many devices in the
+system. If devices are specified on the command line, or if a device type
+matching pattern is specified (see above),
+.Nm
+will only display the given devices or the devices matching the pattern,
+and will not randomly select other devices in the system.
.It faults
Trap/interrupt rate averages per second over last 5 seconds.
.Pp
@@ -195,6 +278,12 @@ seconds; this is a good choice of printing interval since this is how often
some of the statistics are sampled in the system.
Others vary every second and running the output for a while will make it
apparent which are recomputed every second.
+.Pp
+The command:
+.Dl vmstat -p da -p cd -w 1
+will tell vmstat to select the first three direct access or CDROM devices
+and display statistics on those devices, as well as other systems
+statistics every second.
.Sh FILES
.Bl -tag -width /dev/kmemxxx -compact
.It Pa /kernel
diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c
index 3701ec4..7f37b95 100644
--- a/usr.bin/vmstat/vmstat.c
+++ b/usr.bin/vmstat/vmstat.c
@@ -42,7 +42,7 @@ static const char copyright[] =
static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93";
#endif
static const char rcsid[] =
- "$Id: vmstat.c,v 1.23 1998/03/07 23:40:23 dyson Exp $";
+ "$Id: vmstat.c,v 1.24 1998/07/06 21:01:54 bde Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -74,48 +74,45 @@ static const char rcsid[] =
#include <sysexits.h>
#include <time.h>
#include <unistd.h>
+#include <devstat.h>
struct nlist namelist[] = {
#define X_CPTIME 0
{ "_cp_time" },
-#define X_DK_NDRIVE 1
- { "_dk_ndrive" },
-#define X_SUM 2
+#define X_SUM 1
{ "_cnt" },
-#define X_BOOTTIME 3
+#define X_BOOTTIME 2
{ "_boottime" },
-#define X_DKXFER 4
- { "_dk_xfer" },
-#define X_HZ 5
+#define X_HZ 3
{ "_hz" },
-#define X_STATHZ 6
+#define X_STATHZ 4
{ "_stathz" },
-#define X_NCHSTATS 7
+#define X_NCHSTATS 5
{ "_nchstats" },
-#define X_INTRNAMES 8
+#define X_INTRNAMES 6
{ "_intrnames" },
-#define X_EINTRNAMES 9
+#define X_EINTRNAMES 7
{ "_eintrnames" },
-#define X_INTRCNT 10
+#define X_INTRCNT 8
{ "_intrcnt" },
-#define X_EINTRCNT 11
+#define X_EINTRCNT 9
{ "_eintrcnt" },
-#define X_KMEMSTATISTICS 12
+#define X_KMEMSTATISTICS 10
{ "_kmemstatistics" },
-#define X_KMEMBUCKETS 13
+#define X_KMEMBUCKETS 11
{ "_bucket" },
#ifdef notyet
-#define X_DEFICIT 14
+#define X_DEFICIT 12
{ "_deficit" },
-#define X_FORKSTAT 15
+#define X_FORKSTAT 13
{ "_forkstat" },
-#define X_REC 16
+#define X_REC 14
{ "_rectime" },
-#define X_PGIN 17
+#define X_PGIN 15
{ "_pgintime" },
-#define X_XSTATS 18
+#define X_XSTATS 16
{ "_xstats" },
-#define X_END 19
+#define X_END 17
#else
#define X_END 14
#endif
@@ -123,10 +120,6 @@ struct nlist namelist[] = {
#define X_HPDINIT (X_END)
{ "_hp_dinit" },
#endif
-#if defined(i386)
-#define X_DK_NAMES (X_END)
- { "_dk_names" },
-#endif
#ifdef mips
#define X_SCSI_DINIT (X_END)
{ "_scsi_dinit" },
@@ -148,14 +141,17 @@ struct nlist namelist[] = {
{ "" },
};
-struct _disk {
- long time[CPUSTATES];
- long *xfer;
-} cur, last;
+struct statinfo cur, last;
+int num_devices, maxshowdevs, generation;
+struct device_selection *dev_select;
+int num_selected;
+struct devstat_match *matches;
+int num_matches = 0;
+int num_devices_specified, num_selections, select_generation;
+char **specified_devices;
+devstat_select_mode select_mode;
struct vmmeter sum, osum;
-char **dr_name;
-int *dr_select, dk_ndrive, ndrives;
int winlines = 20;
@@ -168,14 +164,13 @@ kvm_t *kd;
#define TIMESTAT 0x10
#define VMSTAT 0x20
-#include "names.c" /* disk names -- machine dependent */
-
-void cpustats(), dkstats(), dointr(), domem(), dosum();
+void cpustats(), dointr(), domem(), dosum();
void dovmstat(), kread(), usage();
#ifdef notyet
void dotimes(), doforkst();
#endif
void printhdr __P((void));
+static void devstats();
int
main(argc, argv)
@@ -187,10 +182,12 @@ main(argc, argv)
int reps;
char *memf, *nlistf;
char errbuf[_POSIX2_LINE_MAX];
+ char *err_str;
memf = nlistf = NULL;
interval = reps = todo = 0;
- while ((c = getopt(argc, argv, "c:fiM:mN:stw:")) != -1) {
+ maxshowdevs = 3;
+ while ((c = getopt(argc, argv, "c:fiM:mN:n:p:stw:")) != -1) {
switch (c) {
case 'c':
reps = atoi(optarg);
@@ -214,6 +211,16 @@ main(argc, argv)
case 'N':
nlistf = optarg;
break;
+ case 'n':
+ maxshowdevs = atoi(optarg);
+ if (maxshowdevs < 0)
+ errx(1, "number of devices %d is < 0",
+ maxshowdevs);
+ break;
+ case 'p':
+ if (buildmatch(optarg, &matches, &num_matches) != 0)
+ errx(1, "%s", devstat_errbuf);
+ break;
case 's':
todo |= SUMSTAT;
break;
@@ -314,62 +321,64 @@ getdrivedata(argv)
char **argv;
{
register int i;
- register char **cp;
char buf[30];
- kread(X_DK_NDRIVE, &dk_ndrive, sizeof(dk_ndrive));
- if (dk_ndrive < 0)
- errx(1, "dk_ndrive %d", dk_ndrive);
- dr_select = calloc((size_t)dk_ndrive, sizeof(int));
- dr_name = calloc((size_t)dk_ndrive, sizeof(char *));
- for (i = 0; i < dk_ndrive; i++)
- dr_name[i] = NULL;
- cur.xfer = calloc((size_t)dk_ndrive, sizeof(long));
- last.xfer = calloc((size_t)dk_ndrive, sizeof(long));
- if (!read_names())
- exit (1);
- for (i = 0; i < dk_ndrive; i++)
- if (dr_name[i] == NULL) {
- (void)sprintf(buf, "??%d", i);
- dr_name[i] = strdup(buf);
- }
+ if ((num_devices = getnumdevs()) < 0)
+ errx(1, "%s", devstat_errbuf);
- /*
- * Choose drives to be displayed. Priority goes to (in order) drives
- * supplied as arguments, default drives. If everything isn't filled
- * in and there are drives not taken care of, display the first few
- * that fit.
- */
-#define BACKWARD_COMPATIBILITY
- for (ndrives = 0; *argv; ++argv) {
-#ifdef BACKWARD_COMPATIBILITY
+ cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
+ last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
+ bzero(cur.dinfo, sizeof(struct devinfo));
+ bzero(last.dinfo, sizeof(struct devinfo));
+
+ if (getdevs(&cur) == -1)
+ errx(1, "%s", devstat_errbuf);
+
+ num_devices = cur.dinfo->numdevs;
+ generation = cur.dinfo->generation;
+
+ specified_devices = (char **)malloc(sizeof(char *));
+ for (num_devices_specified = 0; *argv; ++argv) {
if (isdigit(**argv))
break;
-#endif
- for (i = 0; i < dk_ndrive; i++) {
- if (strcmp(dr_name[i], *argv))
- continue;
- dr_select[i] = 1;
- ++ndrives;
- break;
- }
- }
- for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
- if (dr_select[i])
- continue;
- for (cp = defdrives; *cp; cp++)
- if (strcmp(dr_name[i], *cp) == 0) {
- dr_select[i] = 1;
- ++ndrives;
- break;
- }
- }
- for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
- if (dr_select[i])
- continue;
- dr_select[i] = 1;
- ++ndrives;
+ num_devices_specified++;
+ specified_devices = (char **)realloc(specified_devices,
+ sizeof(char *) *
+ num_devices_specified);
+ specified_devices[num_devices_specified - 1] = *argv;
}
+ dev_select = NULL;
+
+ /*
+ * People are generally only interested in disk statistics when
+ * they're running vmstat. So, that's what we're going to give
+ * them if they don't specify anything by default. We'll also give
+ * them any other random devices in the system so that we get to
+ * maxshowdevs devices, if that many devices exist. If the user
+ * specifies devices on the command line, either through a pattern
+ * match or by naming them explicitly, we will give the user only
+ * those devices.
+ */
+ if ((num_devices_specified == 0) && (num_matches == 0)) {
+ if (buildmatch("da", &matches, &num_matches) != 0)
+ errx(1, "%s", devstat_errbuf);
+
+ select_mode = DS_SELECT_ADD;
+ } else
+ select_mode = DS_SELECT_ONLY;
+
+ /*
+ * At this point, selectdevs will almost surely indicate that the
+ * device list has changed, so we don't look for return values of 0
+ * or 1. If we get back -1, though, there is an error.
+ */
+ if (selectdevs(&dev_select, &num_selected, &num_selections,
+ &select_generation, generation, cur.dinfo->devices,
+ num_devices, matches, num_matches, specified_devices,
+ num_devices_specified, select_mode,
+ maxshowdevs, 0) == -1)
+ errx(1, "%s", devstat_errbuf);
+
return(argv);
}
@@ -397,6 +406,7 @@ dovmstat(interval, reps)
{
struct vmtotal total;
time_t uptime, halfuptime;
+ struct devinfo *tmp_dinfo;
void needhdr();
int mib[2], size;
@@ -409,11 +419,63 @@ dovmstat(interval, reps)
if (!hz)
kread(X_HZ, &hz, sizeof(hz));
+ /*
+ * Make sure that the userland devstat version matches the kernel
+ * devstat version. If not, exit and print a message informing
+ * the user of his mistake.
+ */
+ if (checkversion() < 0)
+ errx(1, "%s", devstat_errbuf);
+
for (hdrcnt = 1;;) {
if (!--hdrcnt)
printhdr();
- kread(X_CPTIME, cur.time, sizeof(cur.time));
- kread(X_DKXFER, cur.xfer, sizeof(*cur.xfer) * dk_ndrive);
+ kread(X_CPTIME, cur.cp_time, sizeof(cur.cp_time));
+
+ tmp_dinfo = last.dinfo;
+ last.dinfo = cur.dinfo;
+ cur.dinfo = tmp_dinfo;
+ last.busy_time = cur.busy_time;
+
+ /*
+ * Here what we want to do is refresh our device stats.
+ * getdevs() returns 1 when the device list has changed.
+ * If the device list has changed, we want to go through
+ * the selection process again, in case a device that we
+ * were previously displaying has gone away.
+ */
+ switch (getdevs(&cur)) {
+ case -1:
+ errx(1, "%s", devstat_errbuf);
+ break;
+ case 1: {
+ int retval;
+
+ num_devices = cur.dinfo->numdevs;
+ generation = cur.dinfo->generation;
+
+ retval = selectdevs(&dev_select, &num_selected,
+ &num_selections, &select_generation,
+ generation, cur.dinfo->devices,
+ num_devices, matches, num_matches,
+ specified_devices,
+ num_devices_specified, select_mode,
+ maxshowdevs, 0);
+ switch (retval) {
+ case -1:
+ errx(1, "%s", devstat_errbuf);
+ break;
+ case 1:
+ printhdr();
+ break;
+ default:
+ break;
+ }
+ }
+ default:
+ break;
+ }
+
kread(X_SUM, &sum, sizeof(sum));
size = sizeof(total);
mib[0] = CTL_VM;
@@ -442,7 +504,7 @@ dovmstat(interval, reps)
(u_long)rate(sum.v_tfree - osum.v_tfree));
(void)printf("%3lu ",
(u_long)rate(sum.v_pdpages - osum.v_pdpages));
- dkstats();
+ devstats();
(void)printf("%4lu %4lu %3lu ",
(u_long)rate(sum.v_intr - osum.v_intr),
(u_long)rate(sum.v_syscall - osum.v_syscall),
@@ -471,17 +533,23 @@ printhdr()
{
register int i;
- (void)printf(" procs memory page%*s", 20, "");
- if (ndrives > 1)
+ (void)printf(" procs memory page%*s", 19, "");
+ if (num_selected > 1)
(void)printf("disks %*s faults cpu\n",
- ndrives * 3 - 6, "");
+ ((num_selected < maxshowdevs) ? num_selected :
+ maxshowdevs ) * 4 - 7, "");
+ else if (num_selected == 1)
+ (void)printf("disk faults cpu\n");
else
- (void)printf("%*s faults cpu\n", ndrives * 3, "");
+ (void)printf("%*s faults cpu\n", num_selected * 4, "");
+
(void)printf(" r b w avm fre flt re pi po fr sr ");
- for (i = 0; i < dk_ndrive; i++)
- if (dr_select[i])
- (void)printf("%c%c ", dr_name[i][0],
- dr_name[i][strlen(dr_name[i]) - 1]);
+ for (i = 0; i < num_devices; i++)
+ if ((dev_select[i].selected)
+ && (dev_select[i].selected <= maxshowdevs))
+ (void)printf("%c%c%d ", dev_select[i].device_name[0],
+ dev_select[i].device_name[1],
+ dev_select[i].unit_number);
(void)printf(" in sy cs us sy id\n");
hdrcnt = winlines - 2;
}
@@ -624,32 +692,39 @@ doforkst()
}
#endif
-void
-dkstats()
+static void
+devstats()
{
register int dn, state;
- double etime;
+ long double transfers_per_second;
+ long double busy_seconds;
long tmp;
-
- for (dn = 0; dn < dk_ndrive; ++dn) {
- tmp = cur.xfer[dn];
- cur.xfer[dn] -= last.xfer[dn];
- last.xfer[dn] = tmp;
- }
- etime = 0;
+
for (state = 0; state < CPUSTATES; ++state) {
- tmp = cur.time[state];
- cur.time[state] -= last.time[state];
- last.time[state] = tmp;
- etime += cur.time[state];
+ tmp = cur.cp_time[state];
+ cur.cp_time[state] -= last.cp_time[state];
+ last.cp_time[state] = tmp;
}
- if (etime == 0)
- etime = 1;
- etime /= hz;
- for (dn = 0; dn < dk_ndrive; ++dn) {
- if (!dr_select[dn])
+
+ busy_seconds = compute_etime(cur.busy_time, last.busy_time);
+
+ for (dn = 0; dn < num_devices; dn++) {
+ int di;
+
+ if ((dev_select[dn].selected == 0)
+ || (dev_select[dn].selected > maxshowdevs))
continue;
- (void)printf("%2.0f ", cur.xfer[dn] / etime);
+
+ di = dev_select[dn].position;
+
+ if (compute_stats(&cur.dinfo->devices[di],
+ &last.dinfo->devices[di], busy_seconds,
+ NULL, NULL, NULL,
+ NULL, &transfers_per_second, NULL,
+ NULL, NULL) != 0)
+ errx(1, "%s", devstat_errbuf);
+
+ printf("%3.0Lf ", transfers_per_second);
}
}
@@ -661,14 +736,16 @@ cpustats()
total = 0;
for (state = 0; state < CPUSTATES; ++state)
- total += cur.time[state];
+ total += cur.cp_time[state];
if (total)
pct = 100 / total;
else
pct = 0;
- (void)printf("%2.0f ", (cur.time[CP_USER] + cur.time[CP_NICE]) * pct);
- (void)printf("%2.0f ", (cur.time[CP_SYS] + cur.time[CP_INTR]) * pct);
- (void)printf("%2.0f", cur.time[CP_IDLE] * pct);
+ (void)printf("%2.0f ", (cur.cp_time[CP_USER] +
+ cur.cp_time[CP_NICE]) * pct);
+ (void)printf("%2.0f ", (cur.cp_time[CP_SYS] +
+ cur.cp_time[CP_INTR]) * pct);
+ (void)printf("%2.0f", cur.cp_time[CP_IDLE] * pct);
}
void
OpenPOWER on IntegriCloud