Update system to new device statistics code.
Submitted by: "Kenneth D. Merry" <ken@plutotech.com>
This commit is contained in:
parent
7a59208d92
commit
8d2fbde504
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=39230
320
usr.bin/systat/devs.c
Normal file
320
usr.bin/systat/devs.c
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright (c) 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$
|
||||
*/
|
||||
/*
|
||||
* Some code and ideas taken from the old disks.c.
|
||||
* static char sccsid[] = "@(#)disks.c 8.1 (Berkeley) 6/6/93";
|
||||
*/
|
||||
/*-
|
||||
* Copyright (c) 1980, 1992, 1993
|
||||
* The Regents of the University of California. 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/devicestat.h>
|
||||
#include <sys/dkstat.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <devstat.h>
|
||||
#include "systat.h"
|
||||
#include "extern.h"
|
||||
|
||||
typedef enum {
|
||||
DS_MATCHTYPE_NONE,
|
||||
DS_MATCHTYPE_SPEC,
|
||||
DS_MATCHTYPE_PATTERN
|
||||
} last_match_type;
|
||||
|
||||
last_match_type last_type;
|
||||
struct device_selection *dev_select;
|
||||
int generation, num_devices, num_selected;
|
||||
int num_selections, select_generation;
|
||||
struct devstat_match *matches = NULL;
|
||||
int num_matches = 0;
|
||||
char **specified_devices;
|
||||
int num_devices_specified = 0;
|
||||
|
||||
static int dsmatchselect(char *args, devstat_select_mode select_mode,
|
||||
int maxshowdevs, struct statinfo *s1);
|
||||
static int dsselect(char *args, devstat_select_mode select_mode,
|
||||
int maxshowdevs, struct statinfo *s1);
|
||||
|
||||
int
|
||||
dsinit(int maxshowdevs, struct statinfo *s1, struct statinfo *s2,
|
||||
struct statinfo *s3)
|
||||
{
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
generation = 0;
|
||||
num_devices = 0;
|
||||
num_selected = 0;
|
||||
num_selections = 0;
|
||||
select_generation = 0;
|
||||
last_type = DS_MATCHTYPE_NONE;
|
||||
|
||||
if (getdevs(s1) == -1)
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
|
||||
num_devices = s1->dinfo->numdevs;
|
||||
generation = s1->dinfo->generation;
|
||||
|
||||
dev_select = NULL;
|
||||
|
||||
/*
|
||||
* 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, s1->dinfo->devices,
|
||||
num_devices, NULL, 0, NULL, 0, DS_SELECT_ADD,
|
||||
maxshowdevs, 0) == -1)
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
dscmd(char *cmd, char *args, int maxshowdevs, struct statinfo *s1)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (prefix(cmd, "display") || prefix(cmd, "add"))
|
||||
return(dsselect(args, DS_SELECT_ADDONLY, maxshowdevs, s1));
|
||||
if (prefix(cmd, "ignore") || prefix(cmd, "delete"))
|
||||
return(dsselect(args, DS_SELECT_REMOVE, maxshowdevs, s1));
|
||||
if (prefix(cmd, "show") || prefix(cmd, "only"))
|
||||
return(dsselect(args, DS_SELECT_ONLY, maxshowdevs, s1));
|
||||
if (prefix(cmd, "type") || prefix(cmd, "match"))
|
||||
return(dsmatchselect(args, DS_SELECT_ONLY, maxshowdevs, s1));
|
||||
if (prefix(cmd, "refresh")) {
|
||||
retval = selectdevs(&dev_select, &num_selected, &num_selections,
|
||||
&select_generation, generation,
|
||||
s1->dinfo->devices, num_devices,
|
||||
(last_type == DS_MATCHTYPE_PATTERN) ?
|
||||
matches : NULL,
|
||||
(last_type == DS_MATCHTYPE_PATTERN) ?
|
||||
num_matches : 0,
|
||||
(last_type == DS_MATCHTYPE_SPEC) ?
|
||||
specified_devices : NULL,
|
||||
(last_type == DS_MATCHTYPE_SPEC) ?
|
||||
num_devices_specified : 0,
|
||||
(last_type == DS_MATCHTYPE_NONE) ?
|
||||
DS_SELECT_ADD : DS_SELECT_ADDONLY,
|
||||
maxshowdevs, 0);
|
||||
if (retval == -1) {
|
||||
warnx("%s", devstat_errbuf);
|
||||
return(0);
|
||||
} else if (retval == 1)
|
||||
return(2);
|
||||
}
|
||||
if (prefix(cmd, "drives")) {
|
||||
register int i;
|
||||
move(CMDLINE, 0);
|
||||
clrtoeol();
|
||||
for (i = 0; i < num_devices; i++) {
|
||||
printw("%s%d ", s1->dinfo->devices[i].device_name,
|
||||
s1->dinfo->devices[i].unit_number);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
dsmatchselect(char *args, devstat_select_mode select_mode, int maxshowdevs,
|
||||
struct statinfo *s1)
|
||||
{
|
||||
char **tempstr;
|
||||
char *tstr[100];
|
||||
char *err_str;
|
||||
int num_args = 0;
|
||||
register int i;
|
||||
int retval = 0;
|
||||
|
||||
/*
|
||||
* Break the (pipe delimited) input string out into separate
|
||||
* strings.
|
||||
*/
|
||||
for (tempstr = tstr, num_args = 0;
|
||||
(*tempstr = strsep(&args, "|")) != NULL && (num_args < 100);
|
||||
num_args++)
|
||||
if (**tempstr != '\0')
|
||||
if (++tempstr >= &tstr[100])
|
||||
break;
|
||||
|
||||
if (num_args > 99) {
|
||||
warnx("dsmatchselect: too many match arguments");
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we've gone through the matching code before, clean out
|
||||
* previously used memory.
|
||||
*/
|
||||
if (num_matches > 0) {
|
||||
free(matches);
|
||||
matches = NULL;
|
||||
num_matches = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_args; i++) {
|
||||
if (buildmatch(tstr[i], &matches, &num_matches) != 0) {
|
||||
warnx("%s", devstat_errbuf);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if (num_args > 0) {
|
||||
|
||||
last_type = DS_MATCHTYPE_PATTERN;
|
||||
|
||||
retval = selectdevs(&dev_select, &num_selected, &num_selections,
|
||||
&select_generation, generation,
|
||||
s1->dinfo->devices, num_devices, matches,
|
||||
num_matches, NULL, 0, select_mode,
|
||||
maxshowdevs, 0);
|
||||
if (retval == -1)
|
||||
err(1, "device selection error");
|
||||
else if (retval == 1)
|
||||
return(2);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int
|
||||
dsselect(char *args, devstat_select_mode select_mode, int maxshowdevs,
|
||||
struct statinfo *s1)
|
||||
{
|
||||
register char *cp;
|
||||
register int i;
|
||||
int retval = 0;
|
||||
char *index();
|
||||
|
||||
/*
|
||||
* If we've gone through this code before, free previously
|
||||
* allocated resources.
|
||||
*/
|
||||
if (num_devices_specified > 0) {
|
||||
for (i = 0; i < num_devices_specified; i++)
|
||||
free(specified_devices[i]);
|
||||
free(specified_devices);
|
||||
specified_devices = NULL;
|
||||
num_devices_specified = 0;
|
||||
}
|
||||
|
||||
/* do an initial malloc */
|
||||
specified_devices = (char **)malloc(sizeof(char *));
|
||||
|
||||
cp = index(args, '\n');
|
||||
if (cp)
|
||||
*cp = '\0';
|
||||
for (;;) {
|
||||
for (cp = args; *cp && isspace(*cp); cp++)
|
||||
;
|
||||
args = cp;
|
||||
for (; *cp && !isspace(*cp); cp++)
|
||||
;
|
||||
if (*cp)
|
||||
*cp++ = '\0';
|
||||
if (cp - args == 0)
|
||||
break;
|
||||
for (i = 0; i < num_devices; i++) {
|
||||
char tmpstr[80];
|
||||
|
||||
sprintf(tmpstr, "%s%d", dev_select[i].device_name,
|
||||
dev_select[i].unit_number);
|
||||
if (strcmp(args, tmpstr) == 0) {
|
||||
|
||||
num_devices_specified++;
|
||||
|
||||
specified_devices =(char **)realloc(
|
||||
specified_devices,
|
||||
sizeof(char *) *
|
||||
num_devices_specified);
|
||||
specified_devices[num_devices_specified -1]=
|
||||
strdup(args);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= num_devices)
|
||||
error("%s: unknown drive", args);
|
||||
args = cp;
|
||||
}
|
||||
|
||||
if (num_devices_specified > 0) {
|
||||
last_type = DS_MATCHTYPE_SPEC;
|
||||
|
||||
retval = selectdevs(&dev_select, &num_selected, &num_selections,
|
||||
&select_generation, generation,
|
||||
s1->dinfo->devices, num_devices, NULL, 0,
|
||||
specified_devices, num_devices_specified,
|
||||
select_mode, maxshowdevs, 0);
|
||||
if (retval == -1)
|
||||
err(1, "%s", devstat_errbuf);
|
||||
else if (retval == 1)
|
||||
return(2);
|
||||
}
|
||||
return(1);
|
||||
}
|
@ -60,6 +60,13 @@ extern int verbose;
|
||||
|
||||
struct inpcb;
|
||||
|
||||
extern struct device_selection *dev_select;
|
||||
extern int generation;
|
||||
extern int num_devices;
|
||||
extern int num_selected;
|
||||
extern int num_selections;
|
||||
extern int select_generation;
|
||||
|
||||
int checkhost __P((struct inpcb *));
|
||||
int checkport __P((struct inpcb *));
|
||||
void closeiostat __P((WINDOW *));
|
||||
|
@ -1,3 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 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$
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 1980, 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
@ -36,28 +65,19 @@ static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93";
|
||||
#endif not lint
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/dkstat.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/dkstat.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <nlist.h>
|
||||
#include <paths.h>
|
||||
#include <devstat.h>
|
||||
#include "systat.h"
|
||||
#include "extern.h"
|
||||
|
||||
static struct nlist namelist[] = {
|
||||
#define X_DK_BUSY 0
|
||||
{ "_dk_busy" },
|
||||
#define X_DK_TIME 1
|
||||
{ "_dk_time" },
|
||||
#define X_DK_XFER 2
|
||||
{ "_dk_xfer" },
|
||||
#define X_DK_WDS 3
|
||||
{ "_dk_wds" },
|
||||
#define X_DK_SEEK 4
|
||||
{ "_dk_seek" },
|
||||
#define X_CP_TIME 5
|
||||
#define X_CP_TIME 0
|
||||
{ "_cp_time" },
|
||||
#ifdef vax
|
||||
#define X_MBDINIT (X_CP_TIME+1)
|
||||
@ -72,27 +92,20 @@ static struct nlist namelist[] = {
|
||||
{ "" },
|
||||
};
|
||||
|
||||
static struct {
|
||||
int dk_busy;
|
||||
long cp_time[CPUSTATES];
|
||||
long *dk_time;
|
||||
long *dk_wds;
|
||||
long *dk_seek;
|
||||
long *dk_xfer;
|
||||
} s, s1;
|
||||
struct statinfo cur, last;
|
||||
|
||||
static int linesperregion;
|
||||
static double etime;
|
||||
static int numbers = 0; /* default display bar graphs */
|
||||
static int msps = 0; /* default ms/seek shown */
|
||||
static int kbpt = 0; /* default ms/seek shown */
|
||||
|
||||
static int barlabels __P((int));
|
||||
static void histogram __P((double, int, double));
|
||||
static void histogram __P((long double, int, double));
|
||||
static int numlabels __P((int));
|
||||
static int devstats __P((int, int, int));
|
||||
static int stats __P((int, int, int));
|
||||
static void stat1 __P((int, int));
|
||||
|
||||
|
||||
WINDOW *
|
||||
openiostat()
|
||||
{
|
||||
@ -113,42 +126,61 @@ closeiostat(w)
|
||||
int
|
||||
initiostat()
|
||||
{
|
||||
if (namelist[X_DK_BUSY].n_type == 0) {
|
||||
if (kvm_nlist(kd, namelist)) {
|
||||
nlisterr(namelist);
|
||||
return(0);
|
||||
}
|
||||
if (namelist[X_DK_BUSY].n_type == 0) {
|
||||
error("Disk init information isn't in namelist");
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if (! dkinit())
|
||||
if (num_devices = getnumdevs() < 0)
|
||||
return(0);
|
||||
|
||||
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));
|
||||
|
||||
/*
|
||||
* This value for maxshowdevs (100) is bogus. I'm not sure exactly
|
||||
* how to calculate it, though.
|
||||
*/
|
||||
if (dsinit(100, &cur, &last, NULL) != 1)
|
||||
return(0);
|
||||
|
||||
if (kvm_nlist(kd, namelist)) {
|
||||
nlisterr(namelist);
|
||||
return(0);
|
||||
if (dk_ndrive) {
|
||||
#define allocate(e, t) \
|
||||
s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
|
||||
s1./**/e = (t *)calloc(dk_ndrive, sizeof (t));
|
||||
allocate(dk_time, long);
|
||||
allocate(dk_wds, long);
|
||||
allocate(dk_seek, long);
|
||||
allocate(dk_xfer, long);
|
||||
#undef allocate
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
void
|
||||
fetchiostat()
|
||||
{
|
||||
if (namelist[X_DK_BUSY].n_type == 0)
|
||||
return;
|
||||
NREAD(X_DK_BUSY, &s.dk_busy, sizeof(s.dk_busy));
|
||||
NREAD(X_DK_TIME, s.dk_time, dk_ndrive * LONG);
|
||||
NREAD(X_DK_XFER, s.dk_xfer, dk_ndrive * LONG);
|
||||
NREAD(X_DK_WDS, s.dk_wds, dk_ndrive * LONG);
|
||||
NREAD(X_DK_SEEK, s.dk_seek, dk_ndrive * LONG);
|
||||
NREAD(X_CP_TIME, s.cp_time, sizeof s.cp_time);
|
||||
struct devinfo *tmp_dinfo;
|
||||
|
||||
NREAD(X_CP_TIME, 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:
|
||||
cmdiostat("refresh", NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
num_devices = cur.dinfo->numdevs;
|
||||
generation = cur.dinfo->generation;
|
||||
|
||||
}
|
||||
|
||||
#define INSET 10
|
||||
@ -158,10 +190,6 @@ labeliostat()
|
||||
{
|
||||
int row;
|
||||
|
||||
if (namelist[X_DK_BUSY].n_type == 0) {
|
||||
error("No dk_busy defined.");
|
||||
return;
|
||||
}
|
||||
row = 0;
|
||||
wmove(wnd, row, 0); wclrtobot(wnd);
|
||||
mvwaddstr(wnd, row++, INSET,
|
||||
@ -182,11 +210,12 @@ numlabels(row)
|
||||
int row;
|
||||
{
|
||||
int i, col, regions, ndrives;
|
||||
char tmpstr[10];
|
||||
|
||||
#define COLWIDTH 14
|
||||
#define COLWIDTH 17
|
||||
#define DRIVESPERLINE ((wnd->maxx - INSET) / COLWIDTH)
|
||||
for (ndrives = 0, i = 0; i < dk_ndrive; i++)
|
||||
if (dk_select[i])
|
||||
for (ndrives = 0, i = 0; i < num_devices; i++)
|
||||
if (dev_select[i].selected)
|
||||
ndrives++;
|
||||
regions = howmany(ndrives, DRIVESPERLINE);
|
||||
/*
|
||||
@ -200,15 +229,17 @@ numlabels(row)
|
||||
if (linesperregion < 3)
|
||||
linesperregion = 3;
|
||||
col = INSET;
|
||||
for (i = 0; i < dk_ndrive; i++)
|
||||
if (dk_select[i] && dk_mspw[i] != 0.0) {
|
||||
for (i = 0; i < num_devices; i++)
|
||||
if (dev_select[i].selected) {
|
||||
if (col + COLWIDTH >= wnd->maxx - INSET) {
|
||||
col = INSET, row += linesperregion + 1;
|
||||
if (row > wnd->maxy - (linesperregion + 1))
|
||||
break;
|
||||
}
|
||||
mvwaddstr(wnd, row, col + 4, dr_name[i]);
|
||||
mvwaddstr(wnd, row + 1, col, "bps tps msps");
|
||||
sprintf(tmpstr, "%s%d", dev_select[i].device_name,
|
||||
dev_select[i].unit_number);
|
||||
mvwaddstr(wnd, row, col + 4, tmpstr);
|
||||
mvwaddstr(wnd, row + 1, col, " KB/t tps MB/s ");
|
||||
col += COLWIDTH;
|
||||
}
|
||||
if (col)
|
||||
@ -221,18 +252,22 @@ barlabels(row)
|
||||
int row;
|
||||
{
|
||||
int i;
|
||||
char tmpstr[10];
|
||||
|
||||
mvwaddstr(wnd, row++, INSET,
|
||||
"/0 /5 /10 /15 /20 /25 /30 /35 /40 /45 /50");
|
||||
linesperregion = 2 + msps;
|
||||
for (i = 0; i < dk_ndrive; i++)
|
||||
if (dk_select[i] && dk_mspw[i] != 0.0) {
|
||||
linesperregion = 2 + kbpt;
|
||||
for (i = 0; i < num_devices; i++)
|
||||
if (dev_select[i].selected) {
|
||||
if (row > wnd->maxy - linesperregion)
|
||||
break;
|
||||
mvwprintw(wnd, row++, 0, "%-4.4s bps|", dr_name[i]);
|
||||
sprintf(tmpstr, "%s%d", dev_select[i].device_name,
|
||||
dev_select[i].unit_number);
|
||||
mvwprintw(wnd, row++, 0, "%-5.5s MB/s|",
|
||||
tmpstr);
|
||||
mvwaddstr(wnd, row++, 0, " tps|");
|
||||
if (msps)
|
||||
mvwaddstr(wnd, row++, 0, " msps|");
|
||||
if (kbpt)
|
||||
mvwaddstr(wnd, row++, 0, " KB/t|");
|
||||
}
|
||||
return (row);
|
||||
}
|
||||
@ -244,16 +279,11 @@ showiostat()
|
||||
register long t;
|
||||
register int i, row, col;
|
||||
|
||||
if (namelist[X_DK_BUSY].n_type == 0)
|
||||
return;
|
||||
for (i = 0; i < dk_ndrive; i++) {
|
||||
#define X(fld) t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t
|
||||
X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time);
|
||||
}
|
||||
#define X(fld) t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t
|
||||
etime = 0;
|
||||
for(i = 0; i < CPUSTATES; i++) {
|
||||
X(cp_time);
|
||||
etime += s.cp_time[i];
|
||||
etime += cur.cp_time[i];
|
||||
}
|
||||
if (etime == 0.0)
|
||||
etime = 1.0;
|
||||
@ -263,11 +293,11 @@ showiostat()
|
||||
stat1(row++, i);
|
||||
if (!numbers) {
|
||||
row += 2;
|
||||
for (i = 0; i < dk_ndrive; i++)
|
||||
if (dk_select[i] && dk_mspw[i] != 0.0) {
|
||||
for (i = 0; i < num_devices; i++)
|
||||
if (dev_select[i].selected) {
|
||||
if (row > wnd->maxy - linesperregion)
|
||||
break;
|
||||
row = stats(row, INSET, i);
|
||||
row = devstats(row, INSET, i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -276,8 +306,8 @@ showiostat()
|
||||
wdeleteln(wnd);
|
||||
wmove(wnd, row + 3, 0);
|
||||
winsertln(wnd);
|
||||
for (i = 0; i < dk_ndrive; i++)
|
||||
if (dk_select[i] && dk_mspw[i] != 0.0) {
|
||||
for (i = 0; i < num_devices; i++)
|
||||
if (dev_select[i].selected) {
|
||||
if (col + COLWIDTH >= wnd->maxx - INSET) {
|
||||
col = INSET, row += linesperregion + 1;
|
||||
if (row > wnd->maxy - (linesperregion + 1))
|
||||
@ -287,42 +317,47 @@ showiostat()
|
||||
wmove(wnd, row + 3, 0);
|
||||
winsertln(wnd);
|
||||
}
|
||||
(void) stats(row + 3, col, i);
|
||||
(void) devstats(row + 3, col, i);
|
||||
col += COLWIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
stats(row, col, dn)
|
||||
devstats(row, col, dn)
|
||||
int row, col, dn;
|
||||
{
|
||||
double atime, words, xtime, itime;
|
||||
long double transfers_per_second;
|
||||
long double kb_per_transfer, mb_per_second;
|
||||
long double busy_seconds;
|
||||
int di;
|
||||
|
||||
di = dev_select[dn].position;
|
||||
|
||||
busy_seconds = compute_etime(cur.busy_time, last.busy_time);
|
||||
|
||||
if (compute_stats(&cur.dinfo->devices[di], &last.dinfo->devices[di],
|
||||
busy_seconds, NULL, NULL, NULL,
|
||||
&kb_per_transfer, &transfers_per_second,
|
||||
&mb_per_second, NULL, NULL) != 0)
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
|
||||
atime = s.dk_time[dn];
|
||||
atime /= hertz;
|
||||
words = s.dk_wds[dn]*32.0; /* number of words transferred */
|
||||
xtime = dk_mspw[dn]*words; /* transfer time */
|
||||
itime = atime - xtime; /* time not transferring */
|
||||
if (xtime < 0)
|
||||
itime += xtime, xtime = 0;
|
||||
if (itime < 0)
|
||||
xtime += itime, itime = 0;
|
||||
if (numbers) {
|
||||
mvwprintw(wnd, row, col, "%3.0f%4.0f%5.1f",
|
||||
words / 512 / etime, s.dk_xfer[dn] / etime,
|
||||
s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0.0);
|
||||
return (row);
|
||||
mvwprintw(wnd, row, col, " %5.2Lf %3.0Lf %5.2Lf ",
|
||||
kb_per_transfer, transfers_per_second,
|
||||
mb_per_second);
|
||||
return(row);
|
||||
}
|
||||
wmove(wnd, row++, col);
|
||||
histogram(words / 512 / etime, 50, 1.0);
|
||||
histogram(mb_per_second, 50, 1.0);
|
||||
wmove(wnd, row++, col);
|
||||
histogram(s.dk_xfer[dn] / etime, 50, 1.0);
|
||||
if (msps) {
|
||||
histogram(transfers_per_second, 50, 1.0);
|
||||
if (kbpt) {
|
||||
wmove(wnd, row++, col);
|
||||
histogram(s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0,
|
||||
50, 1.0);
|
||||
histogram(kb_per_transfer, 50, 1.0);
|
||||
}
|
||||
return (row);
|
||||
|
||||
return(row);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -334,17 +369,17 @@ stat1(row, o)
|
||||
|
||||
time = 0;
|
||||
for (i = 0; i < CPUSTATES; i++)
|
||||
time += s.cp_time[i];
|
||||
time += cur.cp_time[i];
|
||||
if (time == 0.0)
|
||||
time = 1.0;
|
||||
wmove(wnd, row, INSET);
|
||||
#define CPUSCALE 0.5
|
||||
histogram(100.0 * s.cp_time[o] / time, 50, CPUSCALE);
|
||||
histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE);
|
||||
}
|
||||
|
||||
static void
|
||||
histogram(val, colwidth, scale)
|
||||
double val;
|
||||
long double val;
|
||||
int colwidth;
|
||||
double scale;
|
||||
{
|
||||
@ -354,7 +389,7 @@ histogram(val, colwidth, scale)
|
||||
|
||||
k = MIN(v, colwidth);
|
||||
if (v > colwidth) {
|
||||
snprintf(buf, sizeof(buf), "%4.1f", val);
|
||||
snprintf(buf, sizeof(buf), "%5.2Lf", val);
|
||||
k -= strlen(buf);
|
||||
while (k--)
|
||||
waddch(wnd, 'X');
|
||||
@ -371,13 +406,13 @@ cmdiostat(cmd, args)
|
||||
char *cmd, *args;
|
||||
{
|
||||
|
||||
if (prefix(cmd, "msps"))
|
||||
msps = !msps;
|
||||
if (prefix(cmd, "kbpt"))
|
||||
kbpt = !kbpt;
|
||||
else if (prefix(cmd, "numbers"))
|
||||
numbers = 1;
|
||||
else if (prefix(cmd, "bars"))
|
||||
numbers = 0;
|
||||
else if (!dkcmd(cmd, args))
|
||||
else if (!dscmd(cmd, args, 100, &cur))
|
||||
return (0);
|
||||
wclear(wnd);
|
||||
labeliostat();
|
||||
|
@ -217,10 +217,10 @@ bar graphs of the amount of time executing in user mode (``user''),
|
||||
in user mode running low priority processes (``nice''), in
|
||||
system mode (``system''), in interrupt mode (``interrupt''),
|
||||
and idle (``idle''). Statistics
|
||||
on disk throughput show, for each drive, kilobytes of data transferred,
|
||||
number of disk transactions performed, and average seek time
|
||||
(in milliseconds). This information may be displayed as
|
||||
bar graphs or as rows of numbers which scroll downward. Bar
|
||||
on disk throughput show, for each drive, megabytes per second,
|
||||
average number of disk transactions per second, and
|
||||
average kilobytes of data per transaction. This information may be
|
||||
displayed as bar graphs or as rows of numbers which scroll downward. Bar
|
||||
graphs are shown by default.
|
||||
.Pp
|
||||
The following commands are specific to the
|
||||
@ -237,9 +237,9 @@ displayed in numeric columns which scroll downward.
|
||||
Show the disk
|
||||
.Tn I/O
|
||||
statistics in bar graph form (default).
|
||||
.It Cm msps
|
||||
Toggle the display of average seek time (the default is to
|
||||
not display seek times).
|
||||
.It Cm kbpt
|
||||
Toggle the display of kilobytes per transaction. (the default is to
|
||||
not display kilobytes per transaction).
|
||||
.El
|
||||
.It Ic swap
|
||||
Show information about swap space usage on all the
|
||||
@ -452,6 +452,32 @@ drives may be specified, separated by spaces.
|
||||
.It Cm display Op Ar drives
|
||||
Display information about the drives indicated. Multiple drives
|
||||
may be specified, separated by spaces.
|
||||
.It Cm only Op Ar drives
|
||||
Display only the specified drives. Multiple drives may be specified,
|
||||
separated by spaces.
|
||||
.It Cm drives
|
||||
Display a list of available devices.
|
||||
.It Cm match Ar type,if,pass Op Ar | ...
|
||||
Display devivces matching the given pattern. The basic matching
|
||||
expressions are the same as those used in
|
||||
.Xr iostat 8
|
||||
with one difference. Instead of specifying multiple
|
||||
.Fl t
|
||||
arguments which are then ORed together, the user instead specifys multiple
|
||||
matching expressions joined by the pipe ( | ) character. The comma
|
||||
separated arguments within each matching expression are ANDed together, and
|
||||
then the pipe separated matching expressions are ORed together. Any
|
||||
device matching the combined expression will be displayed, if there is room
|
||||
to display it. For example:
|
||||
.Pp
|
||||
.Dl match da,scsi | cd,ide
|
||||
.Pp
|
||||
This will display all SCSI Direct Access devices and all IDE CDROM devices.
|
||||
.Pp
|
||||
.Dl match da | sa | cd,pass
|
||||
.Pp
|
||||
This will display all Direct Access devices, all Sequential Access devices,
|
||||
and all passthrough devices that provide access to CDROM drives.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr iostat 1 ,
|
||||
|
@ -36,7 +36,7 @@
|
||||
static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 1/12/94";
|
||||
#endif
|
||||
static const char rcsid[] =
|
||||
"$Id: vmstat.c,v 1.25 1998/06/09 04:17:29 imp Exp $";
|
||||
"$Id: vmstat.c,v 1.26 1998/07/06 22:08:00 bde Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
@ -44,7 +44,6 @@ static const char rcsid[] =
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/dkstat.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
@ -52,6 +51,7 @@ static const char rcsid[] =
|
||||
#include <sys/uio.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/dkstat.h>
|
||||
#include <sys/vmmeter.h>
|
||||
|
||||
#include <vm/vm_param.h>
|
||||
@ -66,6 +66,7 @@ static const char rcsid[] =
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
#include <devstat.h>
|
||||
#include "systat.h"
|
||||
#include "extern.h"
|
||||
|
||||
@ -73,11 +74,6 @@ static struct Info {
|
||||
long time[CPUSTATES];
|
||||
struct vmmeter Cnt;
|
||||
struct vmtotal Total;
|
||||
long *dk_time;
|
||||
long *dk_wds;
|
||||
long *dk_seek;
|
||||
long *dk_xfer;
|
||||
int dk_busy;
|
||||
struct nchstats nchstats;
|
||||
long nchcount;
|
||||
long *intrcnt;
|
||||
@ -87,6 +83,8 @@ static struct Info {
|
||||
long freevnodes;
|
||||
} s, s1, s2, z;
|
||||
|
||||
struct statinfo cur, last, run;
|
||||
|
||||
#define cnt s.Cnt
|
||||
#define oldcnt s1.Cnt
|
||||
#define total s.Total
|
||||
@ -98,10 +96,11 @@ static enum state { BOOT, TIME, RUN } state = TIME;
|
||||
static void allocinfo __P((struct Info *));
|
||||
static void copyinfo __P((struct Info *, struct Info *));
|
||||
static float cputime __P((int));
|
||||
static void dinfo __P((int, int));
|
||||
static void dinfo __P((int, int, struct statinfo *, struct statinfo *));
|
||||
static void getinfo __P((struct Info *, enum state));
|
||||
static void putint __P((int, int, int, int));
|
||||
static void putfloat __P((double, int, int, int, int, int));
|
||||
static void putlongdouble __P((long double, int, int, int, int, int));
|
||||
static int ucount __P((void));
|
||||
|
||||
static int ncpu;
|
||||
@ -147,31 +146,21 @@ static struct nlist namelist[] = {
|
||||
{ "_cnt" },
|
||||
#define X_BUFFERSPACE 2
|
||||
{ "_bufspace" },
|
||||
#define X_DK_BUSY 3
|
||||
{ "_dk_busy" },
|
||||
#define X_DK_TIME 4
|
||||
{ "_dk_time" },
|
||||
#define X_DK_XFER 5
|
||||
{ "_dk_xfer" },
|
||||
#define X_DK_WDS 6
|
||||
{ "_dk_wds" },
|
||||
#define X_DK_SEEK 7
|
||||
{ "_dk_seek" },
|
||||
#define X_NCHSTATS 8
|
||||
#define X_NCHSTATS 3
|
||||
{ "_nchstats" },
|
||||
#define X_INTRNAMES 9
|
||||
#define X_INTRNAMES 4
|
||||
{ "_intrnames" },
|
||||
#define X_EINTRNAMES 10
|
||||
#define X_EINTRNAMES 5
|
||||
{ "_eintrnames" },
|
||||
#define X_INTRCNT 11
|
||||
#define X_INTRCNT 6
|
||||
{ "_intrcnt" },
|
||||
#define X_EINTRCNT 12
|
||||
#define X_EINTRCNT 7
|
||||
{ "_eintrcnt" },
|
||||
#define X_DESIREDVNODES 13
|
||||
#define X_DESIREDVNODES 8
|
||||
{ "_desiredvnodes" },
|
||||
#define X_NUMVNODES 14
|
||||
#define X_NUMVNODES 9
|
||||
{ "_numvnodes" },
|
||||
#define X_FREEVNODES 15
|
||||
#define X_FREEVNODES 10
|
||||
{ "_freevnodes" },
|
||||
{ "" },
|
||||
};
|
||||
@ -200,13 +189,9 @@ static struct nlist namelist[] = {
|
||||
#define DISKROW 18 /* uses 5 rows and 50 cols (for 9 drives) */
|
||||
#define DISKCOL 0
|
||||
|
||||
#define DRIVESPACE 9 /* max # for space */
|
||||
#define DRIVESPACE 7 /* max # for space */
|
||||
|
||||
#if DK_NDRIVE > DRIVESPACE
|
||||
#define MAXDRIVES DRIVESPACE /* max # to display */
|
||||
#else
|
||||
#define MAXDRIVES DK_NDRIVE /* max # to display */
|
||||
#endif
|
||||
|
||||
int
|
||||
initkre()
|
||||
@ -225,21 +210,22 @@ initkre()
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if (! dkinit())
|
||||
|
||||
if (num_devices = getnumdevs() < 0) {
|
||||
warnx("%s", devstat_errbuf);
|
||||
return(0);
|
||||
if (dk_ndrive && !once) {
|
||||
#define allocate(e, t) \
|
||||
s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
|
||||
s1./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
|
||||
s2./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
|
||||
z./**/e = (t *)calloc(dk_ndrive, sizeof (t));
|
||||
allocate(dk_time, long);
|
||||
allocate(dk_wds, long);
|
||||
allocate(dk_seek, long);
|
||||
allocate(dk_xfer, long);
|
||||
once = 1;
|
||||
#undef allocate
|
||||
}
|
||||
|
||||
cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
|
||||
last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
|
||||
run.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
|
||||
bzero(cur.dinfo, sizeof(struct devinfo));
|
||||
bzero(last.dinfo, sizeof(struct devinfo));
|
||||
bzero(run.dinfo, sizeof(struct devinfo));
|
||||
|
||||
if (dsinit(MAXDRIVES, &cur, &last, &run) != 1)
|
||||
return(0);
|
||||
|
||||
if (nintr == 0) {
|
||||
nintr = (namelist[X_EINTRCNT].n_value -
|
||||
namelist[X_INTRCNT].n_value) / sizeof (long);
|
||||
@ -341,15 +327,23 @@ labelkre()
|
||||
mvprintw(NAMEIROW + 1, NAMEICOL,
|
||||
" Calls hits %% hits %%");
|
||||
mvprintw(DISKROW, DISKCOL, "Discs");
|
||||
mvprintw(DISKROW + 1, DISKCOL, "seeks");
|
||||
mvprintw(DISKROW + 2, DISKCOL, "xfers");
|
||||
mvprintw(DISKROW + 3, DISKCOL, " blks");
|
||||
mvprintw(DISKROW + 4, DISKCOL, " msps");
|
||||
mvprintw(DISKROW + 1, DISKCOL, "KB/t");
|
||||
mvprintw(DISKROW + 2, DISKCOL, "tps");
|
||||
mvprintw(DISKROW + 3, DISKCOL, "MB/s");
|
||||
/*
|
||||
* For now, we don't support a fourth disk statistic. So there's
|
||||
* no point in providing a label for it. If someone can think of a
|
||||
* fourth useful disk statistic, there is room to add it.
|
||||
*/
|
||||
/* mvprintw(DISKROW + 4, DISKCOL, " msps"); */
|
||||
j = 0;
|
||||
for (i = 0; i < dk_ndrive && j < MAXDRIVES; i++)
|
||||
if (dk_select[i]) {
|
||||
mvprintw(DISKROW, DISKCOL + 5 + 5 * j,
|
||||
" %4.4s", dr_name[j]);
|
||||
for (i = 0; i < num_devices && j < MAXDRIVES; i++)
|
||||
if (dev_select[i].selected) {
|
||||
char tmpstr[80];
|
||||
sprintf(tmpstr, "%s%d", dev_select[i].device_name,
|
||||
dev_select[i].unit_number);
|
||||
mvprintw(DISKROW, DISKCOL + 5 + 6 * j,
|
||||
" %5.5s", tmpstr);
|
||||
j++;
|
||||
}
|
||||
for (i = 0; i < nintr; i++) {
|
||||
@ -360,6 +354,7 @@ labelkre()
|
||||
}
|
||||
|
||||
#define X(fld) {t=s.fld[i]; s.fld[i]-=s1.fld[i]; if(state==TIME) s1.fld[i]=t;}
|
||||
#define Q(fld) {t=cur.fld[i]; cur.fld[i]-=last.fld[i]; if(state==TIME) last.fld[i]=t;}
|
||||
#define Y(fld) {t = s.fld; s.fld -= s1.fld; if(state == TIME) s1.fld = t;}
|
||||
#define Z(fld) {t = s.nchstats.fld; s.nchstats.fld -= s1.nchstats.fld; \
|
||||
if(state == TIME) s1.nchstats.fld = t;}
|
||||
@ -380,12 +375,10 @@ showkre()
|
||||
int i, l, c;
|
||||
static int failcnt = 0;
|
||||
|
||||
for (i = 0; i < dk_ndrive; i++) {
|
||||
X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time);
|
||||
}
|
||||
etime = 0;
|
||||
for(i = 0; i < CPUSTATES; i++) {
|
||||
X(time);
|
||||
Q(cp_time);
|
||||
etime += s.time[i];
|
||||
}
|
||||
if (etime < 5.0) { /* < 5 ticks - ignore this trash */
|
||||
@ -496,11 +489,24 @@ showkre()
|
||||
PUTRATE(Cnt.v_soft, GENSTATROW + 1, GENSTATCOL + 20, 5);
|
||||
PUTRATE(Cnt.v_vm_faults, GENSTATROW + 1, GENSTATCOL + 25, 5);
|
||||
mvprintw(DISKROW, DISKCOL + 5, " ");
|
||||
for (i = 0, c = 0; i < dk_ndrive && c < MAXDRIVES; i++)
|
||||
if (dk_select[i]) {
|
||||
mvprintw(DISKROW, DISKCOL + 5 + 5 * c,
|
||||
" %4.4s", dr_name[i]);
|
||||
dinfo(i, ++c);
|
||||
for (i = 0, c = 0; i < num_devices && c < MAXDRIVES; i++)
|
||||
if (dev_select[i].selected) {
|
||||
char tmpstr[80];
|
||||
sprintf(tmpstr, "%s%d", dev_select[i].device_name,
|
||||
dev_select[i].unit_number);
|
||||
mvprintw(DISKROW, DISKCOL + 5 + 6 * c,
|
||||
" %5.5s", tmpstr);
|
||||
switch(state) {
|
||||
case TIME:
|
||||
dinfo(i, ++c, &cur, &last);
|
||||
break;
|
||||
case RUN:
|
||||
dinfo(i, ++c, &cur, &run);
|
||||
break;
|
||||
case BOOT:
|
||||
dinfo(i, ++c, &cur, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
putint(s.nchcount, NAMEIROW + 2, NAMEICOL, 9);
|
||||
putint((nchtotal.ncs_goodhits + nchtotal.ncs_neghits),
|
||||
@ -519,11 +525,27 @@ int
|
||||
cmdkre(cmd, args)
|
||||
char *cmd, *args;
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (prefix(cmd, "run")) {
|
||||
retval = 1;
|
||||
copyinfo(&s2, &s1);
|
||||
switch (getdevs(&run)) {
|
||||
case -1:
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
break;
|
||||
case 1:
|
||||
num_devices = run.dinfo->numdevs;
|
||||
generation = run.dinfo->generation;
|
||||
retval = dscmd("refresh", NULL, MAXDRIVES, &cur);
|
||||
if (retval == 2)
|
||||
labelkre();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
state = RUN;
|
||||
return (1);
|
||||
return (retval);
|
||||
}
|
||||
if (prefix(cmd, "boot")) {
|
||||
state = BOOT;
|
||||
@ -535,11 +557,32 @@ cmdkre(cmd, args)
|
||||
return (1);
|
||||
}
|
||||
if (prefix(cmd, "zero")) {
|
||||
if (state == RUN)
|
||||
retval = 1;
|
||||
if (state == RUN) {
|
||||
getinfo(&s1, RUN);
|
||||
return (1);
|
||||
switch (getdevs(&run)) {
|
||||
case -1:
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
break;
|
||||
case 1:
|
||||
num_devices = run.dinfo->numdevs;
|
||||
generation = run.dinfo->generation;
|
||||
retval = dscmd("refresh",NULL, MAXDRIVES, &cur);
|
||||
if (retval == 2)
|
||||
labelkre();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (retval);
|
||||
}
|
||||
return (dkcmd(cmd, args));
|
||||
retval = dscmd(cmd, args, MAXDRIVES, &cur);
|
||||
|
||||
if (retval == 2)
|
||||
labelkre();
|
||||
|
||||
return(retval);
|
||||
}
|
||||
|
||||
/* calculate number of users on the system */
|
||||
@ -616,25 +659,44 @@ putfloat(f, l, c, w, d, nz)
|
||||
addstr(b);
|
||||
}
|
||||
|
||||
static void
|
||||
putlongdouble(f, l, c, w, d, nz)
|
||||
long double f;
|
||||
int l, c, w, d, nz;
|
||||
{
|
||||
char b[128];
|
||||
|
||||
move(l, c);
|
||||
if (nz && f == 0.0) {
|
||||
while (--w >= 0)
|
||||
addch(' ');
|
||||
return;
|
||||
}
|
||||
sprintf(b, "%*.*Lf", w, d, f);
|
||||
if (strlen(b) > w) {
|
||||
while (--w >= 0)
|
||||
addch('*');
|
||||
return;
|
||||
}
|
||||
addstr(b);
|
||||
}
|
||||
|
||||
static void
|
||||
getinfo(s, st)
|
||||
struct Info *s;
|
||||
enum state st;
|
||||
{
|
||||
struct devinfo *tmp_dinfo;
|
||||
int mib[2], size;
|
||||
extern int errno;
|
||||
|
||||
NREAD(X_CPTIME, s->time, sizeof s->time);
|
||||
NREAD(X_CPTIME, cur.cp_time, sizeof(cur.cp_time));
|
||||
NREAD(X_CNT, &s->Cnt, sizeof s->Cnt);
|
||||
NREAD(X_BUFFERSPACE, &s->bufspace, sizeof(s->bufspace));
|
||||
NREAD(X_DESIREDVNODES, &s->desiredvnodes, sizeof(s->desiredvnodes));
|
||||
NREAD(X_NUMVNODES, &s->numvnodes, LONG);
|
||||
NREAD(X_FREEVNODES, &s->freevnodes, LONG);
|
||||
NREAD(X_DK_BUSY, &s->dk_busy, sizeof(s->dk_busy));
|
||||
NREAD(X_DK_TIME, s->dk_time, dk_ndrive * LONG);
|
||||
NREAD(X_DK_XFER, s->dk_xfer, dk_ndrive * LONG);
|
||||
NREAD(X_DK_WDS, s->dk_wds, dk_ndrive * LONG);
|
||||
NREAD(X_DK_SEEK, s->dk_seek, dk_ndrive * LONG);
|
||||
NREAD(X_NCHSTATS, &s->nchstats, sizeof s->nchstats);
|
||||
NREAD(X_INTRCNT, s->intrcnt, nintr * LONG);
|
||||
size = sizeof(s->Total);
|
||||
@ -647,6 +709,24 @@ getinfo(s, st)
|
||||
size = sizeof(ncpu);
|
||||
if (sysctlbyname("hw.ncpu", &ncpu, &size, NULL, 0) < 0)
|
||||
ncpu = 1;
|
||||
|
||||
tmp_dinfo = last.dinfo;
|
||||
last.dinfo = cur.dinfo;
|
||||
cur.dinfo = tmp_dinfo;
|
||||
|
||||
last.busy_time = cur.busy_time;
|
||||
switch (getdevs(&cur)) {
|
||||
case -1:
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
break;
|
||||
case 1:
|
||||
num_devices = cur.dinfo->numdevs;
|
||||
generation = cur.dinfo->generation;
|
||||
cmdkre("refresh", NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -663,45 +743,45 @@ static void
|
||||
copyinfo(from, to)
|
||||
register struct Info *from, *to;
|
||||
{
|
||||
long *time, *wds, *seek, *xfer;
|
||||
long *intrcnt;
|
||||
struct devinfo tmp_dinfo;
|
||||
|
||||
/*
|
||||
* time, wds, seek, and xfer are malloc'd so we have to
|
||||
* save the pointers before the structure copy and then
|
||||
* copy by hand.
|
||||
*/
|
||||
time = to->dk_time; wds = to->dk_wds; seek = to->dk_seek;
|
||||
xfer = to->dk_xfer; intrcnt = to->intrcnt;
|
||||
intrcnt = to->intrcnt;
|
||||
*to = *from;
|
||||
bcopy(from->dk_time, to->dk_time = time, dk_ndrive * sizeof (long));
|
||||
bcopy(from->dk_wds, to->dk_wds = wds, dk_ndrive * sizeof (long));
|
||||
bcopy(from->dk_seek, to->dk_seek = seek, dk_ndrive * sizeof (long));
|
||||
bcopy(from->dk_xfer, to->dk_xfer = xfer, dk_ndrive * sizeof (long));
|
||||
|
||||
bcopy(from->intrcnt, to->intrcnt = intrcnt, nintr * sizeof (int));
|
||||
}
|
||||
|
||||
static void
|
||||
dinfo(dn, c)
|
||||
dinfo(dn, c, now, then)
|
||||
int dn, c;
|
||||
struct statinfo *now, *then;
|
||||
{
|
||||
double words, atime, itime, xtime;
|
||||
long double transfers_per_second;
|
||||
long double kb_per_transfer, mb_per_second;
|
||||
long double busy_seconds;
|
||||
int di;
|
||||
|
||||
c = DISKCOL + c * 5;
|
||||
atime = s.dk_time[dn];
|
||||
atime /= hertz;
|
||||
words = s.dk_wds[dn]*32.0; /* number of words transferred */
|
||||
xtime = dk_mspw[dn]*words; /* transfer time */
|
||||
itime = atime - xtime; /* time not transferring */
|
||||
if (xtime < 0)
|
||||
itime += xtime, xtime = 0;
|
||||
if (itime < 0)
|
||||
xtime += itime, itime = 0;
|
||||
putint((int)((float)s.dk_seek[dn]/etime+0.5), DISKROW + 1, c, 5);
|
||||
putint((int)((float)s.dk_xfer[dn]/etime+0.5), DISKROW + 2, c, 5);
|
||||
putint((int)(words/etime/512.0 + 0.5), DISKROW + 3, c, 5);
|
||||
if (s.dk_seek[dn])
|
||||
putfloat(itime*1000.0/s.dk_seek[dn], DISKROW + 4, c, 5, 1, 1);
|
||||
else
|
||||
putint(0, DISKROW + 4, c, 5);
|
||||
di = dev_select[dn].position;
|
||||
|
||||
busy_seconds = compute_etime(now->busy_time, then ?
|
||||
then->busy_time :
|
||||
then->dinfo->devices[di].dev_creation_time);
|
||||
|
||||
if (compute_stats(&now->dinfo->devices[di], then ?
|
||||
&then->dinfo->devices[di] : NULL, busy_seconds,
|
||||
NULL, NULL, NULL,
|
||||
&kb_per_transfer, &transfers_per_second,
|
||||
&mb_per_second, NULL, NULL) != 0)
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
|
||||
c = DISKCOL + c * 6;
|
||||
putlongdouble(kb_per_transfer, DISKROW + 1, c, 5, 2, 0);
|
||||
putlongdouble(transfers_per_second, DISKROW + 2, c, 5, 0, 0);
|
||||
putlongdouble(mb_per_second, DISKROW + 3, c, 5, 2, 0);
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,10 +1,11 @@
|
||||
# @(#)Makefile 8.1 (Berkeley) 6/6/93
|
||||
|
||||
PROG= iostat
|
||||
CFLAGS+=-I${.CURDIR}/../../usr.bin/vmstat -I${.CURDIR}/../../sys
|
||||
CFLAGS+=-I${.CURDIR}/../../sys
|
||||
SRCS= iostat.c
|
||||
MAN8= iostat.8
|
||||
DPADD= ${LIBKVM}
|
||||
LDADD= -lkvm
|
||||
DPADD= ${LIBKVM} ${LIBDEVSTAT}
|
||||
LDADD= -lkvm -ldevstat
|
||||
BINGRP= kmem
|
||||
BINMODE=2555
|
||||
|
||||
|
@ -1,3 +1,32 @@
|
||||
.\"
|
||||
.\" Copyright (c) 1997 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$
|
||||
.\"
|
||||
.\" Copyright (c) 1985, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
@ -31,9 +60,9 @@
|
||||
.\"
|
||||
.\" @(#)iostat.8 8.1 (Berkeley) 6/6/93
|
||||
.\"
|
||||
.Dd June 6, 1993
|
||||
.Dd December 22, 1997
|
||||
.Dt IOSTAT 8
|
||||
.Os BSD 4
|
||||
.Os FreeBSD 3.0
|
||||
.Sh NAME
|
||||
.Nm iostat
|
||||
.Nd report
|
||||
@ -41,16 +70,19 @@
|
||||
statistics
|
||||
.Sh SYNOPSIS
|
||||
.Nm iostat
|
||||
.Op Fl CdhIoT?
|
||||
.Op Fl c Ar count
|
||||
.Op Fl M Ar core
|
||||
.Op Fl n Ar devs
|
||||
.Op Fl N Ar system
|
||||
.Op Fl t Ar type,if,pass
|
||||
.Op Fl w Ar wait
|
||||
.Op Ar drives
|
||||
.Sh DESCRIPTION
|
||||
.Nm Iostat
|
||||
displays kernel
|
||||
.Tn I/O
|
||||
statistics on terminal, disk and cpu
|
||||
statistics on terminal, device and cpu
|
||||
operations.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
@ -58,19 +90,123 @@ The options are as follows:
|
||||
.It Fl c
|
||||
Repeat the display
|
||||
.Ar count
|
||||
times.
|
||||
The first display is for the time since a reboot and each subsequent
|
||||
report is for the time period since the last display.
|
||||
If no
|
||||
times. If no
|
||||
.Ar wait
|
||||
interval is specified, the default is 1 second.
|
||||
.It Fl C
|
||||
Display CPU statistics. This is on by default, unless
|
||||
.Fl d
|
||||
is specified.
|
||||
.It Fl d
|
||||
Display only device statistics. If this flag is turned on, only device
|
||||
statistics will be displayed, unless
|
||||
.Fl C
|
||||
or
|
||||
.Fl T
|
||||
is also specfied to enable the display of CPU or TTY statistics.
|
||||
.It Fl h
|
||||
Put iostat in
|
||||
.Sq top
|
||||
mode. In this mode, iostat will show devices in order from highest to
|
||||
lowest bytes per measurement cycle.
|
||||
.It Fl I
|
||||
Display total statstics for a given time period, rather than average
|
||||
statistics for each second during that time period.
|
||||
.It Fl M
|
||||
Extract values associated with the name list from the specified core
|
||||
instead of the default
|
||||
.Dq Pa /dev/kmem .
|
||||
.It Fl n
|
||||
Display up to
|
||||
.Ar devs
|
||||
number of devices.
|
||||
.Nm iostat
|
||||
will display fewer devices if there aren't
|
||||
.Ar devs
|
||||
devices present.
|
||||
.It Fl N
|
||||
Extract the name list from the specified system instead of the default
|
||||
.Dq Pa /kernel .
|
||||
.It Fl o
|
||||
Display old-style
|
||||
.Nm iostat
|
||||
device statistics. Sectors per second, transfers per second, and miliseconds
|
||||
per seek are displayed. If
|
||||
.Fl I
|
||||
is specified, total blocks/sectors, total transfers, and
|
||||
miliseconds per seek are displayed.
|
||||
.It Fl t
|
||||
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 t
|
||||
arguments may be specified on the command line. All
|
||||
.Fl t
|
||||
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 t
|
||||
argument will be included in the
|
||||
.Nm iostat
|
||||
output, up to the number of devices that can be displayed in
|
||||
80 columns, or the maximum number of devices specified by the user.
|
||||
.It Fl T
|
||||
Display TTY statistics. This is on by default, unless
|
||||
.Fl d
|
||||
is specified.
|
||||
.It Fl w
|
||||
Pause
|
||||
.Ar wait
|
||||
@ -78,6 +214,8 @@ seconds between each display.
|
||||
If no repeat
|
||||
.Ar count
|
||||
is specified, the default is infinity.
|
||||
.It Fl ?
|
||||
Display a usage statement and exit.
|
||||
.El
|
||||
.Pp
|
||||
.Nm Iostat
|
||||
@ -90,16 +228,60 @@ characters read from terminals
|
||||
.It tout
|
||||
characters written to terminals
|
||||
.El
|
||||
.It disks
|
||||
Disk operations (this field is system dependent).
|
||||
The header of the field is the disk name and unit number.
|
||||
If more than four disk drives are configured in the system,
|
||||
.It devices
|
||||
Device operations. The header of the field is the device name and unit number.
|
||||
.Nm iostat
|
||||
displays only the first four drives.
|
||||
will display as many devices as will fit in a standard 80 column screen, or
|
||||
the maximum number of devices in the system, whichever is smaller. If
|
||||
.Fl n
|
||||
is specified on the command line, iostat will display the smaller of the
|
||||
requested number of devices, and the maximum number of devices in the system.
|
||||
To force
|
||||
.Nm iostat
|
||||
to display specific drives, their names may be supplied on the command
|
||||
line.
|
||||
.Nm iostat
|
||||
will not display more devices than will fit in an 80 column screen, unless
|
||||
the
|
||||
.Fl n
|
||||
argument is given on the command line to specify a maximum number of
|
||||
devices to display. If fewer devices are specified on the command line
|
||||
than will fit in an 80 column screen, iostat will show only the specified
|
||||
devices.
|
||||
.Pp
|
||||
The standard
|
||||
.Nm iostat
|
||||
device display shows the following statistics:
|
||||
.Pp
|
||||
.Bl -tag -width indent -compact
|
||||
.It KB/t
|
||||
kilobytes per transfer
|
||||
.It tps
|
||||
transfers per second
|
||||
.It MB/s
|
||||
megabytes per second
|
||||
.El
|
||||
.Pp
|
||||
The standard
|
||||
.Nm iostat
|
||||
device display, with the
|
||||
.Fl I
|
||||
flag specified, shows the following statistics:
|
||||
.Pp
|
||||
.Bl -tag -width indent -compact
|
||||
.It KB/t
|
||||
kilobytes per transfer
|
||||
.It xfrs
|
||||
total number of transfers
|
||||
.It MB
|
||||
total number of megabytes transferred
|
||||
.El
|
||||
.Pp
|
||||
The old-style
|
||||
.Nm iostat
|
||||
display (using
|
||||
.Fl o )
|
||||
shows the following statistics:
|
||||
.Pp
|
||||
.Bl -tag -width indent -compact
|
||||
.It sps
|
||||
@ -107,8 +289,22 @@ sectors transferred per second
|
||||
.It tps
|
||||
transfers per second
|
||||
.It msps
|
||||
milliseconds per average seek (including implied
|
||||
seeks and rotational latency)
|
||||
average milliseconds per transaction
|
||||
.El
|
||||
.Pp
|
||||
The old-style
|
||||
.Nm iostat
|
||||
display, with the
|
||||
.Fl I
|
||||
flag specified, shows the following statistics:
|
||||
.Pp
|
||||
.Bl -tag -width indent -compact
|
||||
.It blk
|
||||
total blocks/sectors transferred
|
||||
.It xfr
|
||||
total transfers
|
||||
.It msps
|
||||
average milliseconds per transaction
|
||||
.El
|
||||
.It cpu
|
||||
.Bl -tag -width indent -compact
|
||||
@ -131,6 +327,50 @@ Default kernel namelist.
|
||||
.It Pa /dev/kmem
|
||||
Default memory file.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
.Dl iostat -w 1 da0 da1 cd0
|
||||
.Pp
|
||||
Display statistics for the first two Direct Access devices and the first
|
||||
CDROM device every second ad infinitum.
|
||||
.Pp
|
||||
.Dl iostat -c 2
|
||||
.Pp
|
||||
Display the statistics for the first four devices in the system twice, with
|
||||
a one second display interval.
|
||||
.Pp
|
||||
.Dl iostat -t da -t cd -w 1
|
||||
.Pp
|
||||
Display statistics for all CDROM and Direct Access devices every second
|
||||
ad infinitum.
|
||||
.Pp
|
||||
.Dl iostat -t da,scsi,pass -t cd,scsi,pass
|
||||
.Pp
|
||||
Display statistics once for all SCSI passthrough devices that provide access
|
||||
to either Direct Access or CDROM devices.
|
||||
.Pp
|
||||
.Dl iostat -h -n 8 -w 1
|
||||
.Pp
|
||||
Display up to 8 devices with the most I/O every second ad inifitum.
|
||||
.Pp
|
||||
.Dl iostat -dh -t da -w 1
|
||||
.Pp
|
||||
Omit the TTY and CPU displays, show devices in order of performance and
|
||||
show only Direct Access devices every second ad infinitum.
|
||||
.Pp
|
||||
.Dl iostat -Iw 3
|
||||
.Pp
|
||||
Display total statistics every three seconds ad infinitum.
|
||||
.Pp
|
||||
.Dl iostat -odICTw 2 -c 9
|
||||
.Pp
|
||||
Display total statistics using the old-style output format 9 times, with
|
||||
a two second interval between each measurement/display. The
|
||||
.Fl d
|
||||
flag generally disables the TTY and CPU displays, but since the
|
||||
.Fl T
|
||||
and
|
||||
.Fl C
|
||||
flags are given, the TTY and CPU displays will be displayed.
|
||||
.Sh SEE ALSO
|
||||
.Xr fstat 1 ,
|
||||
.Xr netstat 1 ,
|
||||
@ -142,3 +382,16 @@ Default memory file.
|
||||
.Pp
|
||||
The sections starting with ``Interpreting system activity'' in
|
||||
.%T "Installing and Operating 4.3BSD" .
|
||||
.Sh HISTORY
|
||||
This version of
|
||||
.Nm iostat
|
||||
first appeared in
|
||||
.Fx 3.0 .
|
||||
.Sh BUGS
|
||||
.Pp
|
||||
You cannot display device statistics for a non-running system, due to the
|
||||
fact that the new device statistics interface is accessible only via
|
||||
.Xr sysctl 3 ,
|
||||
which does not provide a way to access non-running systems.
|
||||
.Sh AUTHOR
|
||||
.An Kenneth Merry Aq ken@FreeBSD.ORG
|
||||
|
@ -1,3 +1,36 @@
|
||||
/*
|
||||
* 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$
|
||||
*/
|
||||
/*
|
||||
* Parts of this program are derived from the original FreeBSD iostat
|
||||
* program:
|
||||
*/
|
||||
/*-
|
||||
* Copyright (c) 1986, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
@ -30,146 +63,185 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* Ideas for the new iostat statistics output modes taken from the NetBSD
|
||||
* version of iostat:
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 1996 John M. Vinopal
|
||||
* 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed for the NetBSD Project
|
||||
* by John M. Vinopal.
|
||||
* 4. 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 ``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 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.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static const char copyright[] =
|
||||
"@(#) Copyright (c) 1986, 1991, 1993\n\
|
||||
The Regents of the University of California. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)iostat.c 8.2 (Berkeley) 1/26/94";
|
||||
#endif
|
||||
static const char rcsid[] =
|
||||
"$Id$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/dkstat.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <kvm.h>
|
||||
#include <limits.h>
|
||||
#include <nlist.h>
|
||||
#include <paths.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <devstat.h>
|
||||
|
||||
struct nlist namelist[] = {
|
||||
#define X_DK_TIME 0
|
||||
{ "_dk_time" },
|
||||
#define X_DK_XFER 1
|
||||
{ "_dk_xfer" },
|
||||
#define X_DK_WDS 2
|
||||
{ "_dk_wds" },
|
||||
#define X_TK_NIN 3
|
||||
#define X_TK_NIN 0
|
||||
{ "_tk_nin" },
|
||||
#define X_TK_NOUT 4
|
||||
#define X_TK_NOUT 1
|
||||
{ "_tk_nout" },
|
||||
#define X_DK_SEEK 5
|
||||
{ "_dk_seek" },
|
||||
#define X_CP_TIME 6
|
||||
#define X_CP_TIME 2
|
||||
{ "_cp_time" },
|
||||
#define X_DK_WPMS 7
|
||||
{ "_dk_wpms" },
|
||||
#define X_HZ 8
|
||||
#define X_HZ 3
|
||||
{ "_hz" },
|
||||
#define X_STATHZ 9
|
||||
#define X_STATHZ 4
|
||||
{ "_stathz" },
|
||||
#define X_DK_NDRIVE 10
|
||||
{ "_dk_ndrive" },
|
||||
#define X_END 10
|
||||
#if defined(hp300) || defined(luna68k)
|
||||
#define X_HPDINIT (X_END+1)
|
||||
{ "_hp_dinit" },
|
||||
#endif
|
||||
#if defined(i386)
|
||||
#define X_DK_NAMES (X_END+1)
|
||||
{ "_dk_names" },
|
||||
#endif
|
||||
#ifdef mips
|
||||
#define X_SCSI_DINIT (X_END+1)
|
||||
{ "_scsi_dinit" },
|
||||
#endif
|
||||
#ifdef tahoe
|
||||
#define X_VBDINIT (X_END+1)
|
||||
{ "_vbdinit" },
|
||||
#endif
|
||||
#ifdef vax
|
||||
{ "_mbdinit" },
|
||||
#define X_MBDINIT (X_END+1)
|
||||
{ "_ubdinit" },
|
||||
#define X_UBDINIT (X_END+2)
|
||||
#endif
|
||||
#define X_END 4
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
struct _disk {
|
||||
long cp_time[CPUSTATES];
|
||||
long *dk_time;
|
||||
long *dk_wds;
|
||||
long *dk_seek;
|
||||
long *dk_xfer;
|
||||
long tk_nin;
|
||||
long tk_nout;
|
||||
} cur, last;
|
||||
|
||||
kvm_t *kd;
|
||||
double etime;
|
||||
long *dk_wpms;
|
||||
int dk_ndrive, *dr_select, hz, kmemfd, ndrives;
|
||||
char **dr_name;
|
||||
struct statinfo cur, last;
|
||||
int num_devices;
|
||||
struct device_selection *dev_select;
|
||||
int maxshowdevs;
|
||||
int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0;
|
||||
|
||||
#define nlread(x, v) \
|
||||
kvm_read(kd, namelist[x].n_value, &(v), sizeof(v))
|
||||
|
||||
#include "names.c" /* XXX */
|
||||
/* local function declarations */
|
||||
static void usage(void);
|
||||
static void phdr(int signo);
|
||||
static void devstats(int perf_select);
|
||||
static void cpustats(void);
|
||||
|
||||
void cpustats __P((void));
|
||||
void dkstats __P((void));
|
||||
void phdr __P((int));
|
||||
static void usage __P((void));
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
/*
|
||||
* We also support the following 'traditional' syntax:
|
||||
* iostat [drives] [wait [count]]
|
||||
* This isn't mentioned in the man page, or the usage statement,
|
||||
* but it is supported.
|
||||
*/
|
||||
fprintf(stderr, "usage: iostat [-CdhIoT?] [-c count] [-M core]"
|
||||
" [-n devs] [-N system]\n"
|
||||
"\t [-t type,if,pass] [-w wait] [drives]\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
register int i;
|
||||
long tmp;
|
||||
int ch, hdrcnt, reps, interval, stathz, ndrives;
|
||||
char **cp, *memf, *nlistf, buf[30];
|
||||
int tflag = 0, hflag = 0, cflag = 0, wflag = 0, nflag = 0;
|
||||
int count = 0, waittime = 0;
|
||||
char *memf = NULL, *nlistf = NULL;
|
||||
struct devstat_match *matches;
|
||||
int num_matches = 0;
|
||||
char errbuf[_POSIX2_LINE_MAX];
|
||||
char *err_str;
|
||||
kvm_t *kd;
|
||||
int hz, stathz;
|
||||
int headercount;
|
||||
int generation;
|
||||
int num_devices_specified;
|
||||
int num_selected, num_selections, select_generation;
|
||||
char **specified_devices;
|
||||
devstat_select_mode select_mode;
|
||||
|
||||
interval = reps = 0;
|
||||
nlistf = memf = NULL;
|
||||
while ((ch = getopt(argc, argv, "c:M:N:w:")) != -1)
|
||||
switch(ch) {
|
||||
case 'c':
|
||||
if ((reps = atoi(optarg)) <= 0)
|
||||
errx(1, "repetition count <= 0");
|
||||
break;
|
||||
case 'M':
|
||||
memf = optarg;
|
||||
break;
|
||||
case 'N':
|
||||
nlistf = optarg;
|
||||
break;
|
||||
case 'w':
|
||||
if ((interval = atoi(optarg)) <= 0)
|
||||
errx(1, "interval <= 0");
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
matches = NULL;
|
||||
maxshowdevs = 3;
|
||||
|
||||
while ((c = getopt(argc, argv, "c:CdhIM:n:N:ot:Tw:?")) != -1) {
|
||||
switch(c) {
|
||||
case 'c':
|
||||
cflag++;
|
||||
count = atoi(optarg);
|
||||
if (count < 1)
|
||||
errx(1, "count %d is < 1", count);
|
||||
break;
|
||||
case 'C':
|
||||
Cflag++;
|
||||
break;
|
||||
case 'd':
|
||||
dflag++;
|
||||
break;
|
||||
case 'h':
|
||||
hflag++;
|
||||
break;
|
||||
case 'I':
|
||||
Iflag++;
|
||||
break;
|
||||
case 'M':
|
||||
memf = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
nflag++;
|
||||
maxshowdevs = atoi(optarg);
|
||||
if (maxshowdevs < 0)
|
||||
errx(1, "number of devcies %d is < 0",
|
||||
maxshowdevs);
|
||||
break;
|
||||
case 'N':
|
||||
nlistf = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
oflag++;
|
||||
break;
|
||||
case 't':
|
||||
tflag++;
|
||||
if (buildmatch(optarg, &matches,
|
||||
&num_matches) != 0)
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
break;
|
||||
case 'T':
|
||||
Tflag++;
|
||||
break;
|
||||
case 'w':
|
||||
wflag++;
|
||||
waittime = atoi(optarg);
|
||||
if (waittime < 1)
|
||||
errx(1, "wait time is < 1");
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
@ -180,133 +252,248 @@ main(argc, argv)
|
||||
if (nlistf != NULL || memf != NULL)
|
||||
setgid(getgid());
|
||||
|
||||
kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Figure out how many devices we should display.
|
||||
*/
|
||||
if (nflag == 0) {
|
||||
if (oflag > 0) {
|
||||
if ((dflag > 0) && (Cflag == 0) && (Tflag == 0))
|
||||
maxshowdevs = 5;
|
||||
else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0))
|
||||
maxshowdevs = 5;
|
||||
else
|
||||
maxshowdevs = 4;
|
||||
} else {
|
||||
if ((dflag > 0) && (Cflag == 0))
|
||||
maxshowdevs = 4;
|
||||
else
|
||||
maxshowdevs = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* find out how many devices we have */
|
||||
if ((num_devices = getnumdevs()) < 0)
|
||||
err(1, "can't get number of devices");
|
||||
|
||||
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));
|
||||
|
||||
/*
|
||||
* Grab all the devices. We don't look to see if the list has
|
||||
* changed here, since it almost certainly has. We only look for
|
||||
* errors.
|
||||
*/
|
||||
if (getdevs(&cur) == -1)
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
|
||||
num_devices = cur.dinfo->numdevs;
|
||||
generation = cur.dinfo->generation;
|
||||
|
||||
/*
|
||||
* If the user specified any devices on the command line, see if
|
||||
* they are in the list of devices we have now.
|
||||
*/
|
||||
specified_devices = (char **)malloc(sizeof(char *));
|
||||
for (num_devices_specified = 0; *argv; ++argv) {
|
||||
if (isdigit(**argv))
|
||||
break;
|
||||
num_devices_specified++;
|
||||
specified_devices = (char **)realloc(specified_devices,
|
||||
sizeof(char *) *
|
||||
num_devices_specified);
|
||||
specified_devices[num_devices_specified - 1] = *argv;
|
||||
|
||||
}
|
||||
|
||||
dev_select = NULL;
|
||||
|
||||
if ((num_devices_specified == 0) && (num_matches == 0))
|
||||
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, hflag) == -1)
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
|
||||
free(specified_devices);
|
||||
|
||||
/*
|
||||
* Look for the traditional wait time and count arguments.
|
||||
*/
|
||||
if (*argv) {
|
||||
waittime = atoi(*argv);
|
||||
|
||||
/* Let the user know he goofed, but keep going anyway */
|
||||
if (wflag != 0)
|
||||
warnx("discarding previous wait interval, using"
|
||||
" %d instead", waittime);
|
||||
wflag++;
|
||||
|
||||
if (*++argv) {
|
||||
count = atoi(*argv);
|
||||
if (cflag != 0)
|
||||
warnx("discarding previous count, using %d"
|
||||
" instead", count);
|
||||
cflag++;
|
||||
} else
|
||||
count = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the user specified a count, but not an interval, we default
|
||||
* to an interval of 1 second.
|
||||
*/
|
||||
if ((wflag == 0) && (cflag > 0))
|
||||
waittime = 1;
|
||||
|
||||
/*
|
||||
* If the user specified a wait time, but not a count, we want to
|
||||
* go on ad infinitum. This can be redundant if the user uses the
|
||||
* traditional method of specifying the wait, since in that case we
|
||||
* already set count = -1 above. Oh well.
|
||||
*/
|
||||
if ((wflag > 0) && (cflag == 0))
|
||||
count = -1;
|
||||
|
||||
kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
|
||||
|
||||
if (kd == 0)
|
||||
errx(1, "kvm_openfiles: %s", errbuf);
|
||||
|
||||
if (kvm_nlist(kd, namelist) == -1)
|
||||
errx(1, "kvm_nlist: %s", kvm_geterr(kd));
|
||||
if (namelist[X_DK_NDRIVE].n_type == 0)
|
||||
errx(1, "dk_ndrive not found in namelist");
|
||||
(void)nlread(X_DK_NDRIVE, dk_ndrive);
|
||||
if (dk_ndrive < 0)
|
||||
errx(1, "invalid dk_ndrive %d", dk_ndrive);
|
||||
|
||||
cur.dk_time = calloc(dk_ndrive, sizeof(long));
|
||||
cur.dk_wds = calloc(dk_ndrive, sizeof(long));
|
||||
cur.dk_seek = calloc(dk_ndrive, sizeof(long));
|
||||
cur.dk_xfer = calloc(dk_ndrive, sizeof(long));
|
||||
last.dk_time = calloc(dk_ndrive, sizeof(long));
|
||||
last.dk_wds = calloc(dk_ndrive, sizeof(long));
|
||||
last.dk_seek = calloc(dk_ndrive, sizeof(long));
|
||||
last.dk_xfer = calloc(dk_ndrive, sizeof(long));
|
||||
dr_select = calloc(dk_ndrive, sizeof(int));
|
||||
dr_name = calloc(dk_ndrive, sizeof(char *));
|
||||
dk_wpms = calloc(dk_ndrive, sizeof(long));
|
||||
|
||||
for (i = 0; i < dk_ndrive; i++) {
|
||||
(void)sprintf(buf, "dk%d", i);
|
||||
dr_name[i] = strdup(buf);
|
||||
}
|
||||
if (!read_names())
|
||||
exit(1);
|
||||
(void)nlread(X_HZ, hz);
|
||||
(void)nlread(X_STATHZ, stathz);
|
||||
if (stathz)
|
||||
hz = stathz;
|
||||
(void)kvm_read(kd, namelist[X_DK_WPMS].n_value, dk_wpms,
|
||||
dk_ndrive * sizeof(dk_wpms));
|
||||
|
||||
/*
|
||||
* Choose drives to be displayed. Priority goes to (in order) drives
|
||||
* supplied as arguments and default drives. If everything isn't
|
||||
* filled in and there are drives not taken care of, display the first
|
||||
* few that fit.
|
||||
*
|
||||
* The backward compatibility #ifdefs permit the syntax:
|
||||
* iostat [ drives ] [ interval [ count ] ]
|
||||
* If the user stops the program (control-Z) and then resumes it,
|
||||
* print out the header again.
|
||||
*/
|
||||
#define BACKWARD_COMPATIBILITY
|
||||
for (ndrives = 0; *argv; ++argv) {
|
||||
#ifdef BACKWARD_COMPATIBILITY
|
||||
if (isdigit(**argv))
|
||||
break;
|
||||
#endif
|
||||
for (i = 0; i < dk_ndrive; i++) {
|
||||
if (strcmp(dr_name[i], *argv))
|
||||
continue;
|
||||
dr_select[i] = 1;
|
||||
++ndrives;
|
||||
}
|
||||
}
|
||||
#ifdef BACKWARD_COMPATIBILITY
|
||||
if (*argv) {
|
||||
interval = atoi(*argv);
|
||||
if (*++argv)
|
||||
reps = atoi(*argv);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (interval) {
|
||||
if (!reps)
|
||||
reps = -1;
|
||||
} else
|
||||
if (reps)
|
||||
interval = 1;
|
||||
|
||||
for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
|
||||
if (dr_select[i] || dk_wpms[i] == 0)
|
||||
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;
|
||||
}
|
||||
|
||||
(void)signal(SIGCONT, phdr);
|
||||
|
||||
for (hdrcnt = 1;;) {
|
||||
if (!--hdrcnt) {
|
||||
for (headercount = 1;;) {
|
||||
struct devinfo *tmp_dinfo;
|
||||
long tmp;
|
||||
double etime;
|
||||
|
||||
if (!--headercount) {
|
||||
phdr(0);
|
||||
hdrcnt = 20;
|
||||
headercount = 20;
|
||||
}
|
||||
(void)kvm_read(kd, namelist[X_DK_TIME].n_value,
|
||||
cur.dk_time, dk_ndrive * sizeof(long));
|
||||
(void)kvm_read(kd, namelist[X_DK_XFER].n_value,
|
||||
cur.dk_xfer, dk_ndrive * sizeof(long));
|
||||
(void)kvm_read(kd, namelist[X_DK_WDS].n_value,
|
||||
cur.dk_wds, dk_ndrive * sizeof(long));
|
||||
(void)kvm_read(kd, namelist[X_DK_SEEK].n_value,
|
||||
cur.dk_seek, dk_ndrive * sizeof(long));
|
||||
(void)kvm_read(kd, namelist[X_TK_NIN].n_value,
|
||||
&cur.tk_nin, sizeof(cur.tk_nin));
|
||||
(void)kvm_read(kd, namelist[X_TK_NOUT].n_value,
|
||||
&cur.tk_nout, sizeof(cur.tk_nout));
|
||||
(void)kvm_read(kd, namelist[X_CP_TIME].n_value,
|
||||
cur.cp_time, sizeof(cur.cp_time));
|
||||
for (i = 0; i < dk_ndrive; i++) {
|
||||
if (!dr_select[i])
|
||||
continue;
|
||||
#define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp
|
||||
X(dk_xfer);
|
||||
X(dk_seek);
|
||||
X(dk_wds);
|
||||
X(dk_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, hflag);
|
||||
switch(retval) {
|
||||
case -1:
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
break;
|
||||
case 1:
|
||||
phdr(0);
|
||||
headercount = 20;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We only want to re-select devices if we're in 'top'
|
||||
* mode. This is the only mode where the devices selected
|
||||
* could actually change.
|
||||
*/
|
||||
if (hflag > 0) {
|
||||
int retval;
|
||||
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, hflag);
|
||||
switch(retval) {
|
||||
case -1:
|
||||
errx(1,"%s", devstat_errbuf);
|
||||
break;
|
||||
case 1:
|
||||
phdr(0);
|
||||
headercount = 20;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = cur.tk_nin;
|
||||
cur.tk_nin -= last.tk_nin;
|
||||
last.tk_nin = tmp;
|
||||
tmp = cur.tk_nout;
|
||||
cur.tk_nout -= last.tk_nout;
|
||||
last.tk_nout = tmp;
|
||||
etime = 0;
|
||||
|
||||
etime = 0.0;
|
||||
|
||||
#define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp
|
||||
|
||||
for (i = 0; i < CPUSTATES; i++) {
|
||||
X(cp_time);
|
||||
etime += cur.cp_time[i];
|
||||
@ -314,86 +501,164 @@ main(argc, argv)
|
||||
if (etime == 0.0)
|
||||
etime = 1.0;
|
||||
etime /= (float)hz;
|
||||
(void)printf("%4.0f%5.0f",
|
||||
cur.tk_nin / etime, cur.tk_nout / etime);
|
||||
dkstats();
|
||||
cpustats();
|
||||
(void)printf("\n");
|
||||
(void)fflush(stdout);
|
||||
if ((dflag == 0) || (Tflag > 0))
|
||||
printf("%4.0f%5.0f", cur.tk_nin / etime,
|
||||
cur.tk_nout/etime);
|
||||
devstats(hflag);
|
||||
if ((dflag == 0) || (Cflag > 0))
|
||||
cpustats();
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
|
||||
if (reps >= 0 && --reps <= 0)
|
||||
if (count >= 0 && --count <= 0)
|
||||
break;
|
||||
(void)sleep(interval);
|
||||
|
||||
sleep(waittime);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* ARGUSED */
|
||||
void
|
||||
phdr(signo)
|
||||
int signo;
|
||||
static void
|
||||
phdr(int signo)
|
||||
{
|
||||
register int i;
|
||||
int printed;
|
||||
|
||||
if ((dflag == 0) || (Tflag > 0))
|
||||
(void)printf(" tty");
|
||||
for (i = 0, printed=0;(i < num_devices) && (printed < maxshowdevs);i++){
|
||||
int di;
|
||||
if ((dev_select[i].selected != 0)
|
||||
&& (dev_select[i].selected <= maxshowdevs)) {
|
||||
di = dev_select[i].position;
|
||||
if (oflag > 0)
|
||||
(void)printf("%12.6s%d ",
|
||||
cur.dinfo->devices[di].device_name,
|
||||
cur.dinfo->devices[di].unit_number);
|
||||
else
|
||||
printf("%15.6s%d ",
|
||||
cur.dinfo->devices[di].device_name,
|
||||
cur.dinfo->devices[di].unit_number);
|
||||
printed++;
|
||||
}
|
||||
}
|
||||
if ((dflag == 0) || (Cflag > 0))
|
||||
(void)printf(" cpu\n");
|
||||
else
|
||||
(void)printf("\n");
|
||||
|
||||
if ((dflag == 0) || (Tflag > 0))
|
||||
(void)printf(" tin tout");
|
||||
|
||||
for (i=0, printed = 0;(i < num_devices) && (printed < maxshowdevs);i++){
|
||||
if ((dev_select[i].selected != 0)
|
||||
&& (dev_select[i].selected <= maxshowdevs)) {
|
||||
if (oflag > 0)
|
||||
if (Iflag == 0)
|
||||
(void)printf(" sps tps msps ");
|
||||
else
|
||||
(void)printf(" blk xfr msps ");
|
||||
|
||||
else
|
||||
if (Iflag == 0)
|
||||
printf(" KB/t tps MB/s ");
|
||||
else
|
||||
printf(" KB/t xfrs MB ");
|
||||
printed++;
|
||||
}
|
||||
}
|
||||
if ((dflag == 0) || (Cflag > 0))
|
||||
(void)printf(" us ni sy in id\n");
|
||||
else
|
||||
printf("\n");
|
||||
|
||||
(void)printf(" tty");
|
||||
for (i = 0; i < dk_ndrive; i++)
|
||||
if (dr_select[i])
|
||||
(void)printf(" %4.4s ", dr_name[i]);
|
||||
(void)printf(" cpu\n tin tout");
|
||||
for (i = 0; i < dk_ndrive; i++)
|
||||
if (dr_select[i])
|
||||
(void)printf(" sps tps msps ");
|
||||
(void)printf(" us ni sy in id\n");
|
||||
}
|
||||
|
||||
void
|
||||
dkstats()
|
||||
static void
|
||||
devstats(int perf_select)
|
||||
{
|
||||
register int dn;
|
||||
double atime, itime, msps, words, xtime;
|
||||
long double transfers_per_second;
|
||||
long double kb_per_transfer, mb_per_second;
|
||||
u_int64_t total_bytes, total_transfers, total_blocks;
|
||||
long double busy_seconds;
|
||||
long double total_mb;
|
||||
long double blocks_per_second, ms_per_transaction;
|
||||
|
||||
/*
|
||||
* Calculate elapsed time up front, since it's the same for all
|
||||
* devices.
|
||||
*/
|
||||
busy_seconds = compute_etime(cur.busy_time, last.busy_time);
|
||||
|
||||
for (dn = 0; dn < dk_ndrive; ++dn) {
|
||||
if (!dr_select[dn])
|
||||
for (dn = 0; dn < num_devices; dn++) {
|
||||
int di;
|
||||
|
||||
if (((perf_select == 0) && (dev_select[dn].selected == 0))
|
||||
|| (dev_select[dn].selected > maxshowdevs))
|
||||
continue;
|
||||
words = (double)cur.dk_wds[dn] * 32; /* words xfer'd */
|
||||
(void)printf("%4.0f", /* sectors */
|
||||
words / (DEV_BSIZE / 2) / etime);
|
||||
|
||||
(void)printf("%4.0f", cur.dk_xfer[dn] / etime);
|
||||
di = dev_select[dn].position;
|
||||
|
||||
if (dk_wpms[dn] && cur.dk_xfer[dn]) {
|
||||
atime = cur.dk_time[dn]; /* ticks disk busy */
|
||||
atime /= (float)hz; /* ticks to seconds */
|
||||
xtime = words / dk_wpms[dn]; /* transfer time */
|
||||
itime = atime - xtime; /* time not xfer'ing */
|
||||
if (itime < 0)
|
||||
msps = 0;
|
||||
else
|
||||
msps = itime * 1000 / cur.dk_xfer[dn];
|
||||
} else
|
||||
msps = 0;
|
||||
(void)printf("%5.1f ", msps);
|
||||
if (compute_stats(&cur.dinfo->devices[di],
|
||||
&last.dinfo->devices[di], busy_seconds,
|
||||
&total_bytes, &total_transfers,
|
||||
&total_blocks, &kb_per_transfer,
|
||||
&transfers_per_second, &mb_per_second,
|
||||
&blocks_per_second, &ms_per_transaction)!= 0)
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
|
||||
if (perf_select != 0) {
|
||||
dev_select[dn].bytes = total_bytes;
|
||||
if ((dev_select[dn].selected == 0)
|
||||
|| (dev_select[dn].selected > maxshowdevs))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (oflag > 0) {
|
||||
|
||||
if (Iflag == 0)
|
||||
printf("%4.0Lf%4.0Lf%5.1Lf ",
|
||||
blocks_per_second,
|
||||
transfers_per_second,
|
||||
ms_per_transaction);
|
||||
else
|
||||
printf("%4.1qu%4.1qu%5.1Lf ",
|
||||
total_blocks,
|
||||
total_transfers,
|
||||
ms_per_transaction);
|
||||
} else {
|
||||
|
||||
if (Iflag == 0)
|
||||
printf(" %5.2Lf %3.0Lf %5.2Lf ",
|
||||
kb_per_transfer,
|
||||
transfers_per_second,
|
||||
mb_per_second);
|
||||
else {
|
||||
total_mb = total_bytes;
|
||||
total_mb /= 1024 * 1024;
|
||||
|
||||
printf(" %5.2Lf %3.1qu %5.2Lf ",
|
||||
kb_per_transfer,
|
||||
total_transfers,
|
||||
total_mb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpustats()
|
||||
static void
|
||||
cpustats(void)
|
||||
{
|
||||
register int state;
|
||||
double time;
|
||||
|
||||
time = 0;
|
||||
time = 0.0;
|
||||
|
||||
for (state = 0; state < CPUSTATES; ++state)
|
||||
time += cur.cp_time[state];
|
||||
for (state = 0; state < CPUSTATES; ++state)
|
||||
(void)printf("%3.0f",
|
||||
100. * cur.cp_time[state] / (time ? time : 1));
|
||||
}
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
(void)fprintf(stderr,
|
||||
"usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n");
|
||||
exit(1);
|
||||
printf("%3.0f",
|
||||
100. * cur.cp_time[state] / (time ? time : 1));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user