iostat.c revision 200462
1184610Salfred/*
2184610Salfred * Copyright (c) 1998 Kenneth D. Merry.
3184610Salfred * All rights reserved.
4184610Salfred *
5184610Salfred * Redistribution and use in source and binary forms, with or without
6184610Salfred * modification, are permitted provided that the following conditions
7184610Salfred * are met:
8184610Salfred * 1. Redistributions of source code must retain the above copyright
9184610Salfred *    notice, this list of conditions and the following disclaimer.
10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer in the
12184610Salfred *    documentation and/or other materials provided with the distribution.
13184610Salfred * 3. The name of the author may not be used to endorse or promote products
14184610Salfred *    derived from this software without specific prior written permission.
15184610Salfred *
16184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26184610Salfred * SUCH DAMAGE.
27184610Salfred */
28184610Salfred/*
29184610Salfred * Copyright (c) 1980, 1992, 1993
30184610Salfred *	The Regents of the University of California.  All rights reserved.
31184610Salfred *
32184610Salfred * Redistribution and use in source and binary forms, with or without
33184610Salfred * modification, are permitted provided that the following conditions
34184610Salfred * are met:
35184610Salfred * 1. Redistributions of source code must retain the above copyright
36184610Salfred *    notice, this list of conditions and the following disclaimer.
37184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
38184610Salfred *    notice, this list of conditions and the following disclaimer in the
39184610Salfred *    documentation and/or other materials provided with the distribution.
40184610Salfred * 3. All advertising materials mentioning features or use of this software
41187170Sthompsa *    must display the following acknowledgement:
42187170Sthompsa *	This product includes software developed by the University of
43184610Salfred *	California, Berkeley and its contributors.
44184610Salfred * 4. Neither the name of the University nor the names of its contributors
45184610Salfred *    may be used to endorse or promote products derived from this software
46184610Salfred *    without specific prior written permission.
47184610Salfred *
48184610Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58184610Salfred * SUCH DAMAGE.
59184610Salfred */
60184610Salfred
61184610Salfred#include <sys/cdefs.h>
62184610Salfred
63184610Salfred__FBSDID("$FreeBSD: head/usr.bin/systat/iostat.c 200462 2009-12-13 03:14:06Z delphij $");
64184610Salfred
65184610Salfred#ifdef lint
66184610Salfredstatic const char sccsid[] = "@(#)iostat.c	8.1 (Berkeley) 6/6/93";
67184610Salfred#endif
68184610Salfred
69184610Salfred#include <sys/param.h>
70184610Salfred#include <sys/sysctl.h>
71184610Salfred#include <sys/resource.h>
72184610Salfred
73184610Salfred#include <devstat.h>
74184610Salfred#include <err.h>
75184610Salfred#include <nlist.h>
76184610Salfred#include <paths.h>
77184610Salfred#include <stdlib.h>
78184610Salfred#include <string.h>
79184610Salfred
80184610Salfred#include "systat.h"
81184610Salfred#include "extern.h"
82184610Salfred#include "devs.h"
83184610Salfred
84184610Salfredstruct statinfo cur, last;
85184610Salfred
86184610Salfredstatic  int linesperregion;
87184610Salfredstatic  double etime;
88184610Salfredstatic  int numbers = 0;		/* default display bar graphs */
89184610Salfredstatic  int kbpt = 0;			/* default ms/seek shown */
90184610Salfred
91184610Salfredstatic int barlabels(int);
92184610Salfredstatic void histogram(long double, int, double);
93184610Salfredstatic int numlabels(int);
94184610Salfredstatic int devstats(int, int, int);
95184610Salfredstatic void stat1(int, int);
96184610Salfred
97184610SalfredWINDOW *
98184610Salfredopeniostat(void)
99184610Salfred{
100184610Salfred	return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0));
101184610Salfred}
102184610Salfred
103184610Salfredvoid
104184610Salfredcloseiostat(WINDOW *w)
105184610Salfred{
106184610Salfred	if (w == NULL)
107184610Salfred		return;
108184610Salfred	wclear(w);
109184610Salfred	wrefresh(w);
110184610Salfred	delwin(w);
111184610Salfred}
112184610Salfred
113184610Salfredint
114184610Salfredinitiostat(void)
115184610Salfred{
116184610Salfred	if ((num_devices = devstat_getnumdevs(NULL)) < 0)
117184610Salfred		return(0);
118184610Salfred
119184610Salfred	cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
120184610Salfred	last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
121184610Salfred	bzero(cur.dinfo, sizeof(struct devinfo));
122184610Salfred	bzero(last.dinfo, sizeof(struct devinfo));
123184610Salfred
124184610Salfred	/*
125184610Salfred	 * This value for maxshowdevs (100) is bogus.  I'm not sure exactly
126184610Salfred	 * how to calculate it, though.
127184610Salfred	 */
128184610Salfred	if (dsinit(100, &cur, &last, NULL) != 1)
129184610Salfred		return(0);
130184610Salfred
131184610Salfred	return(1);
132184610Salfred}
133184610Salfred
134184610Salfredvoid
135184610Salfredfetchiostat(void)
136184610Salfred{
137184610Salfred	struct devinfo *tmp_dinfo;
138184610Salfred	size_t len;
139184610Salfred
140184610Salfred	len = sizeof(cur.cp_time);
141184610Salfred	if (sysctlbyname("kern.cp_time", &cur.cp_time, &len, NULL, 0)
142184610Salfred	    || len != sizeof(cur.cp_time)) {
143184610Salfred		perror("kern.cp_time");
144184610Salfred		exit (1);
145184610Salfred	}
146184610Salfred	tmp_dinfo = last.dinfo;
147184610Salfred	last.dinfo = cur.dinfo;
148184610Salfred	cur.dinfo = tmp_dinfo;
149184610Salfred
150184610Salfred	last.snap_time = cur.snap_time;
151184610Salfred
152184610Salfred	/*
153184610Salfred	 * Here what we want to do is refresh our device stats.
154184610Salfred	 * getdevs() returns 1 when the device list has changed.
155184610Salfred	 * If the device list has changed, we want to go through
156184610Salfred	 * the selection process again, in case a device that we
157184610Salfred	 * were previously displaying has gone away.
158184610Salfred	 */
159184610Salfred	switch (devstat_getdevs(NULL, &cur)) {
160184610Salfred	case -1:
161184610Salfred		errx(1, "%s", devstat_errbuf);
162184610Salfred		break;
163184610Salfred	case 1:
164184610Salfred		cmdiostat("refresh", NULL);
165186730Salfred		break;
166186730Salfred	default:
167186730Salfred		break;
168186730Salfred	}
169186730Salfred	num_devices = cur.dinfo->numdevs;
170186730Salfred	generation = cur.dinfo->generation;
171186730Salfred
172186730Salfred}
173186730Salfred
174184610Salfred#define	INSET	10
175184610Salfred
176184610Salfredvoid
177184610Salfredlabeliostat(void)
178184610Salfred{
179184610Salfred	int row;
180184610Salfred
181184610Salfred	row = 0;
182184610Salfred	wmove(wnd, row, 0); wclrtobot(wnd);
183184610Salfred	mvwaddstr(wnd, row++, INSET,
184184610Salfred	    "/0%  /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
185184610Salfred	mvwaddstr(wnd, row++, 0, "cpu  user|");
186184610Salfred	mvwaddstr(wnd, row++, 0, "     nice|");
187184610Salfred	mvwaddstr(wnd, row++, 0, "   system|");
188184610Salfred	mvwaddstr(wnd, row++, 0, "interrupt|");
189184610Salfred	mvwaddstr(wnd, row++, 0, "     idle|");
190184610Salfred	if (numbers)
191184610Salfred		row = numlabels(row + 1);
192184610Salfred	else
193184610Salfred		row = barlabels(row + 1);
194184610Salfred}
195184610Salfred
196184610Salfredstatic int
197184610Salfrednumlabels(int row)
198184610Salfred{
199184610Salfred	int i, _col, regions, ndrives;
200184610Salfred	char tmpstr[10];
201184610Salfred
202184610Salfred#define COLWIDTH	17
203184610Salfred#define DRIVESPERLINE	((wnd->_maxx - INSET) / COLWIDTH)
204184610Salfred	for (ndrives = 0, i = 0; i < num_devices; i++)
205184610Salfred		if (dev_select[i].selected)
206184610Salfred			ndrives++;
207184610Salfred	regions = howmany(ndrives, DRIVESPERLINE);
208184610Salfred	/*
209184610Salfred	 * Deduct -regions for blank line after each scrolling region.
210184610Salfred	 */
211184610Salfred	linesperregion = (wnd->_maxy - row - regions) / regions;
212184610Salfred	/*
213184610Salfred	 * Minimum region contains space for two
214184610Salfred	 * label lines and one line of statistics.
215184610Salfred	 */
216184610Salfred	if (linesperregion < 3)
217184610Salfred		linesperregion = 3;
218184610Salfred	_col = INSET;
219184610Salfred	for (i = 0; i < num_devices; i++)
220184610Salfred		if (dev_select[i].selected) {
221184610Salfred			if (_col + COLWIDTH >= wnd->_maxx - INSET) {
222184610Salfred				_col = INSET, row += linesperregion + 1;
223184610Salfred				if (row > wnd->_maxy - (linesperregion + 1))
224184610Salfred					break;
225184610Salfred			}
226184610Salfred			sprintf(tmpstr, "%s%d", dev_select[i].device_name,
227184610Salfred				dev_select[i].unit_number);
228184610Salfred			mvwaddstr(wnd, row, _col + 4, tmpstr);
229184610Salfred			mvwaddstr(wnd, row + 1, _col, "  KB/t tps  MB/s ");
230184610Salfred			_col += COLWIDTH;
231184610Salfred		}
232184610Salfred	if (_col)
233184610Salfred		row += linesperregion + 1;
234184610Salfred	return (row);
235184610Salfred}
236184610Salfred
237184610Salfredstatic int
238184610Salfredbarlabels(int row)
239184610Salfred{
240184610Salfred	int i;
241184610Salfred	char tmpstr[10];
242184610Salfred
243184610Salfred	mvwaddstr(wnd, row++, INSET,
244184610Salfred	    "/0%  /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
245184610Salfred	linesperregion = 2 + kbpt;
246184610Salfred	for (i = 0; i < num_devices; i++)
247184610Salfred		if (dev_select[i].selected) {
248184610Salfred			if (row > wnd->_maxy - linesperregion)
249184610Salfred				break;
250184610Salfred			sprintf(tmpstr, "%s%d", dev_select[i].device_name,
251184610Salfred				dev_select[i].unit_number);
252184610Salfred			mvwprintw(wnd, row++, 0, "%-5.5s MB/s|",
253184610Salfred				  tmpstr);
254184610Salfred			mvwaddstr(wnd, row++, 0, "      tps|");
255184610Salfred			if (kbpt)
256184610Salfred				mvwaddstr(wnd, row++, 0, "     KB/t|");
257184610Salfred		}
258184610Salfred	return (row);
259184610Salfred}
260184610Salfred
261184610Salfred
262184610Salfredvoid
263184610Salfredshowiostat(void)
264184610Salfred{
265184610Salfred	long t;
266184610Salfred	int i, row, _col;
267184610Salfred
268184610Salfred#define X(fld)	t = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = t
269184610Salfred	etime = 0;
270184610Salfred	for(i = 0; i < CPUSTATES; i++) {
271184610Salfred		X(cp_time);
272184610Salfred		etime += cur.cp_time[i];
273184610Salfred	}
274184610Salfred	if (etime == 0.0)
275184610Salfred		etime = 1.0;
276184610Salfred	etime /= hertz;
277184610Salfred	row = 1;
278184610Salfred	for (i = 0; i < CPUSTATES; i++)
279184610Salfred		stat1(row++, i);
280184610Salfred	if (!numbers) {
281184610Salfred		row += 2;
282184610Salfred		for (i = 0; i < num_devices; i++)
283184610Salfred			if (dev_select[i].selected) {
284184610Salfred				if (row > wnd->_maxy - linesperregion)
285184610Salfred					break;
286184610Salfred				row = devstats(row, INSET, i);
287184610Salfred			}
288184610Salfred		return;
289184610Salfred	}
290184610Salfred	_col = INSET;
291184610Salfred	wmove(wnd, row + linesperregion, 0);
292184610Salfred	wdeleteln(wnd);
293184610Salfred	wmove(wnd, row + 3, 0);
294184610Salfred	winsertln(wnd);
295184610Salfred	for (i = 0; i < num_devices; i++)
296184610Salfred		if (dev_select[i].selected) {
297184610Salfred			if (_col + COLWIDTH >= wnd->_maxx - INSET) {
298184610Salfred				_col = INSET, row += linesperregion + 1;
299184610Salfred				if (row > wnd->_maxy - (linesperregion + 1))
300184610Salfred					break;
301184610Salfred				wmove(wnd, row + linesperregion, 0);
302184610Salfred				wdeleteln(wnd);
303184610Salfred				wmove(wnd, row + 3, 0);
304184610Salfred				winsertln(wnd);
305184610Salfred			}
306184610Salfred			(void) devstats(row + 3, _col, i);
307184610Salfred			_col += COLWIDTH;
308184610Salfred		}
309184610Salfred}
310184610Salfred
311184610Salfredstatic int
312184610Salfreddevstats(int row, int _col, int dn)
313184610Salfred{
314184610Salfred	long double transfers_per_second;
315184610Salfred	long double kb_per_transfer, mb_per_second;
316184610Salfred	long double busy_seconds;
317184610Salfred	int di;
318184610Salfred
319184610Salfred	di = dev_select[dn].position;
320184610Salfred
321184610Salfred	busy_seconds = cur.snap_time - last.snap_time;
322184610Salfred
323184610Salfred	if (devstat_compute_statistics(&cur.dinfo->devices[di],
324184610Salfred	    &last.dinfo->devices[di], busy_seconds,
325184610Salfred	    DSM_KB_PER_TRANSFER, &kb_per_transfer,
326184610Salfred	    DSM_TRANSFERS_PER_SECOND, &transfers_per_second,
327184610Salfred	    DSM_MB_PER_SECOND, &mb_per_second, DSM_NONE) != 0)
328184610Salfred		errx(1, "%s", devstat_errbuf);
329184610Salfred
330184610Salfred	if (numbers) {
331184610Salfred		mvwprintw(wnd, row, _col, " %5.2Lf %3.0Lf %5.2Lf ",
332184610Salfred			 kb_per_transfer, transfers_per_second,
333184610Salfred			 mb_per_second);
334184610Salfred		return(row);
335184610Salfred	}
336184610Salfred	wmove(wnd, row++, _col);
337184610Salfred	histogram(mb_per_second, 50, .5);
338184610Salfred	wmove(wnd, row++, _col);
339184610Salfred	histogram(transfers_per_second, 50, .5);
340184610Salfred	if (kbpt) {
341184610Salfred		wmove(wnd, row++, _col);
342184610Salfred		histogram(kb_per_transfer, 50, .5);
343184610Salfred	}
344184610Salfred
345184610Salfred	return(row);
346184610Salfred
347184610Salfred}
348184610Salfred
349184610Salfredstatic void
350184610Salfredstat1(int row, int o)
351184610Salfred{
352184610Salfred	int i;
353184610Salfred	double dtime;
354184610Salfred
355184610Salfred	dtime = 0.0;
356184610Salfred	for (i = 0; i < CPUSTATES; i++)
357184610Salfred		dtime += cur.cp_time[i];
358184610Salfred	if (dtime == 0.0)
359184610Salfred		dtime = 1.0;
360184610Salfred	wmove(wnd, row, INSET);
361184610Salfred#define CPUSCALE	0.5
362184610Salfred	histogram(100.0 * cur.cp_time[o] / dtime, 50, CPUSCALE);
363184610Salfred}
364184610Salfred
365184610Salfredstatic void
366184610Salfredhistogram(long double val, int colwidth, double scale)
367184610Salfred{
368184610Salfred	char buf[10];
369184610Salfred	int k;
370184610Salfred	int v = (int)(val * scale) + 0.5;
371184610Salfred
372184610Salfred	k = MIN(v, colwidth);
373184610Salfred	if (v > colwidth) {
374184610Salfred		snprintf(buf, sizeof(buf), "%5.2Lf", val);
375184610Salfred		k -= strlen(buf);
376184610Salfred		while (k--)
377184610Salfred			waddch(wnd, 'X');
378184610Salfred		waddstr(wnd, buf);
379184610Salfred		return;
380184610Salfred	}
381184610Salfred	while (k--)
382184610Salfred		waddch(wnd, 'X');
383184610Salfred	wclrtoeol(wnd);
384184610Salfred}
385184610Salfred
386184610Salfredint
387184610Salfredcmdiostat(const char *cmd, const char *args)
388184610Salfred{
389184610Salfred
390184610Salfred	if (prefix(cmd, "kbpt"))
391184610Salfred		kbpt = !kbpt;
392184610Salfred	else if (prefix(cmd, "numbers"))
393184610Salfred		numbers = 1;
394184610Salfred	else if (prefix(cmd, "bars"))
395184610Salfred		numbers = 0;
396184610Salfred	else if (!dscmd(cmd, args, 100, &cur))
397184610Salfred		return (0);
398184610Salfred	wclear(wnd);
399184610Salfred	labeliostat();
400184610Salfred	refresh();
401184610Salfred	return (1);
402184610Salfred}
403184610Salfred