New userland code to read the statistics kept by the NetBSD generic

disk framework, from John M. Vinopal <banshee@gabriella.resort.com>
This commit is contained in:
thorpej 1996-05-10 23:16:30 +00:00
parent e3937c848b
commit 1eaf5ee379
18 changed files with 936 additions and 934 deletions

View File

@ -1,16 +1,15 @@
# $NetBSD: Makefile,v 1.4 1995/12/22 08:04:24 jonathan Exp $
# $NetBSD: Makefile,v 1.5 1996/05/10 23:16:30 thorpej Exp $
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= systat
.if (${MACHINE_ARCH} == "m68k")
CFLAGS+=-D${MACHINE}
.endif
CFLAGS+=-I${.CURDIR}/../../sys/arch -I${.CURDIR}/../vmstat
SRCS= cmds.c cmdtab.c disks.c fetch.c iostat.c keyboard.c main.c mbufs.c \
netcmds.c netstat.c pigs.c swap.c vmstat.c
LDADD= -lcurses -ltermcap -lm -lkvm
.PATH: ${.CURDIR}/../../usr.bin/vmstat
CFLAGS+=-I${.CURDIR}/../../usr.bin/vmstat
SRCS= cmds.c cmdtab.c disks.c dkstats.c fetch.c iostat.c keyboard.c \
main.c mbufs.c netcmds.c netstat.c pigs.c swap.c vmstat.c
DPADD= ${LIBCURSES} ${LIBTERMCAP} ${LIBM} ${LIBKVM}
LDADD= -lcurses -ltermcap -lm -lkvm
BINGRP= kmem
BINMODE=2555

View File

@ -1,4 +1,4 @@
/* $NetBSD: cmds.c,v 1.3 1995/08/31 22:20:18 jtc Exp $ */
/* $NetBSD: cmds.c,v 1.4 1996/05/10 23:16:32 thorpej Exp $ */
/*-
* Copyright (c) 1980, 1992, 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/29/95";
#endif
static char rcsid[] = "$NetBSD: cmds.c,v 1.3 1995/08/31 22:20:18 jtc Exp $";
static char rcsid[] = "$NetBSD: cmds.c,v 1.4 1996/05/10 23:16:32 thorpej Exp $";
#endif /* not lint */
#include <stdlib.h>
@ -110,7 +110,9 @@ command(cmd)
}
p = lookup(cmd);
if (p == (struct cmdtab *)-1) {
error("%s: Ambiguous command.", cmd);
/* if not a primary command, try a display specific one */
if (curcmd->c_cmd == 0 || !(*curcmd->c_cmd)(cmd, cp))
error("%s: Ambiguous command.", cmd);
goto done;
}
if (p) {
@ -140,8 +142,6 @@ command(cmd)
status();
goto done;
}
if (curcmd->c_cmd == 0 || !(*curcmd->c_cmd)(cmd, cp))
error("%s: Unknown command.", cmd);
done:
sigsetmask(omask);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: disks.c,v 1.3 1996/03/15 22:19:23 ragge Exp $ */
/* $NetBSD: disks.c,v 1.4 1996/05/10 23:16:33 thorpej Exp $ */
/*-
* Copyright (c) 1980, 1992, 1993
@ -37,104 +37,13 @@
#if 0
static char sccsid[] = "@(#)disks.c 8.1 (Berkeley) 6/6/93";
#endif
static char rcsid[] = "$NetBSD: disks.c,v 1.3 1996/03/15 22:19:23 ragge Exp $";
static char rcsid[] = "$NetBSD: disks.c,v 1.4 1996/05/10 23:16:33 thorpej Exp $";
#endif /* not lint */
#include <sys/types.h>
#include <sys/buf.h>
#include <nlist.h>
#include <ctype.h>
#include <paths.h>
#include <string.h>
#include <stdlib.h>
#include "systat.h"
#include "extern.h"
static void dkselect(char *args, int truefalse, int selections[]);
static void dkselect __P((char *, int, int []));
static int read_names __P((void));
static struct nlist namelist[] = {
#define X_DK_NDRIVE 0
{ "_dk_ndrive" },
#define X_DK_WPMS 1
{ "_dk_wpms" },
#ifdef sun
#define X_MBDINIT (X_DK_WPMS+1)
{ "_mbdinit" },
#endif
#ifdef tahoe
#define X_VBDINIT (X_DK_WPMS+1)
{ "_vbdinit" },
#endif
#if defined(hp300) || defined(luna68k)
#define X_HPDINIT (X_DK_WPMS+1)
{ "_hp_dinit" },
#endif
#ifdef mips
#define X_SCSI_DINIT (X_DK_WPMS+1)
{ "_scsi_dinit" },
#endif
{ "" },
};
float *dk_mspw;
int dk_ndrive, *dk_select;
char **dr_name;
#include "names.c" /* XXX */
int
dkinit()
{
register int i;
register char *cp;
static int once = 0;
static char buf[1024];
if (once)
return(1);
if (kvm_nlist(kd, namelist)) {
nlisterr(namelist);
return(0);
}
if (namelist[X_DK_NDRIVE].n_value == 0) {
error("dk_ndrive undefined in kernel");
return(0);
}
NREAD(X_DK_NDRIVE, &dk_ndrive, LONG);
if (dk_ndrive <= 0) {
error("dk_ndrive=%d according to %s", dk_ndrive, _PATH_UNIX);
return(0);
}
dk_mspw = (float *)calloc(dk_ndrive, sizeof (float));
{
long *wpms = (long *)calloc(dk_ndrive, sizeof(long));
KREAD(NPTR(X_DK_WPMS), wpms, dk_ndrive * sizeof (long));
for (i = 0; i < dk_ndrive; i++)
*(dk_mspw + i) = (*(wpms + i) == 0)? 0.0:
(float) 1.0 / *(wpms + i);
free(wpms);
}
dr_name = (char **)calloc(dk_ndrive, sizeof (char *));
dk_select = (int *)calloc(dk_ndrive, sizeof (int));
for (cp = buf, i = 0; i < dk_ndrive; i++) {
dr_name[i] = cp;
sprintf(dr_name[i], "dk%d", i);
cp += strlen(dr_name[i]) + 1;
if (dk_mspw[i] != 0.0)
dk_select[i] = 1;
}
if (!read_names()) {
free(dr_name);
free(dk_select);
free(dk_mspw);
return(0);
}
once = 1;
return(1);
}
int
dkcmd(cmd, args)
@ -153,8 +62,7 @@ dkcmd(cmd, args)
move(CMDLINE, 0); clrtoeol();
for (i = 0; i < dk_ndrive; i++)
if (dk_mspw[i] != 0.0)
printw("%s ", dr_name[i]);
printw("%s ", dr_name[i]);
return (1);
}
return (0);
@ -184,11 +92,7 @@ dkselect(args, truefalse, selections)
break;
for (i = 0; i < dk_ndrive; i++)
if (strcmp(args, dr_name[i]) == 0) {
if (dk_mspw[i] != 0.0)
selections[i] = truefalse;
else
error("%s: drive not configured",
dr_name[i]);
selections[i] = truefalse;
break;
}
if (i >= dk_ndrive)

View File

@ -1,4 +1,4 @@
/* $NetBSD: extern.h,v 1.2 1995/01/20 08:51:54 jtc Exp $ */
/* $NetBSD: extern.h,v 1.3 1996/05/10 23:16:34 thorpej Exp $ */
/*-
* Copyright (c) 1991, 1993
@ -76,7 +76,7 @@ struct cmdtab *lookup __P((char *));
void command __P((char *));
void die __P((int));
void display __P((int));
int dkinit __P((void));
int dkinit __P((int));
int dkcmd __P((char *, char *));
void error __P((const char *fmt, ...));
void fetchiostat __P((void));

View File

@ -1,4 +1,4 @@
/* $NetBSD: iostat.c,v 1.4 1996/03/15 22:19:25 ragge Exp $ */
/* $NetBSD: iostat.c,v 1.5 1996/05/10 23:16:35 thorpej Exp $ */
/*
* Copyright (c) 1980, 1992, 1993
@ -37,12 +37,13 @@
#if 0
static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93";
#endif
static char rcsid[] = "$NetBSD: iostat.c,v 1.4 1996/03/15 22:19:25 ragge Exp $";
static char rcsid[] = "$NetBSD: iostat.c,v 1.5 1996/05/10 23:16:35 thorpej Exp $";
#endif not lint
#include <sys/param.h>
#include <sys/dkstat.h>
#include <sys/buf.h>
#include <sys/time.h>
#include <string.h>
#include <stdlib.h>
@ -51,39 +52,13 @@ static char rcsid[] = "$NetBSD: iostat.c,v 1.4 1996/03/15 22:19:25 ragge Exp $";
#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
{ "_cp_time" },
#ifdef tahoe
#define X_VBDINIT (X_CP_TIME+1)
{ "_vbdinit" },
#endif
{ "" },
};
static struct {
int dk_busy;
long cp_time[CPUSTATES];
long *dk_time;
long *dk_wds;
long *dk_seek;
long *dk_xfer;
} s, s1;
#include "dkstats.h"
extern struct _disk cur;
static int linesperregion;
static double etime;
static int numbers = 0; /* default display bar graphs */
static int msps = 0; /* default ms/seek shown */
static int secs = 0; /* default seconds shown */
static int barlabels __P((int));
static void histogram __P((double, int, double));
@ -112,42 +87,16 @@ 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())
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);
dkinit(1);
dkreadstats();
}
void
fetchiostat()
{
if (namelist[X_DK_BUSY].n_type == 0)
if (dk_ndrive == 0)
return;
NREAD(X_DK_BUSY, &s.dk_busy, LONG);
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);
dkreadstats();
}
#define INSET 10
@ -157,8 +106,8 @@ labeliostat()
{
int row;
if (namelist[X_DK_BUSY].n_type == 0) {
error("No dk_busy defined.");
if (dk_ndrive == 0) {
error("No drives defined.");
return;
}
row = 0;
@ -185,7 +134,7 @@ numlabels(row)
#define COLWIDTH 14
#define DRIVESPERLINE ((wnd->maxx - INSET) / COLWIDTH)
for (ndrives = 0, i = 0; i < dk_ndrive; i++)
if (dk_select[i])
if (cur.dk_select[i])
ndrives++;
regions = howmany(ndrives, DRIVESPERLINE);
/*
@ -200,14 +149,14 @@ numlabels(row)
linesperregion = 3;
col = 0;
for (i = 0; i < dk_ndrive; i++)
if (dk_select[i] && dk_mspw[i] != 0.0) {
if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
if (col + COLWIDTH >= wnd->maxx - INSET) {
col = 0, 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");
mvwaddstr(wnd, row, col + 4, cur.dk_name[i]);
mvwaddstr(wnd, row + 1, col, "Kps tps sec");
col += COLWIDTH;
}
if (col)
@ -222,16 +171,16 @@ barlabels(row)
int i;
mvwaddstr(wnd, row++, INSET,
"/0 /5 /10 /15 /20 /25 /30 /35 /40 /45 /50");
linesperregion = 2 + msps;
"/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
linesperregion = 2 + secs;
for (i = 0; i < dk_ndrive; i++)
if (dk_select[i] && dk_mspw[i] != 0.0) {
if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
if (row > wnd->maxy - linesperregion)
break;
mvwprintw(wnd, row++, 0, "%3.3s bps|", dr_name[i]);
mvwprintw(wnd, row++, 0, "%3.3s Kps|", cur.dk_name[i]);
mvwaddstr(wnd, row++, 0, " tps|");
if (msps)
mvwaddstr(wnd, row++, 0, " msps|");
if (secs)
mvwaddstr(wnd, row++, 0, " msec|");
}
return (row);
}
@ -240,19 +189,16 @@ barlabels(row)
void
showiostat()
{
register long t;
register u_int64_t t;
register int i, row, col;
if (namelist[X_DK_BUSY].n_type == 0)
if (dk_ndrive == 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);
}
dkswap();
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;
@ -267,7 +213,7 @@ showiostat()
if (!numbers) {
row += 2;
for (i = 0; i < dk_ndrive; i++)
if (dk_select[i] && dk_mspw[i] != 0.0) {
if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
if (row > wnd->maxy - linesperregion)
break;
row = stats(row, INSET, i);
@ -280,7 +226,7 @@ showiostat()
wmove(wnd, row + 3, 0);
winsertln(wnd);
for (i = 0; i < dk_ndrive; i++)
if (dk_select[i] && dk_mspw[i] != 0.0) {
if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
if (col + COLWIDTH >= wnd->maxx) {
col = 0, row += linesperregion + 1;
if (row > wnd->maxy - (linesperregion + 1))
@ -299,31 +245,26 @@ static int
stats(row, col, dn)
int row, col, dn;
{
double atime, words, xtime, itime;
double atime, words;
atime = s.dk_time[dn];
atime /= (float) hz;
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;
/* time busy in disk activity */
atime = (double)cur.dk_time[dn].tv_sec +
((double)cur.dk_time[dn].tv_usec / (double)1000000);
words = cur.dk_bytes[dn] / 1024.0; /* # of K transferred */
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);
words / etime, cur.dk_xfer[dn] / etime, atime / etime);
return (row);
}
wmove(wnd, row++, col);
histogram(words / 512 / etime, 50, 1.0);
histogram(words / etime, 50, 0.5);
wmove(wnd, row++, col);
histogram(s.dk_xfer[dn] / etime, 50, 1.0);
if (msps) {
histogram(cur.dk_xfer[dn] / etime, 50, 0.5);
if (secs) {
wmove(wnd, row++, col);
histogram(s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0,
50, 1.0);
atime *= 1000; /* In milliseconds */
histogram(atime / etime, 50, 0.5);
}
return (row);
}
@ -337,12 +278,12 @@ 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
@ -362,6 +303,7 @@ histogram(val, colwidth, scale)
while (k--)
waddch(wnd, 'X');
waddstr(wnd, buf);
wclrtoeol(wnd);
return;
}
while (k--)
@ -374,8 +316,8 @@ cmdiostat(cmd, args)
char *cmd, *args;
{
if (prefix(cmd, "msps"))
msps = !msps;
if (prefix(cmd, "secs"))
secs = !secs;
else if (prefix(cmd, "numbers"))
numbers = 1;
else if (prefix(cmd, "bars"))

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.7 1996/03/21 18:04:25 jtc Exp $ */
/* $NetBSD: main.c,v 1.8 1996/05/10 23:16:36 thorpej Exp $ */
/*-
* Copyright (c) 1980, 1992, 1993
@ -43,7 +43,7 @@ static char copyright[] =
#if 0
static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
#endif
static char rcsid[] = "$NetBSD: main.c,v 1.7 1996/03/21 18:04:25 jtc Exp $";
static char rcsid[] = "$NetBSD: main.c,v 1.8 1996/05/10 23:16:36 thorpej Exp $";
#endif /* not lint */
#include <sys/param.h>
@ -53,6 +53,7 @@ static char rcsid[] = "$NetBSD: main.c,v 1.7 1996/03/21 18:04:25 jtc Exp $";
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "systat.h"
#include "extern.h"
@ -68,6 +69,8 @@ static struct nlist namelist[] = {
static int dellave;
kvm_t *kd;
char *memf = NULL;
char *nlistf = NULL;
sig_t sigtstpdfl;
double avenrun[3];
int col;
@ -82,32 +85,59 @@ int CMDLINE;
static WINDOW *wload; /* one line window for load average */
static void usage();
int
main(argc, argv)
int argc;
char **argv;
{
int ch;
char errbuf[80];
argc--, argv++;
while (argc > 0) {
if (argv[0][0] == '-') {
struct cmdtab *p;
while ((ch = getopt(argc, argv, "M:N:w:")) != EOF)
switch(ch) {
case 'M':
memf = optarg;
break;
case 'N':
nlistf = optarg;
break;
case 'w':
if ((naptime = atoi(optarg)) <= 0)
errx(1, "interval <= 0.");
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
/*
* Discard setgid privileges if not the running kernel so that bad
* guys can't print interesting stuff from kernel memory.
*/
if (nlistf != NULL || memf != NULL)
setgid(getgid());
p = lookup(&argv[0][1]);
if (p == (struct cmdtab *)-1)
errx(1, "ambiguous request: %s", &argv[0][1]);
if (p == 0)
errx(1, "unknown request: %s", &argv[0][1]);
curcmd = p;
} else {
while (argc > 0) {
if (isdigit(argv[0][0])) {
naptime = atoi(argv[0]);
if (naptime <= 0)
naptime = 5;
} else {
struct cmdtab *p;
p = lookup(&argv[0][0]);
if (p == (struct cmdtab *)-1)
errx(1, "ambiguous request: %s", &argv[0][0]);
if (p == 0)
errx(1, "unknown request: %s", &argv[0][0]);
curcmd = p;
}
argc--, argv++;
}
kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
if (kd == NULL) {
error("%s", errbuf);
exit(1);
@ -162,6 +192,14 @@ main(argc, argv)
/*NOTREACHED*/
}
static void
usage()
{
fprintf(stderr, "usage: systat [-M core] [-N system] [-w wait]\n");
exit(1);
}
void
labels()
{

View File

@ -1,4 +1,4 @@
/* $NetBSD: swap.c,v 1.4 1995/08/31 22:20:19 jtc Exp $ */
/* $NetBSD: swap.c,v 1.5 1996/05/10 23:16:38 thorpej Exp $ */
/*-
* Copyright (c) 1980, 1992, 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)swap.c 8.3 (Berkeley) 4/29/95";
#endif
static char rcsid[] = "$NetBSD: swap.c,v 1.4 1995/08/31 22:20:19 jtc Exp $";
static char rcsid[] = "$NetBSD: swap.c,v 1.5 1996/05/10 23:16:38 thorpej Exp $";
#endif /* not lint */
/*
@ -64,8 +64,6 @@ static char rcsid[] = "$NetBSD: swap.c,v 1.4 1995/08/31 22:20:19 jtc Exp $";
extern char *getbsize __P((int *headerlenp, long *blocksizep));
void showspace __P((char *header, int hlen, long blocksize));
kvm_t *kd;
struct nlist syms[] = {
{ "_swapmap" }, /* list of free swap areas */
#define VM_SWAPMAP 0

View File

@ -1,4 +1,4 @@
.\" $NetBSD: systat.1,v 1.5 1995/09/27 19:46:12 jtc Exp $
.\" $NetBSD: systat.1,v 1.6 1996/05/10 23:16:39 thorpej Exp $
.\"
.\" Copyright (c) 1985, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@ -41,7 +41,10 @@
.Nd display system statistics on a crt
.Sh SYNOPSIS
.Nm systat
.Op Fl display
.Op Fl M Ar core
.Op Fl N Ar system
.Op Fl w Ar wait
.Op Ar display
.Op Ar refresh-interval
.Sh DESCRIPTION
.Nm Systat
@ -78,12 +81,20 @@ allows each display to have certain display-specific commands.
.Pp
Command line options:
.Bl -tag -width "refresh_interval"
.It Fl Ns Ar display
.It Fl M Ar core
Extract values associated with the name list from
.Ar core
instead of the default
.Pa /dev/mem .
.It Fl N Ar system
Extracr the name list from
.Ar system
instead of the default
.Pa /netbsd .
.It Ar display
The
.Fl
flag expects
.Ar display
to be one of:
argument expects to be one of:
.Ic pigs ,
.Ic iostat ,
.Ic swap ,
@ -91,14 +102,17 @@ to be one of:
.Ic vmstat
or
.Ic netstat .
These displays can also be requested interactively (without the
.Dq Fl )
and are described in
These displays can also be requested interactively and are described in
full detail below.
.It Ar refresh-interval
The
.Ar refresh-value
specifies the screen refresh time interval in seconds.
.Ar refresh-interval
specifies the screen refresh time interval in seconds. This is provided
for backwards compatibility, and overrides the
.Ar refresh-interval
specified with the
.Fl w
flag.
.El
.Pp
Certain characters cause immediate action by
@ -162,7 +176,7 @@ bar graphs of the amount of time executing in user mode (``user''),
in user mode running low priority processes (``nice''), in
system mode (``system''), and idle (``idle''). Statistics
on disk throughput show, for each drive, kilobytes of data transferred,
number of disk transactions performed, and average seek time
number of disk transactions performed, and time spent in disk accesses
(in milliseconds). This information may be displayed as
bar graphs or as rows of numbers which scroll downward. Bar
graphs are shown by default;
@ -181,9 +195,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 secs
Toggle the display of time in disk activity (the default is to
not display time).
.El
.It Ic swap
Show information about swap space usage on all the
@ -226,10 +240,10 @@ Finally the last column shows the number of physical pages
on the free list.
.Pp
Below the memory display is the disk usage display.
It reports the number of seeks, transfers, and number
It reports the number of seeks, transfers, number
of kilobyte blocks transferred per second averaged over the
refresh period of the display (by default, five seconds).
For some disks it also reports the average milliseconds per seek.
refresh period of the display (by default, five seconds), and
the time spent in disk accesses.
Note that the system only keeps statistics on at most four disks.
.Pp
Below the disk display is a list of the

View File

@ -1,4 +1,4 @@
/* $NetBSD: vmstat.c,v 1.4 1995/04/29 05:54:55 cgd Exp $ */
/* $NetBSD: vmstat.c,v 1.5 1996/05/10 23:16:40 thorpej Exp $ */
/*-
* Copyright (c) 1983, 1989, 1992, 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 1/12/94";
#endif
static char rcsid[] = "$NetBSD: vmstat.c,v 1.4 1995/04/29 05:54:55 cgd Exp $";
static char rcsid[] = "$NetBSD: vmstat.c,v 1.5 1996/05/10 23:16:40 thorpej Exp $";
#endif /* not lint */
/*
@ -72,16 +72,15 @@ 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;
} s, s1, s2, z;
#include "dkstats.h"
extern struct _disk cur;
#define cnt s.Cnt
#define oldcnt s1.Cnt
#define total s.Total
@ -215,7 +214,7 @@ initkre()
}
}
hertz = stathz ? stathz : hz;
if (! dkinit())
if (! dkinit(1))
return(0);
if (dk_ndrive && !once) {
#define allocate(e, t) \
@ -223,10 +222,6 @@ initkre()
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
}
@ -331,8 +326,8 @@ labelkre()
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 + 3, DISKCOL, "Kbyte");
mvprintw(DISKROW + 4, DISKCOL, " sec");
j = 0;
for (i = 0; i < dk_ndrive && j < MAXDRIVES; i++)
if (dk_select[i]) {
@ -367,9 +362,9 @@ 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);
}
if (state == TIME)
dkswap();
etime = 0;
for(i = 0; i < CPUSTATES; i++) {
X(time);
@ -617,13 +612,9 @@ getinfo(s, st)
size_t size;
extern int errno;
dkreadstats();
NREAD(X_CPTIME, s->time, sizeof s->time);
NREAD(X_CNT, &s->Cnt, sizeof s->Cnt);
NREAD(X_DK_BUSY, &s->dk_busy, LONG);
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);
@ -649,21 +640,10 @@ static void
copyinfo(from, to)
register struct Info *from, *to;
{
long *time, *wds, *seek, *xfer;
long *intrcnt;
/*
* 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));
}
@ -671,23 +651,18 @@ static void
dinfo(dn, c)
int dn, c;
{
double words, atime, itime, xtime;
double words, atime;
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);
/* time busy in disk activity */
atime = (double)cur.dk_time[dn].tv_sec +
((double)cur.dk_time[dn].tv_usec / (double)1000000);
words = cur.dk_bytes[dn] / 1024.0; /* # of K transferred */
putint((int)((float)cur.dk_seek[dn]/etime+0.5), DISKROW + 1, c, 5);
putint((int)((float)cur.dk_xfer[dn]/etime+0.5), DISKROW + 2, c, 5);
putint((int)(words/etime + 0.5), DISKROW + 3, c, 5);
putfloat(atime/etime, DISKROW + 4, c, 5, 1, 1);
}

View File

@ -1,15 +1,13 @@
# $NetBSD: Makefile,v 1.14 1995/05/07 22:15:57 cgd Exp $
# $NetBSD: Makefile,v 1.15 1996/05/10 23:19:25 thorpej Exp $
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= vmstat
.if (${MACHINE_ARCH} == "m68k")
CFLAGS+=-D${MACHINE}
.endif
CFLAGS+=-I${.CURDIR}/../../sys/arch
SRCS= dkstats.c vmstat.c
MAN= vmstat.8
DPADD= ${LIBKVM}
LDADD= -lkvm
BINGRP= kmem
BINMODE=2555
DPADD= names.c ${LIBKVM}
LDADD= -lkvm
.include <bsd.prog.mk>

271
usr.bin/vmstat/dkstats.c Normal file
View File

@ -0,0 +1,271 @@
/* $NetBSD: dkstats.c,v 1.1 1996/05/10 23:19:27 thorpej Exp $ */
/*
* 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.
*/
#include <sys/dkstat.h>
#include <sys/time.h>
#include <sys/disk.h>
#include <err.h>
#include <fcntl.h>
#include <kvm.h>
#include <limits.h>
#include <nlist.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "dkstats.h"
static struct nlist namelist[] = {
#define X_TK_NIN 0
{ "_tk_nin" }, /* tty characters in */
#define X_TK_NOUT 1
{ "_tk_nout" }, /* tty characters out */
#define X_CP_TIME 2
{ "_cp_time" }, /* system timer ticks */
#define X_HZ 3
{ "_hz" }, /* ticks per second */
#define X_STATHZ 4
{ "_stathz" },
#define X_DISK_COUNT 5
{ "_disk_count" }, /* number of disks */
#define X_DISKLIST 6
{ "_disklist" }, /* TAILQ of disks */
{ NULL },
};
/* Structures to hold the statistics. */
struct _disk cur, last;
/* Kernel pointers: nlistf and memf defined in calling program. */
static kvm_t *kd = NULL;
extern char *nlistf;
extern char *memf;
/* Pointer to list of disks. */
static struct disk *dk_drivehead = NULL;
/* Backward compatibility references. */
int dk_ndrive = 0;
int *dk_select;
char **dr_name;
#define KVM_ERROR(_string) { \
warnx((_string)); \
errx(1, kvm_geterr(kd)); \
}
/*
* Dereference the namelist pointer `v' and fill in the local copy
* 'p' which is of size 's'.
*/
#define deref_nl(v, p, s) deref_kptr((void *)namelist[(v)].n_value, (p), (s));
/* Missing from <sys/time.h> */
#define timerset(tvp, uvp) ((uvp)->tv_sec = (tvp)->tv_sec); \
((uvp)->tv_usec = (tvp)->tv_usec)
void dkswap __P((void));
void dkreadstats __P((void));
int dkinit __P((int));
static void deref_kptr __P((void *, void *, size_t));
/*
* Take the delta between the present values and the last recorded
* values, storing the present values in the 'last' structure, and
* the delta values in the 'cur' structure.
*/
void
dkswap()
{
#define SWAP(fld) tmp = cur.fld; \
cur.fld -= last.fld; \
last.fld = tmp
u_int64_t tmp;
int i;
for (i = 0; i < dk_ndrive; i++) {
struct timeval tmp_timer;
if (!cur.dk_select[i])
continue;
/* Delta Values. */
SWAP(dk_xfer[i]);
SWAP(dk_seek[i]);
SWAP(dk_bytes[i]);
/* Delta Time. */
timerclear(&tmp_timer);
timerset(&(cur.dk_time[i]), &tmp_timer);
timersub(&tmp_timer, &(last.dk_time[i]), &(cur.dk_time[i]));
timerclear(&(last.dk_time[i]));
timerset(&tmp_timer, &(last.dk_time[i]));
}
for (i = 0; i < CPUSTATES; i++) {
SWAP(cp_time[i]);
}
SWAP(tk_nin);
SWAP(tk_nout);
#undef SWAP
}
/*
* Read the disk statistics for each disk in the disk list.
* Also collect statistics for tty i/o and cpu ticks.
*/
void
dkreadstats()
{
struct disk cur_disk, *p;
int i;
p = dk_drivehead;
for (i = 0; i < dk_ndrive; i++) {
deref_kptr(p, &cur_disk, sizeof(cur_disk));
cur.dk_xfer[i] = cur_disk.dk_xfer;
cur.dk_seek[i] = cur_disk.dk_seek;
cur.dk_bytes[i] = cur_disk.dk_bytes;
timerset(&(cur_disk.dk_time), &(cur.dk_time[i]));
p = cur_disk.dk_link.tqe_next;
}
deref_nl(X_CP_TIME, cur.cp_time, sizeof(cur.cp_time));
deref_nl(X_TK_NIN, &cur.tk_nin, sizeof(cur.tk_nin));
deref_nl(X_TK_NOUT, &cur.tk_nout, sizeof(cur.tk_nout));
}
/*
* Perform all of the initialization and memory allocation needed to
* track disk statistics.
*/
int
dkinit(select)
int select;
{
struct disklist_head disk_head;
struct disk cur_disk, *p;
char errbuf[_POSIX2_LINE_MAX];
static int once = 0;
extern int hz;
int i;
if (once)
return(1);
/* Open the kernel. */
if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
errx(1, "kvm_openfiles: %s", errbuf);
/* Obtain the namelist symbols from the kernel. */
if (kvm_nlist(kd, namelist))
KVM_ERROR("kvm_nlist failed to read symbols.");
/* Get the number of attached drives. */
deref_nl(X_DISK_COUNT, &dk_ndrive, sizeof(dk_ndrive));
if (dk_ndrive < 0)
errx(1, "invalid _disk_count %d.", dk_ndrive);
else if (dk_ndrive == 0) {
warnx("No drives attached.");
}
else {
/* Get a pointer to the first disk. */
deref_nl(X_DISKLIST, &disk_head, sizeof(disk_head));
dk_drivehead = disk_head.tqh_first;
}
/* Get ticks per second. */
deref_nl(X_STATHZ, &hz, sizeof(hz));
if (!hz)
deref_nl(X_HZ, &hz, sizeof(hz));
/* allocate space for the statistics */
cur.dk_time = calloc(dk_ndrive, sizeof(struct timeval));
cur.dk_xfer = calloc(dk_ndrive, sizeof(u_int64_t));
cur.dk_seek = calloc(dk_ndrive, sizeof(u_int64_t));
cur.dk_bytes = calloc(dk_ndrive, sizeof(u_int64_t));
last.dk_time = calloc(dk_ndrive, sizeof(struct timeval));
last.dk_xfer = calloc(dk_ndrive, sizeof(u_int64_t));
last.dk_seek = calloc(dk_ndrive, sizeof(u_int64_t));
last.dk_bytes = calloc(dk_ndrive, sizeof(u_int64_t));
cur.dk_select = calloc(dk_ndrive, sizeof(int));
cur.dk_name = calloc(dk_ndrive, sizeof(char *));
if (!cur.dk_time || !cur.dk_xfer || !cur.dk_seek || !cur.dk_bytes
|| !last.dk_time || !last.dk_xfer || !last.dk_seek || !last.dk_bytes
|| !cur.dk_select || !cur.dk_name)
errx(1, "Memory allocation failure.");
/* Set up the compatibility interfaces. */
dk_select = cur.dk_select;
dr_name = cur.dk_name;
/* Read the disk names and set intial selection. */
p = dk_drivehead;
for (i = 0; i < dk_ndrive; i++) {
char buf[10];
deref_kptr(p, &cur_disk, sizeof(cur_disk));
deref_kptr(cur_disk.dk_name, buf, sizeof(buf));
cur.dk_name[i] = strdup(buf);
cur.dk_select[i] = select;
p = cur_disk.dk_link.tqe_next;
}
/* Never do this initalization again. */
once = 1;
return(1);
}
/*
* Dereference the kernel pointer `kptr' and fill in the local copy
* pointed to by `ptr'. The storage space must be pre-allocated,
* and the size of the copy passed in `len'.
*/
static void
deref_kptr(kptr, ptr, len)
void *kptr, *ptr;
size_t len;
{
char buf[128];
if (kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len) {
bzero(buf, sizeof(buf));
snprintf(buf, (sizeof(buf) - 1),
"can't dereference kptr 0x%lx", (u_long)kptr);
KVM_ERROR(buf);
}
}

49
usr.bin/vmstat/dkstats.h Normal file
View File

@ -0,0 +1,49 @@
/* $NetBSD: dkstats.h,v 1.1 1996/05/10 23:19:28 thorpej Exp $ */
/*
* 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.
*/
#include <sys/time.h>
#include <unistd.h>
/* poseur disk entry to hold the information we're interested in. */
struct _disk {
int *dk_select; /* Display stats for selected disks. */
char **dk_name; /* Disk names (sd0, wd1, etc). */
u_int64_t *dk_xfer; /* # of transfers. */
u_int64_t *dk_seek; /* # of seeks (currently unused). */
u_int64_t *dk_bytes; /* # of bytes transfered. */
struct timeval *dk_time; /* Time spent in disk i/o. */
long tk_nin; /* TTY Chars in. */
long tk_nout; /* TTY Chars out. */
long cp_time[CPUSTATES]; /* System timer ticks. */
};

View File

@ -1,245 +0,0 @@
/* $NetBSD: names.c,v 1.19 1996/04/01 21:45:25 mark Exp $ */
/*-
* Copyright (c) 1991, 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.
*
* @(#)names.c 8.1 (Berkeley) 6/6/93
*/
#if !defined(hp300) && !defined(tahoe) && !defined(luna68k) && !defined(mips)
char *defdrives[] = { 0 };
#endif
#if defined(i386)
int
read_names()
{
return 1;
}
#endif
#if defined(arm32)
int
read_names()
{
return 1;
}
#endif
#if defined(pc532)
int
read_names()
{
return 1;
}
#endif
#if defined(sparc)
int
read_names()
{
return 1;
}
#endif
#if defined(m68k) && !defined(hp300)
int
read_names()
{
return(1);
}
#endif
#if defined(__alpha__)
int
read_names()
{
return 1;
}
#endif
#if defined(vax)
int
read_names()
{
return 1;
}
#endif
#if defined(hp300) || defined(luna68k)
#if defined(hp300)
#include <hp300/dev/device.h>
#else
#include <luna68k/dev/device.h>
#endif
char *defdrives[] = { "sd0", "sd1", "sd2", "rd0", "rd1", "rd2", 0 };
int
read_names()
{
register char *p;
register u_long hp;
static char buf[BUFSIZ];
struct hp_device hdev;
struct driver hdrv;
char name[10];
hp = namelist[X_HPDINIT].n_value;
if (hp == 0) {
(void)fprintf(stderr,
"disk init info not in namelist\n");
return (0);
}
p = buf;
for (;; hp += sizeof hdev) {
(void)kvm_read(kd, hp, &hdev, sizeof hdev);
if (hdev.hp_driver == 0)
break;
if (hdev.hp_dk < 0 || hdev.hp_alive == 0 ||
hdev.hp_cdriver == 0)
continue;
(void)kvm_read(kd, (u_long)hdev.hp_driver, &hdrv, sizeof hdrv);
(void)kvm_read(kd, (u_long)hdrv.d_name, name, sizeof name);
dr_name[hdev.hp_dk] = p;
p += sprintf(p, "%s%d", name, hdev.hp_unit) + 1;
}
return (1);
}
#endif /* hp300 || luna68k */
#ifdef tahoe
#include <tahoe/vba/vbavar.h>
char *defdrives[] = { "dk0", "dk1", "dk2", 0 };
int
read_names()
{
register char *p;
struct vba_device udev, *up;
struct vba_driver udrv;
char name[10];
static char buf[BUFSIZ];
up = (struct vba_device *)namelist[X_VBDINIT].n_value;
if (up == 0) {
(void) fprintf(stderr,
"disk init info not in namelist\n");
return (0);
}
p = buf;
for (;; up += sizeof udev) {
(void)kvm_read(kd, up, &udev, sizeof udev);
if (udev.ui_driver == 0)
break;
if (udev.ui_dk < 0 || udev.ui_alive == 0)
continue;
(void)kvm_read(kd, udev.ui_driver, &udrv, sizeof udrv);
(void)kvm_read(kd, udrv.ud_dname, name, sizeof name);
dr_name[udev.ui_dk] = p;
p += sprintf(p, "%s%d", name, udev.ui_unit);
}
return (1);
}
#endif /* tahoe */
#ifdef sun
#include <sundev/mbvar.h>
int
read_names()
{
static int once = 0;
struct mb_device mdev;
struct mb_driver mdrv;
short two_char;
char *cp = (char *) &two_char;
register struct mb_device *mp;
mp = (struct mb_device *)namelist[X_MBDINIT].n_value;
if (mp == 0) {
(void)fprintf(stderr,
"disk init info not in namelist\n");
return (0);
}
for (;; ++mp) {
(void)kvm_read(kd, mp++, &mdev, sizeof(mdev));
if (mdev.md_driver == 0)
break;
if (mdev.md_dk < 0 || mdev.md_alive == 0)
continue;
(void)kvm_read(kd, mdev.md_driver, &mdrv, sizeof(mdrv));
(void)kvm_read(kd, mdrv.mdr_dname, &two_char, sizeof(two_char));
(void)sprintf(dr_name[mdev.md_dk],
"%c%c%d", cp[0], cp[1], mdev.md_unit);
}
return(1);
}
#endif /* sun */
#if defined(mips)
#include <pmax/dev/device.h>
char *defdrives[] = { "rz0", "rz1", "rz2", "rz3", "rz4", "rz5", "rz6", 0 };
int
read_names()
{
register char *p;
register u_long sp;
static char buf[BUFSIZ];
struct pmax_scsi_device sdev;
struct pmax_driver hdrv;
char name[10];
sp = namelist[X_SCSI_DINIT].n_value;
if (sp == 0) {
(void)fprintf(stderr, "disk init info not in namelist\n");
return (0);
}
p = buf;
for (;; sp += sizeof sdev) {
(void)kvm_read(kd, sp, &sdev, sizeof sdev);
if (sdev.sd_driver == 0)
break;
if (sdev.sd_dk < 0 || sdev.sd_alive == 0 ||
sdev.sd_cdriver == 0)
continue;
(void)kvm_read(kd, (u_long)sdev.sd_driver, &hdrv, sizeof hdrv);
(void)kvm_read(kd, (u_long)hdrv.d_name, name, sizeof name);
dr_name[sdev.sd_dk] = p;
p += sprintf(p, "%s%d", name, sdev.sd_unit) + 1;
}
return (1);
}
#endif /* mips */

View File

@ -1,4 +1,4 @@
.\" $NetBSD: vmstat.8,v 1.11 1995/08/10 23:29:47 jtc Exp $
.\" $NetBSD: vmstat.8,v 1.12 1996/05/10 23:19:30 thorpej Exp $
.\"
.\" Copyright (c) 1986, 1993
.\" The Regents of the University of California. All rights reserved.
@ -76,7 +76,7 @@ startup.
.TP
\-M
Extract values associated with the name list from the specified core
instead of the default ``/dev/kmem''.
instead of the default ``/dev/mem''.
.TP
\-N
Extract the name list from the specified system instead of the default
@ -150,7 +150,7 @@ sr pages scanned by clock algorithm, per-second
.RE
.TP
disks
Disk operations per second (this field is system dependent).
Disk transfers per second.
Typically paging will be split across the available drives.
The header of the field is the first character of the disk name and
the unit number.
@ -189,10 +189,10 @@ 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.
.SH FILES
.ta \w'/dev/kmem 'u
.ta \w'/dev/mem 'u
/netbsd default kernel namelist
.br
/dev/kmem default memory file
/dev/mem default memory file
.SH SEE ALSO
.IR fstat (1),
.IR netstat (1),

View File

@ -1,4 +1,4 @@
/* $NetBSD: vmstat.c,v 1.28 1996/04/04 00:27:50 cgd Exp $ */
/* $NetBSD: vmstat.c,v 1.29 1996/05/10 23:19:32 thorpej Exp $ */
/*
* Copyright (c) 1980, 1986, 1991, 1993
@ -43,7 +43,7 @@ static char copyright[] =
#if 0
static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93";
#else
static char rcsid[] = "$NetBSD: vmstat.c,v 1.28 1996/04/04 00:27:50 cgd Exp $";
static char rcsid[] = "$NetBSD: vmstat.c,v 1.29 1996/05/10 23:19:32 thorpej Exp $";
#endif
#endif /* not lint */
@ -72,6 +72,7 @@ static char rcsid[] = "$NetBSD: vmstat.c,v 1.28 1996/04/04 00:27:50 cgd Exp $";
#include <string.h>
#include <paths.h>
#include <limits.h>
#include "dkstats.h"
#define NEWVM /* XXX till old has been updated or purged */
struct nlist namelist[] = {
@ -120,14 +121,6 @@ struct nlist namelist[] = {
#else
#define X_END 15
#endif
#if defined(hp300) || defined(luna68k)
#define X_HPDINIT (X_END)
{ "_hp_dinit" },
#endif
#ifdef mips
#define X_SCSI_DINIT (X_END)
{ "_scsi_dinit" },
#endif
#ifdef tahoe
#define X_VBDINIT (X_END)
{ "_vbdinit" },
@ -143,14 +136,13 @@ struct nlist namelist[] = {
{ "" },
};
struct _disk {
long time[CPUSTATES];
long *xfer;
} cur, last;
/* Objects defined in dkstats.c */
extern struct _disk cur;
extern char **dr_name;
extern int *dk_select, dk_ndrive;
struct vmmeter sum, osum;
char **dr_name;
int *dr_select, dk_ndrive, ndrives;
int ndrives;
int winlines = 20;
@ -163,14 +155,24 @@ kvm_t *kd;
#define TIMESTAT 0x10
#define VMSTAT 0x20
#include "names.c" /* disk names -- machine dependent */
void cpustats(), dkstats(), dointr(), domem(), dosum();
void dovmstat(), kread(), usage();
void cpustats __P((void));
void dkstats __P((void));
void dointr __P((void));
void domem __P((void));
void dosum __P((void));
void dovmstat __P((u_int, int));
void kread __P((int, void *, size_t));
void usage __P((void));
#ifdef notdef
void dotimes(), doforkst();
void dotimes __P((void));
void doforkst __P((void));
#endif
char **choosedrives __P((char **));
/* Namelist and memory file names. */
char *nlistf, *memf;
main(argc, argv)
register int argc;
register char **argv;
@ -180,7 +182,6 @@ main(argc, argv)
register int c, todo;
u_int interval;
int reps;
char *memf, *nlistf;
char errbuf[_POSIX2_LINE_MAX];
memf = nlistf = NULL;
@ -260,10 +261,10 @@ main(argc, argv)
}
if (todo & VMSTAT) {
char **getdrivedata();
struct winsize winsize;
argv = getdrivedata(argv);
dkinit(0); /* Initialize disk stats, no disks selected. */
argv = choosedrives(argv); /* Select disks. */
winsize.ws_row = 0;
(void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize);
if (winsize.ws_row > 0)
@ -306,32 +307,13 @@ main(argc, argv)
}
char **
getdrivedata(argv)
choosedrives(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) {
(void)fprintf(stderr, "vmstat: dk_ndrive %d\n", dk_ndrive);
exit(1);
}
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);
}
/*
* Choose drives to be displayed. Priority goes to (in order) drives
* supplied as arguments, default drives. If everything isn't filled
@ -347,25 +329,15 @@ getdrivedata(argv)
for (i = 0; i < dk_ndrive; i++) {
if (strcmp(dr_name[i], *argv))
continue;
dr_select[i] = 1;
dk_select[i] = 1;
++ndrives;
break;
}
}
for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
if (dr_select[i])
if (dk_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;
dk_select[i] = 1;
++ndrives;
}
return(argv);
@ -414,8 +386,8 @@ dovmstat(interval, reps)
for (hdrcnt = 1;;) {
if (!--hdrcnt)
printhdr();
kread(X_CPTIME, cur.time, sizeof(cur.time));
kread(X_DKXFER, cur.xfer, sizeof(*cur.xfer) * dk_ndrive);
/* Read new disk statistics */
dkreadstats();
kread(X_SUM, &sum, sizeof(sum));
size = sizeof(total);
mib[0] = CTL_VM;
@ -426,7 +398,7 @@ dovmstat(interval, reps)
}
(void)printf("%2d%2d%2d",
total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
#define pgtok(a) ((a) * sum.v_page_size >> 10)
#define pgtok(a) ((a) * (sum.v_page_size >> 10))
#define rate(x) (((x) + halfuptime) / uptime) /* round */
(void)printf("%6ld%6ld ",
pgtok(total.t_avm), pgtok(total.t_free));
@ -477,18 +449,29 @@ printhdr()
register int i;
(void)printf(" procs memory page%*s", 20, "");
if (ndrives > 1)
(void)printf("disks %*s faults cpu\n",
ndrives * 3 - 6, "");
else
(void)printf("%*s faults cpu\n", ndrives * 3, "");
#ifndef NEWVM
(void)printf(" r b w avm fre re at pi po fr de sr ");
if (ndrives > 0)
#ifdef NEWVM
(void)printf("%s %*sfaults cpu\n",
((ndrives > 1) ? "disks" : "disk"),
#else
(void)printf("disks %*sfaults cpu\n",
#endif
((ndrives > 1) ? ndrives * 3 - 4 : 0), "");
else
#ifdef NEWVM
(void)printf("%*s faults cpu\n",
#else
(void)printf("%*s faults cpu\n",
#endif
ndrives * 3, "");
#ifdef NEWVM
(void)printf(" r b w avm fre flt re pi po fr sr ");
#else
(void)printf(" r b w avm fre re at pi po fr de sr ");
#endif
for (i = 0; i < dk_ndrive; i++)
if (dr_select[i])
if (dk_select[i])
(void)printf("%c%c ", dr_name[i][0],
dr_name[i][strlen(dr_name[i]) - 1]);
(void)printf(" in sy cs us sy id\n");
@ -668,25 +651,19 @@ dkstats()
double etime;
long tmp;
for (dn = 0; dn < dk_ndrive; ++dn) {
tmp = cur.xfer[dn];
cur.xfer[dn] -= last.xfer[dn];
last.xfer[dn] = tmp;
}
/* Calculate disk stat deltas. */
dkswap();
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];
etime += cur.cp_time[state];
}
if (etime == 0)
etime = 1;
etime /= hz;
for (dn = 0; dn < dk_ndrive; ++dn) {
if (!dr_select[dn])
if (!dk_select[dn])
continue;
(void)printf("%2.0f ", cur.xfer[dn] / etime);
(void)printf("%2.0f ", cur.dk_xfer[dn] / etime);
}
}
@ -698,14 +675,14 @@ 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);
}
#if defined(pc532)

View File

@ -1,13 +1,16 @@
# $NetBSD: Makefile,v 1.12 1995/12/22 08:04:27 jonathan Exp $
# $NetBSD: Makefile,v 1.13 1996/05/10 23:20:26 thorpej Exp $
# from: @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= iostat
.if (${MACHINE_ARCH} == "m68k")
CFLAGS+=-D${MACHINE}
.endif
CFLAGS+= -I${.CURDIR}/../../sys/arch -I${.CURDIR}/../../usr.bin/vmstat
MAN= iostat.8
.PATH: ${.CURDIR}/../../usr.bin/vmstat
CFLAGS+=-I${.CURDIR}/../../usr.bin/vmstat
# dkstats.c pulled in from ../../usr.bin/vmstat
SRCS= dkstats.c iostat.c
DPADD= ${LIBKVM}
LDADD= -lkvm
BINGRP= kmem

View File

@ -1,4 +1,4 @@
.\" $NetBSD: iostat.8,v 1.8 1995/11/28 20:16:30 thorpej Exp $
.\" $NetBSD: iostat.8,v 1.9 1996/05/10 23:20:28 thorpej Exp $
.\"
.\" Copyright (c) 1985, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -33,9 +33,9 @@
.\"
.\" from: @(#)iostat.8 8.1 (Berkeley) 6/6/93
.\"
.Dd June 6, 1993
.Dd Jan 18, 1996
.Dt IOSTAT 8
.Os BSD 4
.Os NetBSD 1.1
.Sh NAME
.Nm iostat
.Nd report
@ -43,6 +43,7 @@
statistics
.Sh SYNOPSIS
.Nm iostat
.Op Fl CdDIT
.Op Fl c Ar count
.Op Fl M Ar core
.Op Fl N Ar system
@ -52,8 +53,19 @@ statistics
.Nm Iostat
displays kernel
.Tn I/O
statistics on terminal, disk and cpu
operations.
statistics on terminal, disk and cpu operations. By default,
.Nm iostat
displays one line of statistics averaged over the machine's run time.
The use of
.Fl c
presents successive lines averaged over the
.Ar wait
period.
The
.Fl I
option causes
.Nm iostat
to print raw, unaveraged values.
.Pp
The options are as follows:
.Bl -tag -width flag
@ -61,18 +73,44 @@ The options are as follows:
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.
Unless the
.Fl I
flag is in effect, 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
.Ar wait
interval is specified, the default is 1 second.
.It Fl C
Show cpu statistics. This is enabled by default unless the
.Fl d,
.Fl D,
or
.Fl T
flags are used.
.It Fl d
Show disk statistics. This is the default. Displays kilobytes per
transfer, number of transfers, and megabytes transfered. Use of this
flag disables display of cpu and tty statistics.
.It Fl D
Show alternate disk statistics. Displays kilobytes transfered, number of
transfers, and time spent in transfers. Use of this flag disables the
default display.
.It Fl I
Show the running total values, rather than an average.
.It Fl M
Extract values associated with the name list from the specified core
instead of the default
.Dq Pa /dev/kmem .
.Dq Pa /dev/mem .
.It Fl N
Extract the name list from the specified system instead of the default
.Dq Pa /netbsd .
.It Fl T
Show tty statistics. This is enabled by default unless the
.Fl C,
.Fl d,
or
.Fl D
flags are used.
.It Fl w
Pause
.Ar wait
@ -93,7 +131,7 @@ characters read from terminals
characters written to terminals
.El
.It disks
Disk operations (this field is system dependent).
Disk operations.
The header of the field is the disk name and unit number.
If more than four disk drives are configured in the system,
.Nm iostat
@ -104,13 +142,24 @@ to display specific drives, their names may be supplied on the command
line.
.Pp
.Bl -tag -width indent -compact
.It sps
sectors transferred per second
.It tps
.It K/t
Kilobytes transferred per disk transfer
.It t/s
transfers per second
.It msps
milliseconds per average seek (including implied
seeks and rotational latency)
.It Mb/s
Megabytes transferred per second
.Pp
.El
The alternate display format, (selected with
.Fl D
), presents the following values.
.Bl -tag -width indent -compact
.It Kb
Kilobytes transferred
.It xfr
Disk transfers
.It time
Seconds spent in disk activity
.El
.It cpu
.Bl -tag -width indent -compact
@ -125,10 +174,10 @@ seeks and rotational latency)
.El
.El
.Sh FILES
.Bl -tag -width /dev/kmem -compact
.Bl -tag -width /dev/mem -compact
.It Pa /netbsd
Default kernel namelist.
.It Pa /dev/kmem
.It Pa /dev/mem
Default memory file.
.El
.Sh SEE ALSO

View File

@ -1,8 +1,8 @@
/* $NetBSD: iostat.c,v 1.8 1995/11/28 20:16:31 thorpej Exp $ */
/* $NetBSD: iostat.c,v 1.9 1996/05/10 23:20:29 thorpej Exp $ */
/*-
* Copyright (c) 1986, 1991, 1993
* The Regents of the University of California. All rights reserved.
/*
* 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
@ -14,8 +14,40 @@
* 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.
* 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.
*/
/*-
* Copyright (c) 1986, 1991, 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.
@ -36,130 +68,95 @@
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1986, 1991, 1993\n\
The Regents of the University of California. All rights reserved.\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";
static char sccsid[] = "@(#)iostat.c 8.2 (Berkeley) 1/26/94";
#else
static char *rcsid = "$NetBSD: iostat.c,v 1.8 1995/11/28 20:16:31 thorpej Exp $";
static char *rcsid = "$NetBSD: iostat.c,v 1.9 1996/05/10 23:20:29 thorpej Exp $"
;
#endif
#endif /* not lint */
#include <sys/param.h>
#include <sys/buf.h>
#include <sys/dkstat.h>
#include <sys/time.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>
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
{ "_tk_nin" },
#define X_TK_NOUT 4
{ "_tk_nout" },
#define X_DK_SEEK 5
{ "_dk_seek" },
#define X_CP_TIME 6
{ "_cp_time" },
#define X_DK_WPMS 7
{ "_dk_wpms" },
#define X_HZ 8
{ "_hz" },
#define X_STATHZ 9
{ "_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
#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
{ NULL },
};
#include "dkstats.h"
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;
/* Defined in dkstats.c */
extern struct _disk cur;
extern int dk_ndrive;
kvm_t *kd;
double etime;
long *dk_wpms;
int dk_ndrive, *dr_select, hz, kmemfd, ndrives;
char **dr_name;
/* Namelist and memory files. */
char *nlistf, *memf;
#define nlread(x, v) \
kvm_read(kd, namelist[x].n_value, &(v), sizeof(v))
int hz, reps, interval;
static int todo = 0;
#include "names.c" /* XXX */
#define ISSET(x, a) ((x) & (a))
#define SHOW_CPU 0x0001
#define SHOW_TTY 0x0002
#define SHOW_STATS_1 0x0004
#define SHOW_STATS_2 0x0008
#define SHOW_TOTALS 0x0080
void cpustats __P((void));
void dkstats __P((void));
void phdr __P((int));
void usage __P((void));
static void cpustats __P((void));
static void disk_stats __P((double));
static void disk_stats2 __P((double));
static void header __P((int));
static void usage __P((void));
static void display __P((void));
static void selectdrives __P((int, char **));
void dkswap __P((void));
void dkreadstats __P((void));
int dkinit __P((int));
int
main(argc, argv)
int argc;
char *argv[];
{
register int i;
long tmp;
int ch, hdrcnt, reps, interval, stathz, ndrives;
char **cp, *memf, *nlistf, buf[30];
char errbuf[_POSIX2_LINE_MAX];
int ch, hdrcnt;
struct timeval tv;
interval = reps = 0;
nlistf = memf = NULL;
while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF)
while ((ch = getopt(argc, argv, "Cc:dDIM:N:Tw:")) != EOF)
switch(ch) {
case 'c':
if ((reps = atoi(optarg)) <= 0)
errx(1, "repetition count <= 0.");
break;
case 'C':
todo |= SHOW_CPU;
break;
case 'd':
todo |= SHOW_STATS_1;
break;
case 'D':
todo |= SHOW_STATS_2;
break;
case 'I':
todo |= SHOW_TOTALS;
break;
case 'M':
memf = optarg;
break;
case 'N':
nlistf = optarg;
break;
case 'T':
todo |= SHOW_TTY;
break;
case 'w':
if ((interval = atoi(optarg)) <= 0)
errx(1, "interval <= 0.");
@ -171,6 +168,9 @@ main(argc, argv)
argc -= optind;
argv += optind;
if (!ISSET(todo, SHOW_CPU | SHOW_TTY | SHOW_STATS_1 | SHOW_STATS_2))
todo |= SHOW_CPU | SHOW_TTY | SHOW_STATS_1;
/*
* Discard setgid privileges if not the running kernel so that bad
* guys can't print interesting stuff from kernel memory.
@ -178,41 +178,206 @@ main(argc, argv)
if (nlistf != NULL || memf != NULL)
setgid(getgid());
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\n", dk_ndrive);
dkinit(0);
dkreadstats();
selectdrives(argc, argv);
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));
tv.tv_sec = interval;
tv.tv_usec = 0;
for (i = 0; i < dk_ndrive; i++) {
(void)sprintf(buf, "dk%d", i);
dr_name[i] = strdup(buf);
/* print a new header on sigcont */
(void)signal(SIGCONT, header);
for (hdrcnt = 1;;) {
if (!--hdrcnt) {
header(0);
hdrcnt = 20;
}
if (!ISSET(todo, SHOW_TOTALS))
dkswap();
display();
if (reps >= 0 && --reps <= 0)
break;
select(0, NULL, NULL, NULL, &tv);
dkreadstats();
}
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));
exit(0);
}
static void
header(signo)
int signo;
{
register int i;
/* Main Headers. */
if (ISSET(todo, SHOW_TTY))
(void)printf(" tty");
if (ISSET(todo, SHOW_STATS_1))
for (i = 0; i < dk_ndrive; i++)
if (cur.dk_select[i])
(void)printf(" %3.3s ", cur.dk_name[i]);
if (ISSET(todo, SHOW_STATS_2))
for (i = 0; i < dk_ndrive; i++)
if (cur.dk_select[i])
(void)printf(" %3.3s ", cur.dk_name[i]);
if (ISSET(todo, SHOW_CPU))
(void)printf(" cpu");
printf("\n");
/* Sub-Headers. */
if (ISSET(todo, SHOW_TTY))
printf(" tin tout");
if (ISSET(todo, SHOW_STATS_1))
for (i = 0; i < dk_ndrive; i++)
if (cur.dk_select[i])
if (ISSET(todo, SHOW_TOTALS))
(void)printf(" K/t xfr Mb ");
else
(void)printf(" K/t t/s Mb/s ");
if (ISSET(todo, SHOW_STATS_2))
for (i = 0; i < dk_ndrive; i++)
if (cur.dk_select[i])
(void)printf(" Kb xfr time ");
if (ISSET(todo, SHOW_CPU))
(void)printf(" us ni sy in id");
printf("\n");
}
static void
disk_stats(etime)
double etime;
{
register int dn;
double atime, mbps;
for (dn = 0; dn < dk_ndrive; ++dn) {
if (!cur.dk_select[dn])
continue;
/* average Kbytes per transfer. */
if (cur.dk_xfer[dn])
mbps = (cur.dk_bytes[dn] / (1024.0)) / cur.dk_xfer[dn];
else
mbps = 0.0;
(void)printf(" %5.2f", mbps);
/* average transfers per second. */
(void)printf(" %3.0f", cur.dk_xfer[dn] / etime);
/* time busy in disk activity */
atime = (double)cur.dk_time[dn].tv_sec +
((double)cur.dk_time[dn].tv_usec / (double)1000000);
/* Megabytes per second. */
if (atime != 0.0)
mbps = cur.dk_bytes[dn] / (double)(1024 * 1024);
else
mbps = 0;
(void)printf(" %4.2f ", mbps / etime);
}
}
static void
disk_stats2(etime)
double etime;
{
register int dn;
double atime;
for (dn = 0; dn < dk_ndrive; ++dn) {
if (!cur.dk_select[dn])
continue;
/* average kbytes per second. */
(void)printf(" %4.0f", cur.dk_bytes[dn] / (1024.0) / etime);
/* average transfers per second. */
(void)printf(" %3.0f", cur.dk_xfer[dn] / etime);
/* average time busy in disk activity. */
atime = (double)cur.dk_time[dn].tv_sec +
((double)cur.dk_time[dn].tv_usec / (double)1000000);
(void)printf(" %4.2f ", atime / etime);
}
}
static void
cpustats()
{
register int state;
double time;
time = 0;
for (state = 0; state < CPUSTATES; ++state)
time += cur.cp_time[state];
if (!time)
time = 1.0;
/* States are generally never 100% and can use %3.0f. */
for (state = 0; state < CPUSTATES; ++state)
printf("%3.0f", 100. * cur.cp_time[state] / time);
}
static void
usage()
{
(void)fprintf(stderr,
"usage: iostat [-CdDIT] [-c count] [-M core] [-N system] [-w wait] [drives]\n");
exit(1);
}
static void
display()
{
int i;
double etime;
/* Sum up the elapsed ticks. */
etime = 0.0;
for (i = 0; i < CPUSTATES; i++) {
etime += cur.cp_time[i];
}
if (etime == 0.0)
etime = 1.0;
/* Convert to seconds. */
etime /= (float)hz;
/* If we're showing totals only, then don't divide by the
* system time.
*/
if (ISSET(todo, SHOW_TOTALS))
etime = 1.0;
if (ISSET(todo, SHOW_TTY))
printf("%4.0f %4.0f", cur.tk_nin / etime, cur.tk_nout / etime);
if (ISSET(todo, SHOW_STATS_1))
disk_stats(etime);
if (ISSET(todo, SHOW_STATS_2))
disk_stats2(etime);
if (ISSET(todo, SHOW_CPU))
cpustats();
(void)printf("\n");
(void)fflush(stdout);
}
static void
selectdrives(argc, argv)
int argc;
char *argv[];
{
int i, ndrives;
/*
* Choose drives to be displayed. Priority goes to (in order) drives
@ -230,9 +395,9 @@ main(argc, argv)
break;
#endif
for (i = 0; i < dk_ndrive; i++) {
if (strcmp(dr_name[i], *argv))
if (strcmp(cur.dk_name[i], *argv))
continue;
dr_select[i] = 1;
cur.dk_select[i] = 1;
++ndrives;
}
}
@ -251,147 +416,12 @@ main(argc, argv)
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) {
phdr(0);
hdrcnt = 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])
/* Pick up to 4 drives if none specified. */
if (ndrives == 0)
for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
if (cur.dk_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);
cur.dk_select[i] = 1;
++ndrives;
}
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;
for (i = 0; i < CPUSTATES; i++) {
X(cp_time);
etime += cur.cp_time[i];
}
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 (reps >= 0 && --reps <= 0)
break;
(void)sleep(interval);
}
exit(0);
}
/* ARGUSED */
void
phdr(signo)
int signo;
{
register int i;
(void)printf(" tty");
for (i = 0; i < dk_ndrive; i++)
if (dr_select[i])
(void)printf(" %3.3s ", 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()
{
register int dn;
double atime, itime, msps, words, xtime;
for (dn = 0; dn < dk_ndrive; ++dn) {
if (!dr_select[dn])
continue;
words = 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);
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);
}
}
void
cpustats()
{
register int state;
double time;
time = 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));
}
void
usage()
{
(void)fprintf(stderr,
"usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n");
exit(1);
}