Home | History | Annotate | Line # | Download | only in iostat
iostat.c revision 1.1.1.1
      1      1.1  cgd /*-
      2  1.1.1.1  cgd  * Copyright (c) 1986, 1991, 1993
      3  1.1.1.1  cgd  *	The Regents of the University of California.  All rights reserved.
      4      1.1  cgd  *
      5      1.1  cgd  * Redistribution and use in source and binary forms, with or without
      6      1.1  cgd  * modification, are permitted provided that the following conditions
      7      1.1  cgd  * are met:
      8      1.1  cgd  * 1. Redistributions of source code must retain the above copyright
      9      1.1  cgd  *    notice, this list of conditions and the following disclaimer.
     10      1.1  cgd  * 2. Redistributions in binary form must reproduce the above copyright
     11      1.1  cgd  *    notice, this list of conditions and the following disclaimer in the
     12      1.1  cgd  *    documentation and/or other materials provided with the distribution.
     13      1.1  cgd  * 3. All advertising materials mentioning features or use of this software
     14      1.1  cgd  *    must display the following acknowledgement:
     15      1.1  cgd  *	This product includes software developed by the University of
     16      1.1  cgd  *	California, Berkeley and its contributors.
     17      1.1  cgd  * 4. Neither the name of the University nor the names of its contributors
     18      1.1  cgd  *    may be used to endorse or promote products derived from this software
     19      1.1  cgd  *    without specific prior written permission.
     20      1.1  cgd  *
     21      1.1  cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22      1.1  cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23      1.1  cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24      1.1  cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25      1.1  cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26      1.1  cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27      1.1  cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28      1.1  cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29      1.1  cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30      1.1  cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31      1.1  cgd  * SUCH DAMAGE.
     32      1.1  cgd  */
     33      1.1  cgd 
     34      1.1  cgd #ifndef lint
     35  1.1.1.1  cgd static char copyright[] =
     36  1.1.1.1  cgd "@(#) Copyright (c) 1986, 1991, 1993\n\
     37  1.1.1.1  cgd 	The Regents of the University of California.  All rights reserved.\n";
     38      1.1  cgd #endif /* not lint */
     39      1.1  cgd 
     40      1.1  cgd #ifndef lint
     41  1.1.1.1  cgd static char sccsid[] = "@(#)iostat.c	8.2 (Berkeley) 1/26/94";
     42      1.1  cgd #endif /* not lint */
     43      1.1  cgd 
     44      1.1  cgd #include <sys/param.h>
     45      1.1  cgd #include <sys/buf.h>
     46      1.1  cgd #include <sys/dkstat.h>
     47  1.1.1.1  cgd 
     48  1.1.1.1  cgd #include <err.h>
     49  1.1.1.1  cgd #include <ctype.h>
     50      1.1  cgd #include <fcntl.h>
     51  1.1.1.1  cgd #include <kvm.h>
     52  1.1.1.1  cgd #include <limits.h>
     53      1.1  cgd #include <nlist.h>
     54  1.1.1.1  cgd #include <paths.h>
     55  1.1.1.1  cgd #include <signal.h>
     56      1.1  cgd #include <stdio.h>
     57      1.1  cgd #include <stdlib.h>
     58      1.1  cgd #include <string.h>
     59  1.1.1.1  cgd #include <unistd.h>
     60      1.1  cgd 
     61  1.1.1.1  cgd struct nlist namelist[] = {
     62      1.1  cgd #define	X_DK_TIME	0
     63      1.1  cgd 	{ "_dk_time" },
     64      1.1  cgd #define	X_DK_XFER	1
     65      1.1  cgd 	{ "_dk_xfer" },
     66      1.1  cgd #define	X_DK_WDS	2
     67      1.1  cgd 	{ "_dk_wds" },
     68      1.1  cgd #define	X_TK_NIN	3
     69      1.1  cgd 	{ "_tk_nin" },
     70      1.1  cgd #define	X_TK_NOUT	4
     71      1.1  cgd 	{ "_tk_nout" },
     72      1.1  cgd #define	X_DK_SEEK	5
     73      1.1  cgd 	{ "_dk_seek" },
     74      1.1  cgd #define	X_CP_TIME	6
     75      1.1  cgd 	{ "_cp_time" },
     76      1.1  cgd #define	X_DK_WPMS	7
     77      1.1  cgd 	{ "_dk_wpms" },
     78      1.1  cgd #define	X_HZ		8
     79      1.1  cgd 	{ "_hz" },
     80  1.1.1.1  cgd #define	X_STATHZ	9
     81  1.1.1.1  cgd 	{ "_stathz" },
     82      1.1  cgd #define	X_DK_NDRIVE	10
     83      1.1  cgd 	{ "_dk_ndrive" },
     84      1.1  cgd #define	X_END		10
     85  1.1.1.1  cgd #if defined(hp300) || defined(luna68k)
     86      1.1  cgd #define	X_HPDINIT	(X_END+1)
     87      1.1  cgd 	{ "_hp_dinit" },
     88      1.1  cgd #endif
     89  1.1.1.1  cgd #ifdef mips
     90  1.1.1.1  cgd #define	X_SCSI_DINIT	(X_END+1)
     91  1.1.1.1  cgd 	{ "_scsi_dinit" },
     92  1.1.1.1  cgd #endif
     93      1.1  cgd #ifdef tahoe
     94      1.1  cgd #define	X_VBDINIT	(X_END+1)
     95      1.1  cgd 	{ "_vbdinit" },
     96      1.1  cgd #endif
     97      1.1  cgd #ifdef vax
     98      1.1  cgd 	{ "_mbdinit" },
     99      1.1  cgd #define X_MBDINIT	(X_END+1)
    100      1.1  cgd 	{ "_ubdinit" },
    101      1.1  cgd #define X_UBDINIT	(X_END+2)
    102      1.1  cgd #endif
    103      1.1  cgd 	{ NULL },
    104      1.1  cgd };
    105      1.1  cgd 
    106      1.1  cgd struct _disk {
    107      1.1  cgd 	long	cp_time[CPUSTATES];
    108      1.1  cgd 	long	*dk_time;
    109      1.1  cgd 	long	*dk_wds;
    110      1.1  cgd 	long	*dk_seek;
    111      1.1  cgd 	long	*dk_xfer;
    112      1.1  cgd 	long	tk_nin;
    113      1.1  cgd 	long	tk_nout;
    114      1.1  cgd } cur, last;
    115      1.1  cgd 
    116  1.1.1.1  cgd kvm_t	 *kd;
    117  1.1.1.1  cgd double	  etime;
    118  1.1.1.1  cgd long	 *dk_wpms;
    119  1.1.1.1  cgd int	  dk_ndrive, *dr_select, hz, kmemfd, ndrives;
    120  1.1.1.1  cgd char	**dr_name;
    121      1.1  cgd 
    122      1.1  cgd #define nlread(x, v) \
    123  1.1.1.1  cgd 	kvm_read(kd, namelist[x].n_value, &(v), sizeof(v))
    124      1.1  cgd 
    125      1.1  cgd #include "names.c"				/* XXX */
    126      1.1  cgd 
    127  1.1.1.1  cgd void cpustats __P((void));
    128  1.1.1.1  cgd void dkstats __P((void));
    129  1.1.1.1  cgd void phdr __P((int));
    130  1.1.1.1  cgd void usage __P((void));
    131      1.1  cgd 
    132  1.1.1.1  cgd int
    133      1.1  cgd main(argc, argv)
    134      1.1  cgd 	int argc;
    135  1.1.1.1  cgd 	char *argv[];
    136      1.1  cgd {
    137      1.1  cgd 	register int i;
    138      1.1  cgd 	long tmp;
    139  1.1.1.1  cgd 	int ch, hdrcnt, reps, interval, stathz, ndrives;
    140  1.1.1.1  cgd 	char **cp, *memf, *nlistf, buf[30];
    141  1.1.1.1  cgd         char errbuf[_POSIX2_LINE_MAX];
    142      1.1  cgd 
    143      1.1  cgd 	interval = reps = 0;
    144  1.1.1.1  cgd 	nlistf = memf = NULL;
    145      1.1  cgd 	while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF)
    146      1.1  cgd 		switch(ch) {
    147      1.1  cgd 		case 'c':
    148  1.1.1.1  cgd 			if ((reps = atoi(optarg)) <= 0)
    149  1.1.1.1  cgd 				errx(1, "repetition count <= 0.");
    150      1.1  cgd 			break;
    151      1.1  cgd 		case 'M':
    152  1.1.1.1  cgd 			memf = optarg;
    153      1.1  cgd 			break;
    154      1.1  cgd 		case 'N':
    155  1.1.1.1  cgd 			nlistf = optarg;
    156      1.1  cgd 			break;
    157      1.1  cgd 		case 'w':
    158  1.1.1.1  cgd 			if ((interval = atoi(optarg)) <= 0)
    159  1.1.1.1  cgd 				errx(1, "interval <= 0.");
    160      1.1  cgd 			break;
    161      1.1  cgd 		case '?':
    162      1.1  cgd 		default:
    163      1.1  cgd 			usage();
    164      1.1  cgd 		}
    165      1.1  cgd 	argc -= optind;
    166      1.1  cgd 	argv += optind;
    167      1.1  cgd 
    168  1.1.1.1  cgd 	/*
    169  1.1.1.1  cgd 	 * Discard setgid privileges if not the running kernel so that bad
    170  1.1.1.1  cgd 	 * guys can't print interesting stuff from kernel memory.
    171  1.1.1.1  cgd 	 */
    172  1.1.1.1  cgd 	if (nlistf != NULL || memf != NULL)
    173  1.1.1.1  cgd 		setgid(getgid());
    174  1.1.1.1  cgd 
    175  1.1.1.1  cgd         kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
    176  1.1.1.1  cgd 	if (kd == 0)
    177  1.1.1.1  cgd 		errx(1, "kvm_openfiles: %s", errbuf);
    178  1.1.1.1  cgd 	if (kvm_nlist(kd, namelist) == -1)
    179  1.1.1.1  cgd 		errx(1, "kvm_nlist: %s", kvm_geterr(kd));
    180  1.1.1.1  cgd 	if (namelist[X_DK_NDRIVE].n_type == 0)
    181  1.1.1.1  cgd 		errx(1, "dk_ndrive not found in namelist");
    182      1.1  cgd 	(void)nlread(X_DK_NDRIVE, dk_ndrive);
    183      1.1  cgd 	if (dk_ndrive <= 0)
    184  1.1.1.1  cgd 		errx(1, "invalid dk_ndrive %d\n", dk_ndrive);
    185      1.1  cgd 
    186      1.1  cgd 	cur.dk_time = calloc(dk_ndrive, sizeof(long));
    187      1.1  cgd 	cur.dk_wds = calloc(dk_ndrive, sizeof(long));
    188      1.1  cgd 	cur.dk_seek = calloc(dk_ndrive, sizeof(long));
    189      1.1  cgd 	cur.dk_xfer = calloc(dk_ndrive, sizeof(long));
    190      1.1  cgd 	last.dk_time = calloc(dk_ndrive, sizeof(long));
    191      1.1  cgd 	last.dk_wds = calloc(dk_ndrive, sizeof(long));
    192      1.1  cgd 	last.dk_seek = calloc(dk_ndrive, sizeof(long));
    193      1.1  cgd 	last.dk_xfer = calloc(dk_ndrive, sizeof(long));
    194      1.1  cgd 	dr_select = calloc(dk_ndrive, sizeof(int));
    195      1.1  cgd 	dr_name = calloc(dk_ndrive, sizeof(char *));
    196      1.1  cgd 	dk_wpms = calloc(dk_ndrive, sizeof(long));
    197      1.1  cgd 
    198      1.1  cgd 	for (i = 0; i < dk_ndrive; i++) {
    199      1.1  cgd 		(void)sprintf(buf, "dk%d", i);
    200      1.1  cgd 		dr_name[i] = strdup(buf);
    201      1.1  cgd 	}
    202  1.1.1.1  cgd 	if (!read_names())
    203  1.1.1.1  cgd 		exit(1);
    204      1.1  cgd 	(void)nlread(X_HZ, hz);
    205  1.1.1.1  cgd 	(void)nlread(X_STATHZ, stathz);
    206  1.1.1.1  cgd 	if (stathz)
    207  1.1.1.1  cgd 		hz = stathz;
    208  1.1.1.1  cgd 	(void)kvm_read(kd, namelist[X_DK_WPMS].n_value, dk_wpms,
    209      1.1  cgd 		dk_ndrive * sizeof(dk_wpms));
    210      1.1  cgd 
    211      1.1  cgd 	/*
    212      1.1  cgd 	 * Choose drives to be displayed.  Priority goes to (in order) drives
    213      1.1  cgd 	 * supplied as arguments and default drives.  If everything isn't
    214      1.1  cgd 	 * filled in and there are drives not taken care of, display the first
    215      1.1  cgd 	 * few that fit.
    216      1.1  cgd 	 *
    217      1.1  cgd 	 * The backward compatibility #ifdefs permit the syntax:
    218      1.1  cgd 	 *	iostat [ drives ] [ interval [ count ] ]
    219      1.1  cgd 	 */
    220      1.1  cgd #define	BACKWARD_COMPATIBILITY
    221      1.1  cgd 	for (ndrives = 0; *argv; ++argv) {
    222      1.1  cgd #ifdef	BACKWARD_COMPATIBILITY
    223      1.1  cgd 		if (isdigit(**argv))
    224      1.1  cgd 			break;
    225      1.1  cgd #endif
    226      1.1  cgd 		for (i = 0; i < dk_ndrive; i++) {
    227      1.1  cgd 			if (strcmp(dr_name[i], *argv))
    228      1.1  cgd 				continue;
    229      1.1  cgd 			dr_select[i] = 1;
    230      1.1  cgd 			++ndrives;
    231      1.1  cgd 		}
    232      1.1  cgd 	}
    233      1.1  cgd #ifdef	BACKWARD_COMPATIBILITY
    234      1.1  cgd 	if (*argv) {
    235      1.1  cgd 		interval = atoi(*argv);
    236      1.1  cgd 		if (*++argv)
    237      1.1  cgd 			reps = atoi(*argv);
    238      1.1  cgd 	}
    239      1.1  cgd #endif
    240      1.1  cgd 
    241      1.1  cgd 	if (interval) {
    242      1.1  cgd 		if (!reps)
    243      1.1  cgd 			reps = -1;
    244      1.1  cgd 	} else
    245      1.1  cgd 		if (reps)
    246      1.1  cgd 			interval = 1;
    247      1.1  cgd 
    248      1.1  cgd 	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
    249      1.1  cgd 		if (dr_select[i] || dk_wpms[i] == 0)
    250      1.1  cgd 			continue;
    251      1.1  cgd 		for (cp = defdrives; *cp; cp++)
    252      1.1  cgd 			if (strcmp(dr_name[i], *cp) == 0) {
    253      1.1  cgd 				dr_select[i] = 1;
    254      1.1  cgd 				++ndrives;
    255      1.1  cgd 				break;
    256      1.1  cgd 			}
    257      1.1  cgd 	}
    258      1.1  cgd 	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
    259      1.1  cgd 		if (dr_select[i])
    260      1.1  cgd 			continue;
    261      1.1  cgd 		dr_select[i] = 1;
    262      1.1  cgd 		++ndrives;
    263      1.1  cgd 	}
    264      1.1  cgd 
    265      1.1  cgd 	(void)signal(SIGCONT, phdr);
    266      1.1  cgd 
    267      1.1  cgd 	for (hdrcnt = 1;;) {
    268      1.1  cgd 		if (!--hdrcnt) {
    269      1.1  cgd 			phdr(0);
    270      1.1  cgd 			hdrcnt = 20;
    271      1.1  cgd 		}
    272  1.1.1.1  cgd 		(void)kvm_read(kd, namelist[X_DK_TIME].n_value,
    273      1.1  cgd 		    cur.dk_time, dk_ndrive * sizeof(long));
    274  1.1.1.1  cgd 		(void)kvm_read(kd, namelist[X_DK_XFER].n_value,
    275      1.1  cgd 		    cur.dk_xfer, dk_ndrive * sizeof(long));
    276  1.1.1.1  cgd 		(void)kvm_read(kd, namelist[X_DK_WDS].n_value,
    277      1.1  cgd 		    cur.dk_wds, dk_ndrive * sizeof(long));
    278  1.1.1.1  cgd 		(void)kvm_read(kd, namelist[X_DK_SEEK].n_value,
    279      1.1  cgd 		    cur.dk_seek, dk_ndrive * sizeof(long));
    280  1.1.1.1  cgd 		(void)kvm_read(kd, namelist[X_TK_NIN].n_value,
    281      1.1  cgd 		    &cur.tk_nin, sizeof(cur.tk_nin));
    282  1.1.1.1  cgd 		(void)kvm_read(kd, namelist[X_TK_NOUT].n_value,
    283      1.1  cgd 		    &cur.tk_nout, sizeof(cur.tk_nout));
    284  1.1.1.1  cgd 		(void)kvm_read(kd, namelist[X_CP_TIME].n_value,
    285      1.1  cgd 		    cur.cp_time, sizeof(cur.cp_time));
    286      1.1  cgd 		for (i = 0; i < dk_ndrive; i++) {
    287      1.1  cgd 			if (!dr_select[i])
    288      1.1  cgd 				continue;
    289      1.1  cgd #define X(fld)	tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp
    290      1.1  cgd 			X(dk_xfer);
    291      1.1  cgd 			X(dk_seek);
    292      1.1  cgd 			X(dk_wds);
    293      1.1  cgd 			X(dk_time);
    294      1.1  cgd 		}
    295      1.1  cgd 		tmp = cur.tk_nin;
    296      1.1  cgd 		cur.tk_nin -= last.tk_nin;
    297      1.1  cgd 		last.tk_nin = tmp;
    298      1.1  cgd 		tmp = cur.tk_nout;
    299      1.1  cgd 		cur.tk_nout -= last.tk_nout;
    300      1.1  cgd 		last.tk_nout = tmp;
    301      1.1  cgd 		etime = 0;
    302      1.1  cgd 		for (i = 0; i < CPUSTATES; i++) {
    303      1.1  cgd 			X(cp_time);
    304      1.1  cgd 			etime += cur.cp_time[i];
    305      1.1  cgd 		}
    306      1.1  cgd 		if (etime == 0.0)
    307      1.1  cgd 			etime = 1.0;
    308      1.1  cgd 		etime /= (float)hz;
    309      1.1  cgd 		(void)printf("%4.0f%5.0f",
    310      1.1  cgd 		    cur.tk_nin / etime, cur.tk_nout / etime);
    311      1.1  cgd 		dkstats();
    312      1.1  cgd 		cpustats();
    313      1.1  cgd 		(void)printf("\n");
    314      1.1  cgd 		(void)fflush(stdout);
    315      1.1  cgd 
    316      1.1  cgd 		if (reps >= 0 && --reps <= 0)
    317      1.1  cgd 			break;
    318      1.1  cgd 		(void)sleep(interval);
    319      1.1  cgd 	}
    320      1.1  cgd 	exit(0);
    321      1.1  cgd }
    322      1.1  cgd 
    323      1.1  cgd /* ARGUSED */
    324      1.1  cgd void
    325  1.1.1.1  cgd phdr(signo)
    326  1.1.1.1  cgd 	int signo;
    327      1.1  cgd {
    328      1.1  cgd 	register int i;
    329      1.1  cgd 
    330      1.1  cgd 	(void)printf("      tty");
    331      1.1  cgd 	for (i = 0; i < dk_ndrive; i++)
    332      1.1  cgd 		if (dr_select[i])
    333      1.1  cgd 			(void)printf("          %3.3s ", dr_name[i]);
    334      1.1  cgd 	(void)printf("         cpu\n tin tout");
    335      1.1  cgd 	for (i = 0; i < dk_ndrive; i++)
    336      1.1  cgd 		if (dr_select[i])
    337      1.1  cgd 			(void)printf(" sps tps msps ");
    338      1.1  cgd 	(void)printf(" us ni sy id\n");
    339      1.1  cgd }
    340      1.1  cgd 
    341      1.1  cgd void
    342      1.1  cgd dkstats()
    343      1.1  cgd {
    344      1.1  cgd 	register int dn;
    345      1.1  cgd 	double atime, itime, msps, words, xtime;
    346      1.1  cgd 
    347      1.1  cgd 	for (dn = 0; dn < dk_ndrive; ++dn) {
    348      1.1  cgd 		if (!dr_select[dn])
    349      1.1  cgd 			continue;
    350      1.1  cgd 		words = cur.dk_wds[dn] * 32;		/* words xfer'd */
    351      1.1  cgd 		(void)printf("%4.0f",			/* sectors */
    352      1.1  cgd 		    words / (DEV_BSIZE / 2) / etime);
    353      1.1  cgd 
    354      1.1  cgd 		(void)printf("%4.0f", cur.dk_xfer[dn] / etime);
    355      1.1  cgd 
    356      1.1  cgd 		if (dk_wpms[dn] && cur.dk_xfer[dn]) {
    357      1.1  cgd 			atime = cur.dk_time[dn];	/* ticks disk busy */
    358      1.1  cgd 			atime /= (float)hz;		/* ticks to seconds */
    359      1.1  cgd 			xtime = words / dk_wpms[dn];	/* transfer time */
    360      1.1  cgd 			itime = atime - xtime;		/* time not xfer'ing */
    361      1.1  cgd 			if (itime < 0)
    362      1.1  cgd 				msps = 0;
    363      1.1  cgd 			else
    364      1.1  cgd 				msps = itime * 1000 / cur.dk_xfer[dn];
    365      1.1  cgd 		} else
    366      1.1  cgd 			msps = 0;
    367      1.1  cgd 		(void)printf("%5.1f ", msps);
    368      1.1  cgd 	}
    369      1.1  cgd }
    370      1.1  cgd 
    371      1.1  cgd void
    372      1.1  cgd cpustats()
    373      1.1  cgd {
    374      1.1  cgd 	register int state;
    375      1.1  cgd 	double time;
    376      1.1  cgd 
    377      1.1  cgd 	time = 0;
    378      1.1  cgd 	for (state = 0; state < CPUSTATES; ++state)
    379      1.1  cgd 		time += cur.cp_time[state];
    380      1.1  cgd 	for (state = 0; state < CPUSTATES; ++state)
    381      1.1  cgd 		(void)printf("%3.0f",
    382      1.1  cgd 		    100. * cur.cp_time[state] / (time ? time : 1));
    383      1.1  cgd }
    384      1.1  cgd 
    385      1.1  cgd void
    386      1.1  cgd usage()
    387      1.1  cgd {
    388      1.1  cgd 	(void)fprintf(stderr,
    389      1.1  cgd "usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n");
    390      1.1  cgd 	exit(1);
    391      1.1  cgd }
    392