iostat.c revision 1590
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|");
1721590Srgrimes	mvwaddstr(wnd, row++, 0, "     idle|");
1731590Srgrimes	if (numbers)
1741590Srgrimes		row = numlabels(row + 1);
1751590Srgrimes	else
1761590Srgrimes		row = barlabels(row + 1);
1771590Srgrimes}
1781590Srgrimes
1791590Srgrimesstatic int
1801590Srgrimesnumlabels(row)
1811590Srgrimes	int row;
1821590Srgrimes{
1831590Srgrimes	int i, col, regions, ndrives;
1841590Srgrimes
1851590Srgrimes#define COLWIDTH	14
1861590Srgrimes#define DRIVESPERLINE	((wnd->maxx - INSET) / COLWIDTH)
1871590Srgrimes	for (ndrives = 0, i = 0; i < dk_ndrive; i++)
1881590Srgrimes		if (dk_select[i])
1891590Srgrimes			ndrives++;
1901590Srgrimes	regions = howmany(ndrives, DRIVESPERLINE);
1911590Srgrimes	/*
1921590Srgrimes	 * Deduct -regions for blank line after each scrolling region.
1931590Srgrimes	 */
1941590Srgrimes	linesperregion = (wnd->maxy - row - regions) / regions;
1951590Srgrimes	/*
1961590Srgrimes	 * Minimum region contains space for two
1971590Srgrimes	 * label lines and one line of statistics.
1981590Srgrimes	 */
1991590Srgrimes	if (linesperregion < 3)
2001590Srgrimes		linesperregion = 3;
2011590Srgrimes	col = 0;
2021590Srgrimes	for (i = 0; i < dk_ndrive; i++)
2031590Srgrimes		if (dk_select[i] && dk_mspw[i] != 0.0) {
2041590Srgrimes			if (col + COLWIDTH >= wnd->maxx - INSET) {
2051590Srgrimes				col = 0, row += linesperregion + 1;
2061590Srgrimes				if (row > wnd->maxy - (linesperregion + 1))
2071590Srgrimes					break;
2081590Srgrimes			}
2091590Srgrimes			mvwaddstr(wnd, row, col + 4, dr_name[i]);
2101590Srgrimes			mvwaddstr(wnd, row + 1, col, "bps tps msps");
2111590Srgrimes			col += COLWIDTH;
2121590Srgrimes		}
2131590Srgrimes	if (col)
2141590Srgrimes		row += linesperregion + 1;
2151590Srgrimes	return (row);
2161590Srgrimes}
2171590Srgrimes
2181590Srgrimesstatic int
2191590Srgrimesbarlabels(row)
2201590Srgrimes	int row;
2211590Srgrimes{
2221590Srgrimes	int i;
2231590Srgrimes
2241590Srgrimes	mvwaddstr(wnd, row++, INSET,
2251590Srgrimes	    "/0   /5   /10  /15  /20  /25  /30  /35  /40  /45  /50");
2261590Srgrimes	linesperregion = 2 + msps;
2271590Srgrimes	for (i = 0; i < dk_ndrive; i++)
2281590Srgrimes		if (dk_select[i] && dk_mspw[i] != 0.0) {
2291590Srgrimes			if (row > wnd->maxy - linesperregion)
2301590Srgrimes				break;
2311590Srgrimes			mvwprintw(wnd, row++, 0, "%3.3s   bps|", dr_name[i]);
2321590Srgrimes			mvwaddstr(wnd, row++, 0, "      tps|");
2331590Srgrimes			if (msps)
2341590Srgrimes				mvwaddstr(wnd, row++, 0, "     msps|");
2351590Srgrimes		}
2361590Srgrimes	return (row);
2371590Srgrimes}
2381590Srgrimes
2391590Srgrimes
2401590Srgrimesvoid
2411590Srgrimesshowiostat()
2421590Srgrimes{
2431590Srgrimes	register long t;
2441590Srgrimes	register int i, row, col;
2451590Srgrimes
2461590Srgrimes	if (namelist[X_DK_BUSY].n_type == 0)
2471590Srgrimes		return;
2481590Srgrimes	for (i = 0; i < dk_ndrive; i++) {
2491590Srgrimes#define X(fld)	t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t
2501590Srgrimes		X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time);
2511590Srgrimes	}
2521590Srgrimes	etime = 0;
2531590Srgrimes	for(i = 0; i < CPUSTATES; i++) {
2541590Srgrimes		X(cp_time);
2551590Srgrimes		etime += s.cp_time[i];
2561590Srgrimes	}
2571590Srgrimes	if (etime == 0.0)
2581590Srgrimes		etime = 1.0;
2591590Srgrimes	etime /= (float) hz;
2601590Srgrimes	row = 1;
2611590Srgrimes
2621590Srgrimes	/*
2631590Srgrimes	 * Last CPU state not calculated yet.
2641590Srgrimes	 */
2651590Srgrimes	for (i = 0; i < CPUSTATES - 1; i++)
2661590Srgrimes		stat1(row++, i);
2671590Srgrimes	if (!numbers) {
2681590Srgrimes		row += 2;
2691590Srgrimes		for (i = 0; i < dk_ndrive; i++)
2701590Srgrimes			if (dk_select[i] && dk_mspw[i] != 0.0) {
2711590Srgrimes				if (row > wnd->maxy - linesperregion)
2721590Srgrimes					break;
2731590Srgrimes				row = stats(row, INSET, i);
2741590Srgrimes			}
2751590Srgrimes		return;
2761590Srgrimes	}
2771590Srgrimes	col = 0;
2781590Srgrimes	wmove(wnd, row + linesperregion, 0);
2791590Srgrimes	wdeleteln(wnd);
2801590Srgrimes	wmove(wnd, row + 3, 0);
2811590Srgrimes	winsertln(wnd);
2821590Srgrimes	for (i = 0; i < dk_ndrive; i++)
2831590Srgrimes		if (dk_select[i] && dk_mspw[i] != 0.0) {
2841590Srgrimes			if (col + COLWIDTH >= wnd->maxx) {
2851590Srgrimes				col = 0, row += linesperregion + 1;
2861590Srgrimes				if (row > wnd->maxy - (linesperregion + 1))
2871590Srgrimes					break;
2881590Srgrimes				wmove(wnd, row + linesperregion, 0);
2891590Srgrimes				wdeleteln(wnd);
2901590Srgrimes				wmove(wnd, row + 3, 0);
2911590Srgrimes				winsertln(wnd);
2921590Srgrimes			}
2931590Srgrimes			(void) stats(row + 3, col, i);
2941590Srgrimes			col += COLWIDTH;
2951590Srgrimes		}
2961590Srgrimes}
2971590Srgrimes
2981590Srgrimesstatic int
2991590Srgrimesstats(row, col, dn)
3001590Srgrimes	int row, col, dn;
3011590Srgrimes{
3021590Srgrimes	double atime, words, xtime, itime;
3031590Srgrimes
3041590Srgrimes	atime = s.dk_time[dn];
3051590Srgrimes	atime /= (float) hz;
3061590Srgrimes	words = s.dk_wds[dn]*32.0;	/* number of words transferred */
3071590Srgrimes	xtime = dk_mspw[dn]*words;	/* transfer time */
3081590Srgrimes	itime = atime - xtime;		/* time not transferring */
3091590Srgrimes	if (xtime < 0)
3101590Srgrimes		itime += xtime, xtime = 0;
3111590Srgrimes	if (itime < 0)
3121590Srgrimes		xtime += itime, itime = 0;
3131590Srgrimes	if (numbers) {
3141590Srgrimes		mvwprintw(wnd, row, col, "%3.0f%4.0f%5.1f",
3151590Srgrimes		    words / 512 / etime, s.dk_xfer[dn] / etime,
3161590Srgrimes		    s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0.0);
3171590Srgrimes		return (row);
3181590Srgrimes	}
3191590Srgrimes	wmove(wnd, row++, col);
3201590Srgrimes	histogram(words / 512 / etime, 50, 1.0);
3211590Srgrimes	wmove(wnd, row++, col);
3221590Srgrimes	histogram(s.dk_xfer[dn] / etime, 50, 1.0);
3231590Srgrimes	if (msps) {
3241590Srgrimes		wmove(wnd, row++, col);
3251590Srgrimes		histogram(s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0,
3261590Srgrimes		   50, 1.0);
3271590Srgrimes	}
3281590Srgrimes	return (row);
3291590Srgrimes}
3301590Srgrimes
3311590Srgrimesstatic void
3321590Srgrimesstat1(row, o)
3331590Srgrimes	int row, o;
3341590Srgrimes{
3351590Srgrimes	register int i;
3361590Srgrimes	double time;
3371590Srgrimes
3381590Srgrimes	time = 0;
3391590Srgrimes	for (i = 0; i < CPUSTATES; i++)
3401590Srgrimes		time += s.cp_time[i];
3411590Srgrimes	if (time == 0.0)
3421590Srgrimes		time = 1.0;
3431590Srgrimes	wmove(wnd, row, INSET);
3441590Srgrimes#define CPUSCALE	0.5
3451590Srgrimes	histogram(100.0 * s.cp_time[o] / time, 50, CPUSCALE);
3461590Srgrimes}
3471590Srgrimes
3481590Srgrimesstatic void
3491590Srgrimeshistogram(val, colwidth, scale)
3501590Srgrimes	double val;
3511590Srgrimes	int colwidth;
3521590Srgrimes	double scale;
3531590Srgrimes{
3541590Srgrimes	char buf[10];
3551590Srgrimes	register int k;
3561590Srgrimes	register int v = (int)(val * scale) + 0.5;
3571590Srgrimes
3581590Srgrimes	k = MIN(v, colwidth);
3591590Srgrimes	if (v > colwidth) {
3601590Srgrimes		sprintf(buf, "%4.1f", val);
3611590Srgrimes		k -= strlen(buf);
3621590Srgrimes		while (k--)
3631590Srgrimes			waddch(wnd, 'X');
3641590Srgrimes		waddstr(wnd, buf);
3651590Srgrimes		return;
3661590Srgrimes	}
3671590Srgrimes	while (k--)
3681590Srgrimes		waddch(wnd, 'X');
3691590Srgrimes	wclrtoeol(wnd);
3701590Srgrimes}
3711590Srgrimes
3721590Srgrimesint
3731590Srgrimescmdiostat(cmd, args)
3741590Srgrimes	char *cmd, *args;
3751590Srgrimes{
3761590Srgrimes
3771590Srgrimes	if (prefix(cmd, "msps"))
3781590Srgrimes		msps = !msps;
3791590Srgrimes	else if (prefix(cmd, "numbers"))
3801590Srgrimes		numbers = 1;
3811590Srgrimes	else if (prefix(cmd, "bars"))
3821590Srgrimes		numbers = 0;
3831590Srgrimes	else if (!dkcmd(cmd, args))
3841590Srgrimes		return (0);
3851590Srgrimes	wclear(wnd);
3861590Srgrimes	labeliostat();
3871590Srgrimes	refresh();
3881590Srgrimes	return (1);
3891590Srgrimes}
390