iostat.c revision 158160
11590Srgrimes/*
239230Sgibbs * Copyright (c) 1998 Kenneth D. Merry.
339230Sgibbs * All rights reserved.
439230Sgibbs *
539230Sgibbs * Redistribution and use in source and binary forms, with or without
639230Sgibbs * modification, are permitted provided that the following conditions
739230Sgibbs * are met:
839230Sgibbs * 1. Redistributions of source code must retain the above copyright
939230Sgibbs *    notice, this list of conditions and the following disclaimer.
1039230Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1139230Sgibbs *    notice, this list of conditions and the following disclaimer in the
1239230Sgibbs *    documentation and/or other materials provided with the distribution.
1339230Sgibbs * 3. The name of the author may not be used to endorse or promote products
1439230Sgibbs *    derived from this software without specific prior written permission.
1539230Sgibbs *
1639230Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1739230Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1839230Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1939230Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2039230Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2139230Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2239230Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2339230Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2439230Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2539230Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2639230Sgibbs * SUCH DAMAGE.
2739230Sgibbs */
2839230Sgibbs/*
291590Srgrimes * Copyright (c) 1980, 1992, 1993
301590Srgrimes *	The Regents of the University of California.  All rights reserved.
311590Srgrimes *
321590Srgrimes * Redistribution and use in source and binary forms, with or without
331590Srgrimes * modification, are permitted provided that the following conditions
341590Srgrimes * are met:
351590Srgrimes * 1. Redistributions of source code must retain the above copyright
361590Srgrimes *    notice, this list of conditions and the following disclaimer.
371590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
381590Srgrimes *    notice, this list of conditions and the following disclaimer in the
391590Srgrimes *    documentation and/or other materials provided with the distribution.
401590Srgrimes * 3. All advertising materials mentioning features or use of this software
411590Srgrimes *    must display the following acknowledgement:
421590Srgrimes *	This product includes software developed by the University of
431590Srgrimes *	California, Berkeley and its contributors.
441590Srgrimes * 4. Neither the name of the University nor the names of its contributors
451590Srgrimes *    may be used to endorse or promote products derived from this software
461590Srgrimes *    without specific prior written permission.
471590Srgrimes *
481590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
491590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
501590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
511590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
521590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
531590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
541590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
551590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
561590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
571590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
581590Srgrimes * SUCH DAMAGE.
591590Srgrimes */
601590Srgrimes
6187715Smarkm#include <sys/cdefs.h>
621590Srgrimes
6387715Smarkm__FBSDID("$FreeBSD: head/usr.bin/systat/iostat.c 158160 2006-04-30 04:26:46Z bde $");
6487715Smarkm
6587715Smarkm#ifdef lint
6687715Smarkmstatic const char sccsid[] = "@(#)iostat.c	8.1 (Berkeley) 6/6/93";
6787715Smarkm#endif
6887715Smarkm
691590Srgrimes#include <sys/param.h>
7074671Stmm#include <sys/sysctl.h>
71111007Sphk#include <sys/resource.h>
721590Srgrimes
7387715Smarkm#include <devstat.h>
7487715Smarkm#include <err.h>
751590Srgrimes#include <nlist.h>
761590Srgrimes#include <paths.h>
7787715Smarkm#include <stdlib.h>
7887715Smarkm#include <string.h>
7987715Smarkm
801590Srgrimes#include "systat.h"
811590Srgrimes#include "extern.h"
8240060Sobrien#include "devs.h"
831590Srgrimes
8439230Sgibbsstruct statinfo cur, last;
851590Srgrimes
861590Srgrimesstatic  int linesperregion;
871590Srgrimesstatic  double etime;
881590Srgrimesstatic  int numbers = 0;		/* default display bar graphs */
8939230Sgibbsstatic  int kbpt = 0;			/* default ms/seek shown */
901590Srgrimes
9192922Simpstatic int barlabels(int);
9292922Simpstatic void histogram(long double, int, double);
9392922Simpstatic int numlabels(int);
9492922Simpstatic int devstats(int, int, int);
9592922Simpstatic void stat1(int, int);
961590Srgrimes
971590SrgrimesWINDOW *
981590Srgrimesopeniostat()
991590Srgrimes{
100158160Sbde	return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0));
1011590Srgrimes}
1021590Srgrimes
1031590Srgrimesvoid
1041590Srgrimescloseiostat(w)
1051590Srgrimes	WINDOW *w;
1061590Srgrimes{
1071590Srgrimes	if (w == NULL)
1081590Srgrimes		return;
1091590Srgrimes	wclear(w);
1101590Srgrimes	wrefresh(w);
1111590Srgrimes	delwin(w);
1121590Srgrimes}
1131590Srgrimes
1141590Srgrimesint
1151590Srgrimesinitiostat()
1161590Srgrimes{
11783131Sken	if ((num_devices = devstat_getnumdevs(NULL)) < 0)
1181590Srgrimes		return(0);
11939230Sgibbs
12039230Sgibbs	cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
12139230Sgibbs	last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
12239230Sgibbs	bzero(cur.dinfo, sizeof(struct devinfo));
12339230Sgibbs	bzero(last.dinfo, sizeof(struct devinfo));
12439230Sgibbs
12539230Sgibbs	/*
12639230Sgibbs	 * This value for maxshowdevs (100) is bogus.  I'm not sure exactly
12739230Sgibbs	 * how to calculate it, though.
12839230Sgibbs	 */
12939230Sgibbs	if (dsinit(100, &cur, &last, NULL) != 1)
13039230Sgibbs		return(0);
13139230Sgibbs
1321590Srgrimes	return(1);
1331590Srgrimes}
1341590Srgrimes
1351590Srgrimesvoid
1361590Srgrimesfetchiostat()
1371590Srgrimes{
13839230Sgibbs	struct devinfo *tmp_dinfo;
13969141Srwatson	size_t len;
14039230Sgibbs
14169141Srwatson	len = sizeof(cur.cp_time);
14287715Smarkm	if (sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0)
14387715Smarkm	    || len != sizeof(cur.cp_time)) {
14469141Srwatson		perror("kern.cp_time");
14569141Srwatson		exit (1);
14669141Srwatson	}
14739230Sgibbs	tmp_dinfo = last.dinfo;
14839230Sgibbs	last.dinfo = cur.dinfo;
14939230Sgibbs	cur.dinfo = tmp_dinfo;
150121836Stjr
151121836Stjr	last.snap_time = cur.snap_time;
15239230Sgibbs
15339230Sgibbs	/*
15439230Sgibbs	 * Here what we want to do is refresh our device stats.
15539230Sgibbs	 * getdevs() returns 1 when the device list has changed.
15639230Sgibbs	 * If the device list has changed, we want to go through
15739230Sgibbs	 * the selection process again, in case a device that we
15839230Sgibbs	 * were previously displaying has gone away.
15939230Sgibbs	 */
16083131Sken	switch (devstat_getdevs(NULL, &cur)) {
16139230Sgibbs	case -1:
16239230Sgibbs		errx(1, "%s", devstat_errbuf);
16339230Sgibbs		break;
16439230Sgibbs	case 1:
16539230Sgibbs		cmdiostat("refresh", NULL);
16639230Sgibbs		break;
16739230Sgibbs	default:
16839230Sgibbs		break;
16939230Sgibbs	}
17039230Sgibbs	num_devices = cur.dinfo->numdevs;
17139230Sgibbs	generation = cur.dinfo->generation;
17239230Sgibbs
1731590Srgrimes}
1741590Srgrimes
1751590Srgrimes#define	INSET	10
1761590Srgrimes
1771590Srgrimesvoid
1781590Srgrimeslabeliostat()
1791590Srgrimes{
1801590Srgrimes	int row;
1811590Srgrimes
1821590Srgrimes	row = 0;
1831590Srgrimes	wmove(wnd, row, 0); wclrtobot(wnd);
1841590Srgrimes	mvwaddstr(wnd, row++, INSET,
1851590Srgrimes	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
1861590Srgrimes	mvwaddstr(wnd, row++, 0, "cpu  user|");
1871590Srgrimes	mvwaddstr(wnd, row++, 0, "     nice|");
1881590Srgrimes	mvwaddstr(wnd, row++, 0, "   system|");
1894930Sbde	mvwaddstr(wnd, row++, 0, "interrupt|");
1901590Srgrimes	mvwaddstr(wnd, row++, 0, "     idle|");
1911590Srgrimes	if (numbers)
1921590Srgrimes		row = numlabels(row + 1);
1931590Srgrimes	else
1941590Srgrimes		row = barlabels(row + 1);
1951590Srgrimes}
1961590Srgrimes
1971590Srgrimesstatic int
1981590Srgrimesnumlabels(row)
1991590Srgrimes	int row;
2001590Srgrimes{
20187715Smarkm	int i, _col, regions, ndrives;
20239230Sgibbs	char tmpstr[10];
2031590Srgrimes
20439230Sgibbs#define COLWIDTH	17
20550635Speter#define DRIVESPERLINE	((wnd->_maxx - INSET) / COLWIDTH)
20639230Sgibbs	for (ndrives = 0, i = 0; i < num_devices; i++)
20739230Sgibbs		if (dev_select[i].selected)
2081590Srgrimes			ndrives++;
2091590Srgrimes	regions = howmany(ndrives, DRIVESPERLINE);
2101590Srgrimes	/*
2111590Srgrimes	 * Deduct -regions for blank line after each scrolling region.
2121590Srgrimes	 */
21350635Speter	linesperregion = (wnd->_maxy - row - regions) / regions;
2141590Srgrimes	/*
2151590Srgrimes	 * Minimum region contains space for two
2161590Srgrimes	 * label lines and one line of statistics.
2171590Srgrimes	 */
2181590Srgrimes	if (linesperregion < 3)
2191590Srgrimes		linesperregion = 3;
22087715Smarkm	_col = INSET;
22139230Sgibbs	for (i = 0; i < num_devices; i++)
22239230Sgibbs		if (dev_select[i].selected) {
22387715Smarkm			if (_col + COLWIDTH >= wnd->_maxx - INSET) {
22487715Smarkm				_col = INSET, row += linesperregion + 1;
22550635Speter				if (row > wnd->_maxy - (linesperregion + 1))
2261590Srgrimes					break;
2271590Srgrimes			}
22839230Sgibbs			sprintf(tmpstr, "%s%d", dev_select[i].device_name,
22939230Sgibbs				dev_select[i].unit_number);
23087715Smarkm			mvwaddstr(wnd, row, _col + 4, tmpstr);
23187715Smarkm			mvwaddstr(wnd, row + 1, _col, "  KB/t tps  MB/s ");
23287715Smarkm			_col += COLWIDTH;
2331590Srgrimes		}
23487715Smarkm	if (_col)
2351590Srgrimes		row += linesperregion + 1;
2361590Srgrimes	return (row);
2371590Srgrimes}
2381590Srgrimes
2391590Srgrimesstatic int
2401590Srgrimesbarlabels(row)
2411590Srgrimes	int row;
2421590Srgrimes{
2431590Srgrimes	int i;
24439230Sgibbs	char tmpstr[10];
2451590Srgrimes
2461590Srgrimes	mvwaddstr(wnd, row++, INSET,
24761147Sphk	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
24839230Sgibbs	linesperregion = 2 + kbpt;
24939230Sgibbs	for (i = 0; i < num_devices; i++)
25039230Sgibbs		if (dev_select[i].selected) {
25150635Speter			if (row > wnd->_maxy - linesperregion)
2521590Srgrimes				break;
25339230Sgibbs			sprintf(tmpstr, "%s%d", dev_select[i].device_name,
25439230Sgibbs				dev_select[i].unit_number);
25539230Sgibbs			mvwprintw(wnd, row++, 0, "%-5.5s MB/s|",
25639230Sgibbs				  tmpstr);
2571590Srgrimes			mvwaddstr(wnd, row++, 0, "      tps|");
25839230Sgibbs			if (kbpt)
25939230Sgibbs				mvwaddstr(wnd, row++, 0, "     KB/t|");
2601590Srgrimes		}
2611590Srgrimes	return (row);
2621590Srgrimes}
2631590Srgrimes
2641590Srgrimes
2651590Srgrimesvoid
2661590Srgrimesshowiostat()
2671590Srgrimes{
26887715Smarkm	long t;
26987715Smarkm	int i, row, _col;
2701590Srgrimes
27139230Sgibbs#define X(fld)	t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t
2721590Srgrimes	etime = 0;
2731590Srgrimes	for(i = 0; i < CPUSTATES; i++) {
2741590Srgrimes		X(cp_time);
27539230Sgibbs		etime += cur.cp_time[i];
2761590Srgrimes	}
2771590Srgrimes	if (etime == 0.0)
2781590Srgrimes		etime = 1.0;
2794930Sbde	etime /= hertz;
2801590Srgrimes	row = 1;
2814930Sbde	for (i = 0; i < CPUSTATES; i++)
2821590Srgrimes		stat1(row++, i);
2831590Srgrimes	if (!numbers) {
2841590Srgrimes		row += 2;
28539230Sgibbs		for (i = 0; i < num_devices; i++)
28639230Sgibbs			if (dev_select[i].selected) {
28750635Speter				if (row > wnd->_maxy - linesperregion)
2881590Srgrimes					break;
28939230Sgibbs				row = devstats(row, INSET, i);
2901590Srgrimes			}
2911590Srgrimes		return;
2921590Srgrimes	}
29387715Smarkm	_col = INSET;
2941590Srgrimes	wmove(wnd, row + linesperregion, 0);
2951590Srgrimes	wdeleteln(wnd);
2961590Srgrimes	wmove(wnd, row + 3, 0);
2971590Srgrimes	winsertln(wnd);
29839230Sgibbs	for (i = 0; i < num_devices; i++)
29939230Sgibbs		if (dev_select[i].selected) {
30087715Smarkm			if (_col + COLWIDTH >= wnd->_maxx - INSET) {
30187715Smarkm				_col = INSET, row += linesperregion + 1;
30250635Speter				if (row > wnd->_maxy - (linesperregion + 1))
3031590Srgrimes					break;
3041590Srgrimes				wmove(wnd, row + linesperregion, 0);
3051590Srgrimes				wdeleteln(wnd);
3061590Srgrimes				wmove(wnd, row + 3, 0);
3071590Srgrimes				winsertln(wnd);
3081590Srgrimes			}
30987715Smarkm			(void) devstats(row + 3, _col, i);
31087715Smarkm			_col += COLWIDTH;
3111590Srgrimes		}
3121590Srgrimes}
3131590Srgrimes
3141590Srgrimesstatic int
31587715Smarkmdevstats(row, _col, dn)
31687715Smarkm	int row, _col, dn;
3171590Srgrimes{
31839230Sgibbs	long double transfers_per_second;
31939230Sgibbs	long double kb_per_transfer, mb_per_second;
32039230Sgibbs	long double busy_seconds;
32139230Sgibbs	int di;
32239230Sgibbs
32339230Sgibbs	di = dev_select[dn].position;
3241590Srgrimes
325112288Sphk	busy_seconds = cur.snap_time - last.snap_time;
32639230Sgibbs
32783131Sken	if (devstat_compute_statistics(&cur.dinfo->devices[di],
32883131Sken	    &last.dinfo->devices[di], busy_seconds,
32983131Sken	    DSM_KB_PER_TRANSFER, &kb_per_transfer,
33083131Sken	    DSM_TRANSFERS_PER_SECOND, &transfers_per_second,
33183131Sken	    DSM_MB_PER_SECOND, &mb_per_second, DSM_NONE) != 0)
33239230Sgibbs		errx(1, "%s", devstat_errbuf);
33339230Sgibbs
3341590Srgrimes	if (numbers) {
33587715Smarkm		mvwprintw(wnd, row, _col, " %5.2Lf %3.0Lf %5.2Lf ",
33639230Sgibbs			 kb_per_transfer, transfers_per_second,
33739230Sgibbs			 mb_per_second);
33839230Sgibbs		return(row);
3391590Srgrimes	}
34087715Smarkm	wmove(wnd, row++, _col);
34161148Sphk	histogram(mb_per_second, 50, .5);
34287715Smarkm	wmove(wnd, row++, _col);
34361148Sphk	histogram(transfers_per_second, 50, .5);
34439230Sgibbs	if (kbpt) {
34587715Smarkm		wmove(wnd, row++, _col);
34661148Sphk		histogram(kb_per_transfer, 50, .5);
3471590Srgrimes	}
34839230Sgibbs
34939230Sgibbs	return(row);
35039230Sgibbs
3511590Srgrimes}
3521590Srgrimes
3531590Srgrimesstatic void
3541590Srgrimesstat1(row, o)
3551590Srgrimes	int row, o;
3561590Srgrimes{
35787715Smarkm	int i;
35887715Smarkm	double dtime;
3591590Srgrimes
36087715Smarkm	dtime = 0.0;
3611590Srgrimes	for (i = 0; i < CPUSTATES; i++)
36287715Smarkm		dtime += cur.cp_time[i];
36387715Smarkm	if (dtime == 0.0)
36487715Smarkm		dtime = 1.0;
3651590Srgrimes	wmove(wnd, row, INSET);
3661590Srgrimes#define CPUSCALE	0.5
36787715Smarkm	histogram(100.0 * cur.cp_time[o] / dtime, 50, CPUSCALE);
3681590Srgrimes}
3691590Srgrimes
3701590Srgrimesstatic void
3711590Srgrimeshistogram(val, colwidth, scale)
37239230Sgibbs	long double val;
3731590Srgrimes	int colwidth;
3741590Srgrimes	double scale;
3751590Srgrimes{
3761590Srgrimes	char buf[10];
37787715Smarkm	int k;
37887715Smarkm	int v = (int)(val * scale) + 0.5;
3791590Srgrimes
3801590Srgrimes	k = MIN(v, colwidth);
3811590Srgrimes	if (v > colwidth) {
38239230Sgibbs		snprintf(buf, sizeof(buf), "%5.2Lf", val);
3831590Srgrimes		k -= strlen(buf);
3841590Srgrimes		while (k--)
3851590Srgrimes			waddch(wnd, 'X');
3861590Srgrimes		waddstr(wnd, buf);
3871590Srgrimes		return;
3881590Srgrimes	}
3891590Srgrimes	while (k--)
3901590Srgrimes		waddch(wnd, 'X');
3911590Srgrimes	wclrtoeol(wnd);
3921590Srgrimes}
3931590Srgrimes
3941590Srgrimesint
3951590Srgrimescmdiostat(cmd, args)
39687715Smarkm	const char *cmd, *args;
3971590Srgrimes{
3981590Srgrimes
39939230Sgibbs	if (prefix(cmd, "kbpt"))
40039230Sgibbs		kbpt = !kbpt;
4011590Srgrimes	else if (prefix(cmd, "numbers"))
4021590Srgrimes		numbers = 1;
4031590Srgrimes	else if (prefix(cmd, "bars"))
4041590Srgrimes		numbers = 0;
40539230Sgibbs	else if (!dscmd(cmd, args, 100, &cur))
4061590Srgrimes		return (0);
4071590Srgrimes	wclear(wnd);
4081590Srgrimes	labeliostat();
4091590Srgrimes	refresh();
4101590Srgrimes	return (1);
4111590Srgrimes}
412