iostat.c revision 4930
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1980, 1992, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
351590Srgrimesstatic char sccsid[] = "@(#)iostat.c	8.1 (Berkeley) 6/6/93";
361590Srgrimes#endif not lint
371590Srgrimes
381590Srgrimes#include <sys/param.h>
391590Srgrimes#include <sys/dkstat.h>
401590Srgrimes#include <sys/buf.h>
411590Srgrimes
421590Srgrimes#include <string.h>
431590Srgrimes#include <stdlib.h>
441590Srgrimes#include <nlist.h>
451590Srgrimes#include <paths.h>
461590Srgrimes#include "systat.h"
471590Srgrimes#include "extern.h"
481590Srgrimes
491590Srgrimesstatic struct nlist namelist[] = {
501590Srgrimes#define X_DK_BUSY	0
511590Srgrimes	{ "_dk_busy" },
521590Srgrimes#define X_DK_TIME	1
531590Srgrimes	{ "_dk_time" },
541590Srgrimes#define X_DK_XFER	2
551590Srgrimes	{ "_dk_xfer" },
561590Srgrimes#define X_DK_WDS	3
571590Srgrimes	{ "_dk_wds" },
581590Srgrimes#define X_DK_SEEK	4
591590Srgrimes	{ "_dk_seek" },
601590Srgrimes#define X_CP_TIME	5
611590Srgrimes	{ "_cp_time" },
621590Srgrimes#ifdef vax
631590Srgrimes#define X_MBDINIT	(X_CP_TIME+1)
641590Srgrimes	{ "_mbdinit" },
651590Srgrimes#define X_UBDINIT	(X_CP_TIME+2)
661590Srgrimes	{ "_ubdinit" },
671590Srgrimes#endif
681590Srgrimes#ifdef tahoe
691590Srgrimes#define	X_VBDINIT	(X_CP_TIME+1)
701590Srgrimes	{ "_vbdinit" },
711590Srgrimes#endif
721590Srgrimes	{ "" },
731590Srgrimes};
741590Srgrimes
751590Srgrimesstatic struct {
761590Srgrimes	int	dk_busy;
771590Srgrimes	long	cp_time[CPUSTATES];
781590Srgrimes	long	*dk_time;
791590Srgrimes	long	*dk_wds;
801590Srgrimes	long	*dk_seek;
811590Srgrimes	long	*dk_xfer;
821590Srgrimes} s, s1;
831590Srgrimes
841590Srgrimesstatic  int linesperregion;
851590Srgrimesstatic  double etime;
861590Srgrimesstatic  int numbers = 0;		/* default display bar graphs */
871590Srgrimesstatic  int msps = 0;			/* default ms/seek shown */
881590Srgrimes
891590Srgrimesstatic int barlabels __P((int));
901590Srgrimesstatic void histogram __P((double, int, double));
911590Srgrimesstatic int numlabels __P((int));
921590Srgrimesstatic int stats __P((int, int, int));
931590Srgrimesstatic void stat1 __P((int, int));
941590Srgrimes
951590Srgrimes
961590SrgrimesWINDOW *
971590Srgrimesopeniostat()
981590Srgrimes{
991590Srgrimes	return (subwin(stdscr, LINES-1-5, 0, 5, 0));
1001590Srgrimes}
1011590Srgrimes
1021590Srgrimesvoid
1031590Srgrimescloseiostat(w)
1041590Srgrimes	WINDOW *w;
1051590Srgrimes{
1061590Srgrimes	if (w == NULL)
1071590Srgrimes		return;
1081590Srgrimes	wclear(w);
1091590Srgrimes	wrefresh(w);
1101590Srgrimes	delwin(w);
1111590Srgrimes}
1121590Srgrimes
1131590Srgrimesint
1141590Srgrimesinitiostat()
1151590Srgrimes{
1161590Srgrimes	if (namelist[X_DK_BUSY].n_type == 0) {
1171590Srgrimes		if (kvm_nlist(kd, namelist)) {
1181590Srgrimes			nlisterr(namelist);
1191590Srgrimes			return(0);
1201590Srgrimes		}
1211590Srgrimes		if (namelist[X_DK_BUSY].n_type == 0) {
1221590Srgrimes			error("Disk init information isn't in namelist");
1231590Srgrimes			return(0);
1241590Srgrimes		}
1251590Srgrimes	}
1261590Srgrimes	if (! dkinit())
1271590Srgrimes		return(0);
1281590Srgrimes	if (dk_ndrive) {
1291590Srgrimes#define	allocate(e, t) \
1301590Srgrimes    s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
1311590Srgrimes    s1./**/e = (t *)calloc(dk_ndrive, sizeof (t));
1321590Srgrimes		allocate(dk_time, long);
1331590Srgrimes		allocate(dk_wds, long);
1341590Srgrimes		allocate(dk_seek, long);
1351590Srgrimes		allocate(dk_xfer, long);
1361590Srgrimes#undef allocate
1371590Srgrimes	}
1381590Srgrimes	return(1);
1391590Srgrimes}
1401590Srgrimes
1411590Srgrimesvoid
1421590Srgrimesfetchiostat()
1431590Srgrimes{
1441590Srgrimes	if (namelist[X_DK_BUSY].n_type == 0)
1451590Srgrimes		return;
1461590Srgrimes	NREAD(X_DK_BUSY, &s.dk_busy, LONG);
1471590Srgrimes	NREAD(X_DK_TIME, s.dk_time, dk_ndrive * LONG);
1481590Srgrimes	NREAD(X_DK_XFER, s.dk_xfer, dk_ndrive * LONG);
1491590Srgrimes	NREAD(X_DK_WDS, s.dk_wds, dk_ndrive * LONG);
1501590Srgrimes	NREAD(X_DK_SEEK, s.dk_seek, dk_ndrive * LONG);
1511590Srgrimes	NREAD(X_CP_TIME, s.cp_time, sizeof s.cp_time);
1521590Srgrimes}
1531590Srgrimes
1541590Srgrimes#define	INSET	10
1551590Srgrimes
1561590Srgrimesvoid
1571590Srgrimeslabeliostat()
1581590Srgrimes{
1591590Srgrimes	int row;
1601590Srgrimes
1611590Srgrimes	if (namelist[X_DK_BUSY].n_type == 0) {
1621590Srgrimes		error("No dk_busy defined.");
1631590Srgrimes		return;
1641590Srgrimes	}
1651590Srgrimes	row = 0;
1661590Srgrimes	wmove(wnd, row, 0); wclrtobot(wnd);
1671590Srgrimes	mvwaddstr(wnd, row++, INSET,
1681590Srgrimes	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
1691590Srgrimes	mvwaddstr(wnd, row++, 0, "cpu  user|");
1701590Srgrimes	mvwaddstr(wnd, row++, 0, "     nice|");
1711590Srgrimes	mvwaddstr(wnd, row++, 0, "   system|");
1724930Sbde	mvwaddstr(wnd, row++, 0, "interrupt|");
1731590Srgrimes	mvwaddstr(wnd, row++, 0, "     idle|");
1741590Srgrimes	if (numbers)
1751590Srgrimes		row = numlabels(row + 1);
1761590Srgrimes	else
1771590Srgrimes		row = barlabels(row + 1);
1781590Srgrimes}
1791590Srgrimes
1801590Srgrimesstatic int
1811590Srgrimesnumlabels(row)
1821590Srgrimes	int row;
1831590Srgrimes{
1841590Srgrimes	int i, col, regions, ndrives;
1851590Srgrimes
1861590Srgrimes#define COLWIDTH	14
1871590Srgrimes#define DRIVESPERLINE	((wnd->maxx - INSET) / COLWIDTH)
1881590Srgrimes	for (ndrives = 0, i = 0; i < dk_ndrive; i++)
1891590Srgrimes		if (dk_select[i])
1901590Srgrimes			ndrives++;
1911590Srgrimes	regions = howmany(ndrives, DRIVESPERLINE);
1921590Srgrimes	/*
1931590Srgrimes	 * Deduct -regions for blank line after each scrolling region.
1941590Srgrimes	 */
1951590Srgrimes	linesperregion = (wnd->maxy - row - regions) / regions;
1961590Srgrimes	/*
1971590Srgrimes	 * Minimum region contains space for two
1981590Srgrimes	 * label lines and one line of statistics.
1991590Srgrimes	 */
2001590Srgrimes	if (linesperregion < 3)
2011590Srgrimes		linesperregion = 3;
2021590Srgrimes	col = 0;
2031590Srgrimes	for (i = 0; i < dk_ndrive; i++)
2041590Srgrimes		if (dk_select[i] && dk_mspw[i] != 0.0) {
2051590Srgrimes			if (col + COLWIDTH >= wnd->maxx - INSET) {
2061590Srgrimes				col = 0, row += linesperregion + 1;
2071590Srgrimes				if (row > wnd->maxy - (linesperregion + 1))
2081590Srgrimes					break;
2091590Srgrimes			}
2101590Srgrimes			mvwaddstr(wnd, row, col + 4, dr_name[i]);
2111590Srgrimes			mvwaddstr(wnd, row + 1, col, "bps tps msps");
2121590Srgrimes			col += COLWIDTH;
2131590Srgrimes		}
2141590Srgrimes	if (col)
2151590Srgrimes		row += linesperregion + 1;
2161590Srgrimes	return (row);
2171590Srgrimes}
2181590Srgrimes
2191590Srgrimesstatic int
2201590Srgrimesbarlabels(row)
2211590Srgrimes	int row;
2221590Srgrimes{
2231590Srgrimes	int i;
2241590Srgrimes
2251590Srgrimes	mvwaddstr(wnd, row++, INSET,
2261590Srgrimes	    "/0   /5   /10  /15  /20  /25  /30  /35  /40  /45  /50");
2271590Srgrimes	linesperregion = 2 + msps;
2281590Srgrimes	for (i = 0; i < dk_ndrive; i++)
2291590Srgrimes		if (dk_select[i] && dk_mspw[i] != 0.0) {
2301590Srgrimes			if (row > wnd->maxy - linesperregion)
2311590Srgrimes				break;
2321590Srgrimes			mvwprintw(wnd, row++, 0, "%3.3s   bps|", dr_name[i]);
2331590Srgrimes			mvwaddstr(wnd, row++, 0, "      tps|");
2341590Srgrimes			if (msps)
2351590Srgrimes				mvwaddstr(wnd, row++, 0, "     msps|");
2361590Srgrimes		}
2371590Srgrimes	return (row);
2381590Srgrimes}
2391590Srgrimes
2401590Srgrimes
2411590Srgrimesvoid
2421590Srgrimesshowiostat()
2431590Srgrimes{
2441590Srgrimes	register long t;
2451590Srgrimes	register int i, row, col;
2461590Srgrimes
2471590Srgrimes	if (namelist[X_DK_BUSY].n_type == 0)
2481590Srgrimes		return;
2491590Srgrimes	for (i = 0; i < dk_ndrive; i++) {
2501590Srgrimes#define X(fld)	t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t
2511590Srgrimes		X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time);
2521590Srgrimes	}
2531590Srgrimes	etime = 0;
2541590Srgrimes	for(i = 0; i < CPUSTATES; i++) {
2551590Srgrimes		X(cp_time);
2561590Srgrimes		etime += s.cp_time[i];
2571590Srgrimes	}
2581590Srgrimes	if (etime == 0.0)
2591590Srgrimes		etime = 1.0;
2604930Sbde	etime /= hertz;
2611590Srgrimes	row = 1;
2624930Sbde	for (i = 0; i < CPUSTATES; i++)
2631590Srgrimes		stat1(row++, i);
2641590Srgrimes	if (!numbers) {
2651590Srgrimes		row += 2;
2661590Srgrimes		for (i = 0; i < dk_ndrive; i++)
2671590Srgrimes			if (dk_select[i] && dk_mspw[i] != 0.0) {
2681590Srgrimes				if (row > wnd->maxy - linesperregion)
2691590Srgrimes					break;
2701590Srgrimes				row = stats(row, INSET, i);
2711590Srgrimes			}
2721590Srgrimes		return;
2731590Srgrimes	}
2741590Srgrimes	col = 0;
2751590Srgrimes	wmove(wnd, row + linesperregion, 0);
2761590Srgrimes	wdeleteln(wnd);
2771590Srgrimes	wmove(wnd, row + 3, 0);
2781590Srgrimes	winsertln(wnd);
2791590Srgrimes	for (i = 0; i < dk_ndrive; i++)
2801590Srgrimes		if (dk_select[i] && dk_mspw[i] != 0.0) {
2811590Srgrimes			if (col + COLWIDTH >= wnd->maxx) {
2821590Srgrimes				col = 0, row += linesperregion + 1;
2831590Srgrimes				if (row > wnd->maxy - (linesperregion + 1))
2841590Srgrimes					break;
2851590Srgrimes				wmove(wnd, row + linesperregion, 0);
2861590Srgrimes				wdeleteln(wnd);
2871590Srgrimes				wmove(wnd, row + 3, 0);
2881590Srgrimes				winsertln(wnd);
2891590Srgrimes			}
2901590Srgrimes			(void) stats(row + 3, col, i);
2911590Srgrimes			col += COLWIDTH;
2921590Srgrimes		}
2931590Srgrimes}
2941590Srgrimes
2951590Srgrimesstatic int
2961590Srgrimesstats(row, col, dn)
2971590Srgrimes	int row, col, dn;
2981590Srgrimes{
2991590Srgrimes	double atime, words, xtime, itime;
3001590Srgrimes
3011590Srgrimes	atime = s.dk_time[dn];
3024930Sbde	atime /= hertz;
3031590Srgrimes	words = s.dk_wds[dn]*32.0;	/* number of words transferred */
3041590Srgrimes	xtime = dk_mspw[dn]*words;	/* transfer time */
3051590Srgrimes	itime = atime - xtime;		/* time not transferring */
3061590Srgrimes	if (xtime < 0)
3071590Srgrimes		itime += xtime, xtime = 0;
3081590Srgrimes	if (itime < 0)
3091590Srgrimes		xtime += itime, itime = 0;
3101590Srgrimes	if (numbers) {
3111590Srgrimes		mvwprintw(wnd, row, col, "%3.0f%4.0f%5.1f",
3121590Srgrimes		    words / 512 / etime, s.dk_xfer[dn] / etime,
3131590Srgrimes		    s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0.0);
3141590Srgrimes		return (row);
3151590Srgrimes	}
3161590Srgrimes	wmove(wnd, row++, col);
3171590Srgrimes	histogram(words / 512 / etime, 50, 1.0);
3181590Srgrimes	wmove(wnd, row++, col);
3191590Srgrimes	histogram(s.dk_xfer[dn] / etime, 50, 1.0);
3201590Srgrimes	if (msps) {
3211590Srgrimes		wmove(wnd, row++, col);
3221590Srgrimes		histogram(s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0,
3231590Srgrimes		   50, 1.0);
3241590Srgrimes	}
3251590Srgrimes	return (row);
3261590Srgrimes}
3271590Srgrimes
3281590Srgrimesstatic void
3291590Srgrimesstat1(row, o)
3301590Srgrimes	int row, o;
3311590Srgrimes{
3321590Srgrimes	register int i;
3331590Srgrimes	double time;
3341590Srgrimes
3351590Srgrimes	time = 0;
3361590Srgrimes	for (i = 0; i < CPUSTATES; i++)
3371590Srgrimes		time += s.cp_time[i];
3381590Srgrimes	if (time == 0.0)
3391590Srgrimes		time = 1.0;
3401590Srgrimes	wmove(wnd, row, INSET);
3411590Srgrimes#define CPUSCALE	0.5
3421590Srgrimes	histogram(100.0 * s.cp_time[o] / time, 50, CPUSCALE);
3431590Srgrimes}
3441590Srgrimes
3451590Srgrimesstatic void
3461590Srgrimeshistogram(val, colwidth, scale)
3471590Srgrimes	double val;
3481590Srgrimes	int colwidth;
3491590Srgrimes	double scale;
3501590Srgrimes{
3511590Srgrimes	char buf[10];
3521590Srgrimes	register int k;
3531590Srgrimes	register int v = (int)(val * scale) + 0.5;
3541590Srgrimes
3551590Srgrimes	k = MIN(v, colwidth);
3561590Srgrimes	if (v > colwidth) {
3571590Srgrimes		sprintf(buf, "%4.1f", val);
3581590Srgrimes		k -= strlen(buf);
3591590Srgrimes		while (k--)
3601590Srgrimes			waddch(wnd, 'X');
3611590Srgrimes		waddstr(wnd, buf);
3621590Srgrimes		return;
3631590Srgrimes	}
3641590Srgrimes	while (k--)
3651590Srgrimes		waddch(wnd, 'X');
3661590Srgrimes	wclrtoeol(wnd);
3671590Srgrimes}
3681590Srgrimes
3691590Srgrimesint
3701590Srgrimescmdiostat(cmd, args)
3711590Srgrimes	char *cmd, *args;
3721590Srgrimes{
3731590Srgrimes
3741590Srgrimes	if (prefix(cmd, "msps"))
3751590Srgrimes		msps = !msps;
3761590Srgrimes	else if (prefix(cmd, "numbers"))
3771590Srgrimes		numbers = 1;
3781590Srgrimes	else if (prefix(cmd, "bars"))
3791590Srgrimes		numbers = 0;
3801590Srgrimes	else if (!dkcmd(cmd, args))
3811590Srgrimes		return (0);
3821590Srgrimes	wclear(wnd);
3831590Srgrimes	labeliostat();
3841590Srgrimes	refresh();
3851590Srgrimes	return (1);
3861590Srgrimes}
387