iostat.c revision 200462
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 200462 2009-12-13 03:14:06Z delphij $");
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>
76200462Sdelphij#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 *
98175387Sdelphijopeniostat(void)
991590Srgrimes{
100158160Sbde	return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0));
1011590Srgrimes}
1021590Srgrimes
1031590Srgrimesvoid
104175387Sdelphijcloseiostat(WINDOW *w)
1051590Srgrimes{
1061590Srgrimes	if (w == NULL)
1071590Srgrimes		return;
1081590Srgrimes	wclear(w);
1091590Srgrimes	wrefresh(w);
1101590Srgrimes	delwin(w);
1111590Srgrimes}
1121590Srgrimes
1131590Srgrimesint
114175387Sdelphijinitiostat(void)
1151590Srgrimes{
11683131Sken	if ((num_devices = devstat_getnumdevs(NULL)) < 0)
1171590Srgrimes		return(0);
11839230Sgibbs
11939230Sgibbs	cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
12039230Sgibbs	last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
12139230Sgibbs	bzero(cur.dinfo, sizeof(struct devinfo));
12239230Sgibbs	bzero(last.dinfo, sizeof(struct devinfo));
123158161Sbde
12439230Sgibbs	/*
12539230Sgibbs	 * This value for maxshowdevs (100) is bogus.  I'm not sure exactly
12639230Sgibbs	 * how to calculate it, though.
12739230Sgibbs	 */
12839230Sgibbs	if (dsinit(100, &cur, &last, NULL) != 1)
12939230Sgibbs		return(0);
13039230Sgibbs
1311590Srgrimes	return(1);
1321590Srgrimes}
1331590Srgrimes
1341590Srgrimesvoid
135175387Sdelphijfetchiostat(void)
1361590Srgrimes{
13739230Sgibbs	struct devinfo *tmp_dinfo;
13869141Srwatson	size_t len;
13939230Sgibbs
14069141Srwatson	len = sizeof(cur.cp_time);
14187715Smarkm	if (sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0)
14287715Smarkm	    || len != sizeof(cur.cp_time)) {
14369141Srwatson		perror("kern.cp_time");
14469141Srwatson		exit (1);
14569141Srwatson	}
14639230Sgibbs	tmp_dinfo = last.dinfo;
14739230Sgibbs	last.dinfo = cur.dinfo;
14839230Sgibbs	cur.dinfo = tmp_dinfo;
149121836Stjr
150121836Stjr	last.snap_time = cur.snap_time;
151158161Sbde
15239230Sgibbs	/*
15339230Sgibbs	 * Here what we want to do is refresh our device stats.
15439230Sgibbs	 * getdevs() returns 1 when the device list has changed.
15539230Sgibbs	 * If the device list has changed, we want to go through
15639230Sgibbs	 * the selection process again, in case a device that we
15739230Sgibbs	 * were previously displaying has gone away.
15839230Sgibbs	 */
15983131Sken	switch (devstat_getdevs(NULL, &cur)) {
16039230Sgibbs	case -1:
16139230Sgibbs		errx(1, "%s", devstat_errbuf);
16239230Sgibbs		break;
16339230Sgibbs	case 1:
16439230Sgibbs		cmdiostat("refresh", NULL);
16539230Sgibbs		break;
16639230Sgibbs	default:
16739230Sgibbs		break;
16839230Sgibbs	}
16939230Sgibbs	num_devices = cur.dinfo->numdevs;
17039230Sgibbs	generation = cur.dinfo->generation;
17139230Sgibbs
1721590Srgrimes}
1731590Srgrimes
1741590Srgrimes#define	INSET	10
1751590Srgrimes
1761590Srgrimesvoid
177175387Sdelphijlabeliostat(void)
1781590Srgrimes{
1791590Srgrimes	int row;
1801590Srgrimes
1811590Srgrimes	row = 0;
1821590Srgrimes	wmove(wnd, row, 0); wclrtobot(wnd);
1831590Srgrimes	mvwaddstr(wnd, row++, INSET,
184164689Syar	    "/0%  /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
1851590Srgrimes	mvwaddstr(wnd, row++, 0, "cpu  user|");
1861590Srgrimes	mvwaddstr(wnd, row++, 0, "     nice|");
1871590Srgrimes	mvwaddstr(wnd, row++, 0, "   system|");
1884930Sbde	mvwaddstr(wnd, row++, 0, "interrupt|");
1891590Srgrimes	mvwaddstr(wnd, row++, 0, "     idle|");
1901590Srgrimes	if (numbers)
1911590Srgrimes		row = numlabels(row + 1);
1921590Srgrimes	else
1931590Srgrimes		row = barlabels(row + 1);
1941590Srgrimes}
1951590Srgrimes
1961590Srgrimesstatic int
197175387Sdelphijnumlabels(int row)
1981590Srgrimes{
19987715Smarkm	int i, _col, regions, ndrives;
20039230Sgibbs	char tmpstr[10];
2011590Srgrimes
20239230Sgibbs#define COLWIDTH	17
20350635Speter#define DRIVESPERLINE	((wnd->_maxx - INSET) / COLWIDTH)
20439230Sgibbs	for (ndrives = 0, i = 0; i < num_devices; i++)
20539230Sgibbs		if (dev_select[i].selected)
2061590Srgrimes			ndrives++;
2071590Srgrimes	regions = howmany(ndrives, DRIVESPERLINE);
2081590Srgrimes	/*
2091590Srgrimes	 * Deduct -regions for blank line after each scrolling region.
2101590Srgrimes	 */
21150635Speter	linesperregion = (wnd->_maxy - row - regions) / regions;
2121590Srgrimes	/*
2131590Srgrimes	 * Minimum region contains space for two
2141590Srgrimes	 * label lines and one line of statistics.
2151590Srgrimes	 */
2161590Srgrimes	if (linesperregion < 3)
2171590Srgrimes		linesperregion = 3;
21887715Smarkm	_col = INSET;
21939230Sgibbs	for (i = 0; i < num_devices; i++)
22039230Sgibbs		if (dev_select[i].selected) {
22187715Smarkm			if (_col + COLWIDTH >= wnd->_maxx - INSET) {
22287715Smarkm				_col = INSET, row += linesperregion + 1;
22350635Speter				if (row > wnd->_maxy - (linesperregion + 1))
2241590Srgrimes					break;
2251590Srgrimes			}
22639230Sgibbs			sprintf(tmpstr, "%s%d", dev_select[i].device_name,
22739230Sgibbs				dev_select[i].unit_number);
22887715Smarkm			mvwaddstr(wnd, row, _col + 4, tmpstr);
22987715Smarkm			mvwaddstr(wnd, row + 1, _col, "  KB/t tps  MB/s ");
23087715Smarkm			_col += COLWIDTH;
2311590Srgrimes		}
23287715Smarkm	if (_col)
2331590Srgrimes		row += linesperregion + 1;
2341590Srgrimes	return (row);
2351590Srgrimes}
2361590Srgrimes
2371590Srgrimesstatic int
238175387Sdelphijbarlabels(int row)
2391590Srgrimes{
2401590Srgrimes	int i;
24139230Sgibbs	char tmpstr[10];
2421590Srgrimes
2431590Srgrimes	mvwaddstr(wnd, row++, INSET,
244164689Syar	    "/0%  /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
24539230Sgibbs	linesperregion = 2 + kbpt;
24639230Sgibbs	for (i = 0; i < num_devices; i++)
24739230Sgibbs		if (dev_select[i].selected) {
24850635Speter			if (row > wnd->_maxy - linesperregion)
2491590Srgrimes				break;
25039230Sgibbs			sprintf(tmpstr, "%s%d", dev_select[i].device_name,
25139230Sgibbs				dev_select[i].unit_number);
252158161Sbde			mvwprintw(wnd, row++, 0, "%-5.5s MB/s|",
25339230Sgibbs				  tmpstr);
2541590Srgrimes			mvwaddstr(wnd, row++, 0, "      tps|");
25539230Sgibbs			if (kbpt)
25639230Sgibbs				mvwaddstr(wnd, row++, 0, "     KB/t|");
2571590Srgrimes		}
2581590Srgrimes	return (row);
2591590Srgrimes}
2601590Srgrimes
2611590Srgrimes
2621590Srgrimesvoid
263175387Sdelphijshowiostat(void)
2641590Srgrimes{
26587715Smarkm	long t;
26687715Smarkm	int i, row, _col;
2671590Srgrimes
26839230Sgibbs#define X(fld)	t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t
2691590Srgrimes	etime = 0;
2701590Srgrimes	for(i = 0; i < CPUSTATES; i++) {
2711590Srgrimes		X(cp_time);
27239230Sgibbs		etime += cur.cp_time[i];
2731590Srgrimes	}
2741590Srgrimes	if (etime == 0.0)
2751590Srgrimes		etime = 1.0;
2764930Sbde	etime /= hertz;
2771590Srgrimes	row = 1;
2784930Sbde	for (i = 0; i < CPUSTATES; i++)
2791590Srgrimes		stat1(row++, i);
2801590Srgrimes	if (!numbers) {
2811590Srgrimes		row += 2;
28239230Sgibbs		for (i = 0; i < num_devices; i++)
28339230Sgibbs			if (dev_select[i].selected) {
28450635Speter				if (row > wnd->_maxy - linesperregion)
2851590Srgrimes					break;
28639230Sgibbs				row = devstats(row, INSET, i);
2871590Srgrimes			}
2881590Srgrimes		return;
2891590Srgrimes	}
29087715Smarkm	_col = INSET;
2911590Srgrimes	wmove(wnd, row + linesperregion, 0);
2921590Srgrimes	wdeleteln(wnd);
2931590Srgrimes	wmove(wnd, row + 3, 0);
2941590Srgrimes	winsertln(wnd);
29539230Sgibbs	for (i = 0; i < num_devices; i++)
29639230Sgibbs		if (dev_select[i].selected) {
29787715Smarkm			if (_col + COLWIDTH >= wnd->_maxx - INSET) {
29887715Smarkm				_col = INSET, row += linesperregion + 1;
29950635Speter				if (row > wnd->_maxy - (linesperregion + 1))
3001590Srgrimes					break;
3011590Srgrimes				wmove(wnd, row + linesperregion, 0);
3021590Srgrimes				wdeleteln(wnd);
3031590Srgrimes				wmove(wnd, row + 3, 0);
3041590Srgrimes				winsertln(wnd);
3051590Srgrimes			}
30687715Smarkm			(void) devstats(row + 3, _col, i);
30787715Smarkm			_col += COLWIDTH;
3081590Srgrimes		}
3091590Srgrimes}
3101590Srgrimes
3111590Srgrimesstatic int
312175387Sdelphijdevstats(int row, int _col, int dn)
3131590Srgrimes{
31439230Sgibbs	long double transfers_per_second;
31539230Sgibbs	long double kb_per_transfer, mb_per_second;
31639230Sgibbs	long double busy_seconds;
31739230Sgibbs	int di;
318158161Sbde
31939230Sgibbs	di = dev_select[dn].position;
3201590Srgrimes
321112288Sphk	busy_seconds = cur.snap_time - last.snap_time;
32239230Sgibbs
32383131Sken	if (devstat_compute_statistics(&cur.dinfo->devices[di],
32483131Sken	    &last.dinfo->devices[di], busy_seconds,
32583131Sken	    DSM_KB_PER_TRANSFER, &kb_per_transfer,
32683131Sken	    DSM_TRANSFERS_PER_SECOND, &transfers_per_second,
32783131Sken	    DSM_MB_PER_SECOND, &mb_per_second, DSM_NONE) != 0)
32839230Sgibbs		errx(1, "%s", devstat_errbuf);
32939230Sgibbs
3301590Srgrimes	if (numbers) {
33187715Smarkm		mvwprintw(wnd, row, _col, " %5.2Lf %3.0Lf %5.2Lf ",
33239230Sgibbs			 kb_per_transfer, transfers_per_second,
33339230Sgibbs			 mb_per_second);
33439230Sgibbs		return(row);
3351590Srgrimes	}
33687715Smarkm	wmove(wnd, row++, _col);
33761148Sphk	histogram(mb_per_second, 50, .5);
33887715Smarkm	wmove(wnd, row++, _col);
33961148Sphk	histogram(transfers_per_second, 50, .5);
34039230Sgibbs	if (kbpt) {
34187715Smarkm		wmove(wnd, row++, _col);
34261148Sphk		histogram(kb_per_transfer, 50, .5);
3431590Srgrimes	}
34439230Sgibbs
34539230Sgibbs	return(row);
34639230Sgibbs
3471590Srgrimes}
3481590Srgrimes
3491590Srgrimesstatic void
350175387Sdelphijstat1(int row, int o)
3511590Srgrimes{
35287715Smarkm	int i;
35387715Smarkm	double dtime;
3541590Srgrimes
35587715Smarkm	dtime = 0.0;
3561590Srgrimes	for (i = 0; i < CPUSTATES; i++)
35787715Smarkm		dtime += cur.cp_time[i];
35887715Smarkm	if (dtime == 0.0)
35987715Smarkm		dtime = 1.0;
3601590Srgrimes	wmove(wnd, row, INSET);
3611590Srgrimes#define CPUSCALE	0.5
36287715Smarkm	histogram(100.0 * cur.cp_time[o] / dtime, 50, CPUSCALE);
3631590Srgrimes}
3641590Srgrimes
3651590Srgrimesstatic void
366175387Sdelphijhistogram(long double val, int colwidth, double scale)
3671590Srgrimes{
3681590Srgrimes	char buf[10];
36987715Smarkm	int k;
37087715Smarkm	int v = (int)(val * scale) + 0.5;
3711590Srgrimes
3721590Srgrimes	k = MIN(v, colwidth);
3731590Srgrimes	if (v > colwidth) {
37439230Sgibbs		snprintf(buf, sizeof(buf), "%5.2Lf", val);
3751590Srgrimes		k -= strlen(buf);
3761590Srgrimes		while (k--)
3771590Srgrimes			waddch(wnd, 'X');
3781590Srgrimes		waddstr(wnd, buf);
3791590Srgrimes		return;
3801590Srgrimes	}
3811590Srgrimes	while (k--)
3821590Srgrimes		waddch(wnd, 'X');
3831590Srgrimes	wclrtoeol(wnd);
3841590Srgrimes}
3851590Srgrimes
3861590Srgrimesint
387175387Sdelphijcmdiostat(const char *cmd, const char *args)
3881590Srgrimes{
3891590Srgrimes
39039230Sgibbs	if (prefix(cmd, "kbpt"))
39139230Sgibbs		kbpt = !kbpt;
3921590Srgrimes	else if (prefix(cmd, "numbers"))
3931590Srgrimes		numbers = 1;
3941590Srgrimes	else if (prefix(cmd, "bars"))
3951590Srgrimes		numbers = 0;
39639230Sgibbs	else if (!dscmd(cmd, args, 100, &cur))
3971590Srgrimes		return (0);
3981590Srgrimes	wclear(wnd);
3991590Srgrimes	labeliostat();
4001590Srgrimes	refresh();
4011590Srgrimes	return (1);
4021590Srgrimes}
403