iostat.c revision 74671
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1998 Kenneth D. Merry.
31541Srgrimes * All rights reserved.
41541Srgrimes *
51541Srgrimes * Redistribution and use in source and binary forms, with or without
61541Srgrimes * modification, are permitted provided that the following conditions
71541Srgrimes * are met:
81541Srgrimes * 1. Redistributions of source code must retain the above copyright
91541Srgrimes *    notice, this list of conditions and the following disclaimer.
101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111541Srgrimes *    notice, this list of conditions and the following disclaimer in the
121541Srgrimes *    documentation and/or other materials provided with the distribution.
131541Srgrimes * 3. The name of the author may not be used to endorse or promote products
141541Srgrimes *    derived from this software without specific prior written permission.
151541Srgrimes *
161541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
171541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
201541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261541Srgrimes * SUCH DAMAGE.
271541Srgrimes *
281541Srgrimes * $FreeBSD: head/usr.bin/systat/iostat.c 74671 2001-03-23 03:58:25Z tmm $
291541Srgrimes */
301541Srgrimes/*
311541Srgrimes * Copyright (c) 1980, 1992, 1993
321541Srgrimes *	The Regents of the University of California.  All rights reserved.
331541Srgrimes *
341541Srgrimes * Redistribution and use in source and binary forms, with or without
351541Srgrimes * modification, are permitted provided that the following conditions
3622521Sdyson * are met:
371541Srgrimes * 1. Redistributions of source code must retain the above copyright
3822521Sdyson *    notice, this list of conditions and the following disclaimer.
3922521Sdyson * 2. Redistributions in binary form must reproduce the above copyright
4022521Sdyson *    notice, this list of conditions and the following disclaimer in the
4122521Sdyson *    documentation and/or other materials provided with the distribution.
4222521Sdyson * 3. All advertising materials mentioning features or use of this software
4350477Speter *    must display the following acknowledgement:
441541Srgrimes *	This product includes software developed by the University of
451541Srgrimes *	California, Berkeley and its contributors.
461541Srgrimes * 4. Neither the name of the University nor the names of its contributors
471541Srgrimes *    may be used to endorse or promote products derived from this software
481541Srgrimes *    without specific prior written permission.
4977130Sru *
501541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5196755Strhodes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
521541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5396755Strhodes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
541541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5535256Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
561541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
571541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
581541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
591541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6096755Strhodes * SUCH DAMAGE.
611541Srgrimes */
621541Srgrimes
6396755Strhodes#ifndef lint
641541Srgrimesstatic char sccsid[] = "@(#)iostat.c	8.1 (Berkeley) 6/6/93";
651541Srgrimes#endif not lint
661541Srgrimes
671541Srgrimes#include <sys/param.h>
681541Srgrimes#include <sys/dkstat.h>
691541Srgrimes#include <sys/sysctl.h>
701541Srgrimes
711541Srgrimes#include <string.h>
7277130Sru#include <stdlib.h>
7377130Sru#include <nlist.h>
741541Srgrimes#include <paths.h>
751541Srgrimes#include <devstat.h>
761541Srgrimes#include <err.h>
771541Srgrimes#include "systat.h"
781541Srgrimes#include "extern.h"
791541Srgrimes#include "devs.h"
801541Srgrimes
811541Srgrimesstruct statinfo cur, last;
8296755Strhodes
831541Srgrimesstatic  int linesperregion;
841541Srgrimesstatic  double etime;
8526963Salexstatic  int numbers = 0;		/* default display bar graphs */
861541Srgrimesstatic  int kbpt = 0;			/* default ms/seek shown */
871541Srgrimes
881541Srgrimesstatic int barlabels __P((int));
891541Srgrimesstatic void histogram __P((long double, int, double));
901541Srgrimesstatic int numlabels __P((int));
911541Srgrimesstatic int devstats __P((int, int, int));
921541Srgrimesstatic void stat1 __P((int, int));
931541Srgrimes
941541SrgrimesWINDOW *
951541Srgrimesopeniostat()
9622521Sdyson{
9722521Sdyson	return (subwin(stdscr, LINES-1-5, 0, 5, 0));
9822521Sdyson}
9922521Sdyson
10022521Sdysonvoid
1011541Srgrimescloseiostat(w)
10222521Sdyson	WINDOW *w;
10322521Sdyson{
10422521Sdyson	if (w == NULL)
10522521Sdyson		return;
10622521Sdyson	wclear(w);
10722521Sdyson	wrefresh(w);
10822521Sdyson	delwin(w);
10922521Sdyson}
11022521Sdyson
1111541Srgrimesint
1121541Srgrimesinitiostat()
1131541Srgrimes{
1141541Srgrimes	if ((num_devices = getnumdevs()) < 0)
1151541Srgrimes		return(0);
1161541Srgrimes
1171541Srgrimes	cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
1181541Srgrimes	last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
1191541Srgrimes	bzero(cur.dinfo, sizeof(struct devinfo));
1201541Srgrimes	bzero(last.dinfo, sizeof(struct devinfo));
1211541Srgrimes
1221541Srgrimes	/*
1231541Srgrimes	 * This value for maxshowdevs (100) is bogus.  I'm not sure exactly
1241541Srgrimes	 * how to calculate it, though.
1258876Srgrimes	 */
1261541Srgrimes	if (dsinit(100, &cur, &last, NULL) != 1)
1271541Srgrimes		return(0);
1281541Srgrimes
1291541Srgrimes	return(1);
13077130Sru}
1311541Srgrimes
1321541Srgrimesvoid
1331541Srgrimesfetchiostat()
1341541Srgrimes{
1358876Srgrimes	struct devinfo *tmp_dinfo;
1361541Srgrimes	size_t len;
1371541Srgrimes	int err;
1381541Srgrimes
1391541Srgrimes	len = sizeof(cur.cp_time);
1401541Srgrimes	err = sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0);
1411541Srgrimes	if (err || len != sizeof(cur.cp_time)) {
1421541Srgrimes		perror("kern.cp_time");
1431541Srgrimes		exit (1);
14496755Strhodes	}
1451541Srgrimes	tmp_dinfo = last.dinfo;
1461541Srgrimes	last.dinfo = cur.dinfo;
1471541Srgrimes	cur.dinfo = tmp_dinfo;
1481541Srgrimes
1498876Srgrimes	last.busy_time = cur.busy_time;
1501541Srgrimes
1511541Srgrimes	/*
1521541Srgrimes	 * Here what we want to do is refresh our device stats.
1531541Srgrimes	 * getdevs() returns 1 when the device list has changed.
1541541Srgrimes	 * If the device list has changed, we want to go through
1558876Srgrimes	 * the selection process again, in case a device that we
1561541Srgrimes	 * were previously displaying has gone away.
1571541Srgrimes	 */
1581541Srgrimes	switch (getdevs(&cur)) {
1591541Srgrimes	case -1:
160108470Sschweikh		errx(1, "%s", devstat_errbuf);
1611541Srgrimes		break;
1621541Srgrimes	case 1:
1631541Srgrimes		cmdiostat("refresh", NULL);
16426964Salex		break;
1651541Srgrimes	default:
1661541Srgrimes		break;
1671541Srgrimes	}
16826964Salex	num_devices = cur.dinfo->numdevs;
1691541Srgrimes	generation = cur.dinfo->generation;
1701541Srgrimes
1711541Srgrimes}
17226964Salex
1731541Srgrimes#define	INSET	10
1741541Srgrimes
1751541Srgrimesvoid
1761541Srgrimeslabeliostat()
1771541Srgrimes{
17876166Smarkm	int row;
1792960Swollman
18076166Smarkm	row = 0;
18176166Smarkm	wmove(wnd, row, 0); wclrtobot(wnd);
18276166Smarkm	mvwaddstr(wnd, row++, INSET,
18376166Smarkm	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
18476166Smarkm	mvwaddstr(wnd, row++, 0, "cpu  user|");
18512769Sphk	mvwaddstr(wnd, row++, 0, "     nice|");
1861541Srgrimes	mvwaddstr(wnd, row++, 0, "   system|");
18776166Smarkm	mvwaddstr(wnd, row++, 0, "interrupt|");
18877031Sru	mvwaddstr(wnd, row++, 0, "     idle|");
1891541Srgrimes	if (numbers)
19066356Sbp		row = numlabels(row + 1);
19166356Sbp	else
19266356Sbp		row = barlabels(row + 1);
19366356Sbp}
19466356Sbp
19512769Sphkstatic int
19612769Sphknumlabels(row)
19712769Sphk	int row;
1981541Srgrimes{
19965464Sbp	int i, col, regions, ndrives;
20066356Sbp	char tmpstr[10];
20166356Sbp
20265464Sbp#define COLWIDTH	17
20366356Sbp#define DRIVESPERLINE	((wnd->_maxx - INSET) / COLWIDTH)
20465464Sbp	for (ndrives = 0, i = 0; i < num_devices; i++)
20566356Sbp		if (dev_select[i].selected)
20665464Sbp			ndrives++;
20765464Sbp	regions = howmany(ndrives, DRIVESPERLINE);
20865467Sbp	/*
20965464Sbp	 * Deduct -regions for blank line after each scrolling region.
21065464Sbp	 */
21165467Sbp	linesperregion = (wnd->_maxy - row - regions) / regions;
21265464Sbp	/*
21365464Sbp	 * Minimum region contains space for two
21412595Sbde	 * label lines and one line of statistics.
2151541Srgrimes	 */
2161541Srgrimes	if (linesperregion < 3)
2171541Srgrimes		linesperregion = 3;
2181541Srgrimes	col = INSET;
2191541Srgrimes	for (i = 0; i < num_devices; i++)
2201541Srgrimes		if (dev_select[i].selected) {
2211541Srgrimes			if (col + COLWIDTH >= wnd->_maxx - INSET) {
2221541Srgrimes				col = INSET, row += linesperregion + 1;
2231541Srgrimes				if (row > wnd->_maxy - (linesperregion + 1))
2241541Srgrimes					break;
2251541Srgrimes			}
2261541Srgrimes			sprintf(tmpstr, "%s%d", dev_select[i].device_name,
2271541Srgrimes				dev_select[i].unit_number);
2281541Srgrimes			mvwaddstr(wnd, row, col + 4, tmpstr);
2291541Srgrimes			mvwaddstr(wnd, row + 1, col, "  KB/t tps  MB/s ");
2301541Srgrimes			col += COLWIDTH;
2311541Srgrimes		}
2321541Srgrimes	if (col)
2331541Srgrimes		row += linesperregion + 1;
2341541Srgrimes	return (row);
2351541Srgrimes}
2361541Srgrimes
2371541Srgrimesstatic int
2388876Srgrimesbarlabels(row)
23922521Sdyson	int row;
2401541Srgrimes{
2411541Srgrimes	int i;
2421541Srgrimes	char tmpstr[10];
2431541Srgrimes
2441541Srgrimes	mvwaddstr(wnd, row++, INSET,
2451541Srgrimes	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
2461541Srgrimes	linesperregion = 2 + kbpt;
2471541Srgrimes	for (i = 0; i < num_devices; i++)
2481541Srgrimes		if (dev_select[i].selected) {
2491541Srgrimes			if (row > wnd->_maxy - linesperregion)
2501541Srgrimes				break;
2511541Srgrimes			sprintf(tmpstr, "%s%d", dev_select[i].device_name,
2521541Srgrimes				dev_select[i].unit_number);
2531541Srgrimes			mvwprintw(wnd, row++, 0, "%-5.5s MB/s|",
2541541Srgrimes				  tmpstr);
2551541Srgrimes			mvwaddstr(wnd, row++, 0, "      tps|");
2561541Srgrimes			if (kbpt)
25750616Sbde				mvwaddstr(wnd, row++, 0, "     KB/t|");
2581541Srgrimes		}
2591541Srgrimes	return (row);
2601541Srgrimes}
2611541Srgrimes
2621541Srgrimes
26350616Sbdevoid
2641541Srgrimesshowiostat()
2651541Srgrimes{
2661541Srgrimes	register long t;
2671541Srgrimes	register int i, row, col;
2681541Srgrimes
2691541Srgrimes#define X(fld)	t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t
2701541Srgrimes	etime = 0;
2711541Srgrimes	for(i = 0; i < CPUSTATES; i++) {
2721541Srgrimes		X(cp_time);
2731541Srgrimes		etime += cur.cp_time[i];
2741541Srgrimes	}
2758876Srgrimes	if (etime == 0.0)
2761541Srgrimes		etime = 1.0;
2771541Srgrimes	etime /= hertz;
2781541Srgrimes	row = 1;
2791541Srgrimes	for (i = 0; i < CPUSTATES; i++)
2801541Srgrimes		stat1(row++, i);
2811541Srgrimes	if (!numbers) {
28224987Skato		row += 2;
28322521Sdyson		for (i = 0; i < num_devices; i++)
28424987Skato			if (dev_select[i].selected) {
2851541Srgrimes				if (row > wnd->_maxy - linesperregion)
2861541Srgrimes					break;
2871541Srgrimes				row = devstats(row, INSET, i);
2881541Srgrimes			}
2891541Srgrimes		return;
2901541Srgrimes	}
2911541Srgrimes	col = INSET;
2921541Srgrimes	wmove(wnd, row + linesperregion, 0);
29366356Sbp	wdeleteln(wnd);
2941541Srgrimes	wmove(wnd, row + 3, 0);
2951541Srgrimes	winsertln(wnd);
2968876Srgrimes	for (i = 0; i < num_devices; i++)
2971541Srgrimes		if (dev_select[i].selected) {
2981541Srgrimes			if (col + COLWIDTH >= wnd->_maxx - INSET) {
2991541Srgrimes				col = INSET, row += linesperregion + 1;
3001541Srgrimes				if (row > wnd->_maxy - (linesperregion + 1))
3011541Srgrimes					break;
3021541Srgrimes				wmove(wnd, row + linesperregion, 0);
30366356Sbp				wdeleteln(wnd);
30466356Sbp				wmove(wnd, row + 3, 0);
30566356Sbp				winsertln(wnd);
30666356Sbp			}
30766356Sbp			(void) devstats(row + 3, col, i);
30866356Sbp			col += COLWIDTH;
3091541Srgrimes		}
3101541Srgrimes}
3111541Srgrimes
3121541Srgrimesstatic int
3131541Srgrimesdevstats(row, col, dn)
3141541Srgrimes	int row, col, dn;
3151541Srgrimes{
3161541Srgrimes	long double transfers_per_second;
3171541Srgrimes	long double kb_per_transfer, mb_per_second;
3181541Srgrimes	long double busy_seconds;
3191541Srgrimes	int di;
3201541Srgrimes
32166356Sbp	di = dev_select[dn].position;
32266356Sbp
32383366Sjulian	busy_seconds = compute_etime(cur.busy_time, last.busy_time);
32466356Sbp
32566356Sbp	if (compute_stats(&cur.dinfo->devices[di], &last.dinfo->devices[di],
3261541Srgrimes			  busy_seconds, NULL, NULL, NULL,
3271541Srgrimes			  &kb_per_transfer, &transfers_per_second,
3281541Srgrimes			  &mb_per_second, NULL, NULL) != 0)
3291541Srgrimes		errx(1, "%s", devstat_errbuf);
3301541Srgrimes
3311541Srgrimes	if (numbers) {
3321541Srgrimes		mvwprintw(wnd, row, col, " %5.2Lf %3.0Lf %5.2Lf ",
3331541Srgrimes			 kb_per_transfer, transfers_per_second,
3341541Srgrimes			 mb_per_second);
3351541Srgrimes		return(row);
3361541Srgrimes	}
3371541Srgrimes	wmove(wnd, row++, col);
3381541Srgrimes	histogram(mb_per_second, 50, .5);
3391541Srgrimes	wmove(wnd, row++, col);
3401541Srgrimes	histogram(transfers_per_second, 50, .5);
3411541Srgrimes	if (kbpt) {
3421541Srgrimes		wmove(wnd, row++, col);
3431541Srgrimes		histogram(kb_per_transfer, 50, .5);
3441541Srgrimes	}
3451541Srgrimes
3461541Srgrimes	return(row);
3471541Srgrimes
34829584Sphk}
34998183Ssemenu
3501541Srgrimesstatic void
3511541Srgrimesstat1(row, o)
3521541Srgrimes	int row, o;
3531541Srgrimes{
3541541Srgrimes	register int i;
3551541Srgrimes	double time;
35622521Sdyson
35722521Sdyson	time = 0;
35822521Sdyson	for (i = 0; i < CPUSTATES; i++)
35922521Sdyson		time += cur.cp_time[i];
36022521Sdyson	if (time == 0.0)
36122521Sdyson		time = 1.0;
36222521Sdyson	wmove(wnd, row, INSET);
36322521Sdyson#define CPUSCALE	0.5
36422521Sdyson	histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE);
36522521Sdyson}
36622521Sdyson
36722521Sdysonstatic void
36822521Sdysonhistogram(val, colwidth, scale)
36922521Sdyson	long double val;
37066356Sbp	int colwidth;
37183366Sjulian	double scale;
37222521Sdyson{
37366356Sbp	char buf[10];
37422521Sdyson	register int k;
3751541Srgrimes	register int v = (int)(val * scale) + 0.5;
37666356Sbp
37722521Sdyson	k = MIN(v, colwidth);
37822521Sdyson	if (v > colwidth) {
37966356Sbp		snprintf(buf, sizeof(buf), "%5.2Lf", val);
38066356Sbp		k -= strlen(buf);
38166356Sbp		while (k--)
38266356Sbp			waddch(wnd, 'X');
38366356Sbp		waddstr(wnd, buf);
38466356Sbp		return;
38566356Sbp	}
38622521Sdyson	while (k--)
38766356Sbp		waddch(wnd, 'X');
38822521Sdyson	wclrtoeol(wnd);
38922521Sdyson}
39066356Sbp
39122521Sdysonint
39266356Sbpcmdiostat(cmd, args)
39366356Sbp	char *cmd, *args;
39422521Sdyson{
39566356Sbp
39683366Sjulian	if (prefix(cmd, "kbpt"))
39766356Sbp		kbpt = !kbpt;
39866356Sbp	else if (prefix(cmd, "numbers"))
39966356Sbp		numbers = 1;
40066356Sbp	else if (prefix(cmd, "bars"))
40166356Sbp		numbers = 0;
40266356Sbp	else if (!dscmd(cmd, args, 100, &cur))
40398183Ssemenu		return (0);
40498183Ssemenu	wclear(wnd);
40598183Ssemenu	labeliostat();
40698183Ssemenu	refresh();
40798183Ssemenu	return (1);
40898183Ssemenu}
40966356Sbp