xref: /netbsd-src/usr.bin/systat/iostat.c (revision 6b2ce0800ea603257f1adcc2fdd1fd535ec94e2a)
1*6b2ce080Schristos /*	$NetBSD: iostat.c,v 1.39 2019/01/25 15:31:11 christos Exp $	*/
22f3cb7aeSjtc 
312749a2aSjtc /*
412749a2aSjtc  * Copyright (c) 1980, 1992, 1993
512749a2aSjtc  *	The Regents of the University of California.  All rights reserved.
612749a2aSjtc  *
712749a2aSjtc  * Redistribution and use in source and binary forms, with or without
812749a2aSjtc  * modification, are permitted provided that the following conditions
912749a2aSjtc  * are met:
1012749a2aSjtc  * 1. Redistributions of source code must retain the above copyright
1112749a2aSjtc  *    notice, this list of conditions and the following disclaimer.
1212749a2aSjtc  * 2. Redistributions in binary form must reproduce the above copyright
1312749a2aSjtc  *    notice, this list of conditions and the following disclaimer in the
1412749a2aSjtc  *    documentation and/or other materials provided with the distribution.
1589aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
1612749a2aSjtc  *    may be used to endorse or promote products derived from this software
1712749a2aSjtc  *    without specific prior written permission.
1812749a2aSjtc  *
1912749a2aSjtc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2012749a2aSjtc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2112749a2aSjtc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2212749a2aSjtc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2312749a2aSjtc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2412749a2aSjtc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2512749a2aSjtc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2612749a2aSjtc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2712749a2aSjtc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2812749a2aSjtc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2912749a2aSjtc  * SUCH DAMAGE.
3012749a2aSjtc  */
3112749a2aSjtc 
3259413993Smrg #include <sys/cdefs.h>
3312749a2aSjtc #ifndef lint
342f3cb7aeSjtc #if 0
3512749a2aSjtc static char sccsid[] = "@(#)iostat.c	8.1 (Berkeley) 6/6/93";
362f3cb7aeSjtc #endif
37*6b2ce080Schristos __RCSID("$NetBSD: iostat.c,v 1.39 2019/01/25 15:31:11 christos Exp $");
38d594ce93Scgd #endif /* not lint */
3912749a2aSjtc 
4012749a2aSjtc #include <sys/param.h>
4112749a2aSjtc 
4212749a2aSjtc #include <string.h>
43828483a7Ssimonb 
4412749a2aSjtc #include "systat.h"
4512749a2aSjtc #include "extern.h"
46e48af18bSblymn #include "drvstats.h"
4712749a2aSjtc 
4812749a2aSjtc static  int linesperregion;
4912749a2aSjtc static  int numbers = 0;		/* default display bar graphs */
501eaf5ee3Sthorpej static  int secs = 0;			/* default seconds shown */
513cf4c73dSmrg static  int read_write = 0;		/* default read/write shown */
5212749a2aSjtc 
53fc391547Sad static int barlabels(int);
54fc391547Sad static void histogram(double, int, double);
55fc391547Sad static int numlabels(int);
56fc391547Sad static int stats(int, int, int);
57fc391547Sad static void stat1(int, int);
5812749a2aSjtc 
5912749a2aSjtc 
6012749a2aSjtc WINDOW *
openiostat(void)61fc391547Sad openiostat(void)
6212749a2aSjtc {
6359413993Smrg 
649f46bb07Sdsl 	return (subwin(stdscr, -1, 0, 5, 0));
6512749a2aSjtc }
6612749a2aSjtc 
6712749a2aSjtc void
closeiostat(WINDOW * w)68fc391547Sad closeiostat(WINDOW *w)
6912749a2aSjtc {
7059413993Smrg 
7112749a2aSjtc 	if (w == NULL)
7212749a2aSjtc 		return;
7312749a2aSjtc 	wclear(w);
7412749a2aSjtc 	wrefresh(w);
7512749a2aSjtc 	delwin(w);
7612749a2aSjtc }
7712749a2aSjtc 
7812749a2aSjtc int
initiostat(void)79fc391547Sad initiostat(void)
8012749a2aSjtc {
8159413993Smrg 
82e48af18bSblymn 	drvinit(1);
830283f983Sdsl 	cpureadstats();
84e48af18bSblymn 	drvreadstats();
8559413993Smrg 	return(1);
8612749a2aSjtc }
8712749a2aSjtc 
8812749a2aSjtc void
fetchiostat(void)89fc391547Sad fetchiostat(void)
9012749a2aSjtc {
9159413993Smrg 
920283f983Sdsl 	cpureadstats();
930283f983Sdsl 
94e48af18bSblymn 	if (ndrive != 0)
95e48af18bSblymn 		drvreadstats();
9612749a2aSjtc }
9712749a2aSjtc 
98d278ba38Smjl #define	INSET	14
9912749a2aSjtc 
10012749a2aSjtc void
labeliostat(void)101fc391547Sad labeliostat(void)
10212749a2aSjtc {
10312749a2aSjtc 	int row;
10412749a2aSjtc 
105e48af18bSblymn 	if (ndrive == 0) {
1061eaf5ee3Sthorpej 		error("No drives defined.");
10712749a2aSjtc 		return;
10812749a2aSjtc 	}
10912749a2aSjtc 	row = 0;
11012749a2aSjtc 	wmove(wnd, row, 0); wclrtobot(wnd);
11112749a2aSjtc 	mvwaddstr(wnd, row++, INSET,
11212749a2aSjtc 	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
113d20841bbSwiz 	mvwaddstr(wnd, row++, 0, "    CPU  user|");
11412749a2aSjtc 	mvwaddstr(wnd, row++, 0, "         nice|");
11512749a2aSjtc 	mvwaddstr(wnd, row++, 0, "       system|");
11664806926Smycroft 	mvwaddstr(wnd, row++, 0, "    interrupt|");
11712749a2aSjtc 	mvwaddstr(wnd, row++, 0, "         idle|");
11812749a2aSjtc 	if (numbers)
11912749a2aSjtc 		row = numlabels(row + 1);
12012749a2aSjtc 	else
12112749a2aSjtc 		row = barlabels(row + 1);
12212749a2aSjtc }
12312749a2aSjtc 
12412749a2aSjtc static int
numlabels(int row)125fc391547Sad numlabels(int row)
12612749a2aSjtc {
127e7a39c4fSlukem 	int col, regions;
128e7a39c4fSlukem 	size_t i, ndrives;
12912749a2aSjtc 
130f62ff76fSdsl #define COLWIDTH	(9 + secs * 5 + 1 + read_write * 9 + 1)
13155a20c51Sdsl #define DRIVESPERLINE	((getmaxx(wnd) + 1) / COLWIDTH)
132e48af18bSblymn 	for (ndrives = 0, i = 0; i < ndrive; i++)
133e48af18bSblymn 		if (cur.select[i])
134132bb1feSblymn 			ndrives++;
135132bb1feSblymn 
13612749a2aSjtc 	regions = howmany(ndrives, DRIVESPERLINE);
13712749a2aSjtc 	/*
13812749a2aSjtc 	 * Deduct -regions for blank line after each scrolling region.
13912749a2aSjtc 	 */
14055a20c51Sdsl 	linesperregion = (getmaxy(wnd) - row - regions + 1) / regions;
14112749a2aSjtc 	/*
14212749a2aSjtc 	 * Minimum region contains space for two
14312749a2aSjtc 	 * label lines and one line of statistics.
14412749a2aSjtc 	 */
14512749a2aSjtc 	if (linesperregion < 3)
14612749a2aSjtc 		linesperregion = 3;
14712749a2aSjtc 	col = 0;
148e48af18bSblymn 	for (i = 0; i < ndrive; i++)
149e48af18bSblymn 		if (cur.select[i]) {
15055a20c51Sdsl 			if (col + COLWIDTH - 1 > getmaxx(wnd)) {
15112749a2aSjtc 				col = 0, row += linesperregion + 1;
15255a20c51Sdsl 				if (row > getmaxy(wnd) - (linesperregion))
15312749a2aSjtc 					break;
15412749a2aSjtc 			}
155132bb1feSblymn 
156e48af18bSblymn 			mvwprintw(wnd, row, col + 5, "%s", cur.name[i]);
157132bb1feSblymn 
1583cf4c73dSmrg 			if (read_write)
159f62ff76fSdsl 				mvwprintw(wnd, row, col + 11 + secs * 5,
160ff927e70Sdsl 				    "(write)");
161ff927e70Sdsl 			mvwprintw(wnd, row + 1, col, " kBps %s",
162ff927e70Sdsl 				read_write ? "r/s" : "tps");
163ff927e70Sdsl 			if (secs)
164ff927e70Sdsl 				waddstr(wnd, "  sec");
165ff927e70Sdsl 			if (read_write)
166ff927e70Sdsl 				waddstr(wnd, "  kBps w/s");
16712749a2aSjtc 			col += COLWIDTH;
16812749a2aSjtc 		}
16912749a2aSjtc 	if (col)
17012749a2aSjtc 		row += linesperregion + 1;
17112749a2aSjtc 	return (row);
17212749a2aSjtc }
17312749a2aSjtc 
17412749a2aSjtc static int
barlabels(int row)175fc391547Sad barlabels(int row)
17612749a2aSjtc {
177e7a39c4fSlukem 	size_t i;
17812749a2aSjtc 
17912749a2aSjtc 	mvwaddstr(wnd, row++, INSET,
1801eaf5ee3Sthorpej 	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
1813cf4c73dSmrg 	linesperregion = 2 + secs + (read_write ? 2 : 0);
182e48af18bSblymn 	for (i = 0; i < ndrive; i++) {
183e48af18bSblymn 		if (cur.select[i]) {
1848fd3f56fSjtc 			if (row > getmaxy(wnd) - linesperregion)
18512749a2aSjtc 				break;
1869f3eaa50Sthorpej 			mvwprintw(wnd, row++, 0, "%7.7s  kBps|",
187e48af18bSblymn 			    cur.name[i]);
18812749a2aSjtc 			mvwaddstr(wnd, row++, 0, "          tps|");
1893cf4c73dSmrg 			if (read_write) {
1903cf4c73dSmrg 				mvwprintw(wnd, row++, 0, " (write) kBps|");
1913cf4c73dSmrg 				mvwaddstr(wnd, row++, 0, "          tps|");
1923cf4c73dSmrg 			}
1931eaf5ee3Sthorpej 			if (secs)
1941eaf5ee3Sthorpej 				mvwaddstr(wnd, row++, 0, "         msec|");
19512749a2aSjtc 		}
196132bb1feSblymn 	}
197e48af18bSblymn 
19812749a2aSjtc 	return (row);
19912749a2aSjtc }
20012749a2aSjtc 
20112749a2aSjtc void
showiostat(void)202fc391547Sad showiostat(void)
20312749a2aSjtc {
204e7a39c4fSlukem 	int row, col;
205e7a39c4fSlukem 	size_t i;
20612749a2aSjtc 
207e48af18bSblymn 	if (ndrive == 0)
20812749a2aSjtc 		return;
2090283f983Sdsl 	cpuswap();
210e48af18bSblymn 	drvswap();
2111eaf5ee3Sthorpej 
212f80c7eebSsommerfeld 	etime = cur.cp_etime;
21312749a2aSjtc 	row = 1;
21412749a2aSjtc 
21512749a2aSjtc 	/*
21664806926Smycroft 	 * Interrupt CPU state not calculated yet.
21712749a2aSjtc 	 */
21864806926Smycroft 	for (i = 0; i < CPUSTATES; i++)
21912749a2aSjtc 		stat1(row++, i);
22012749a2aSjtc 	if (!numbers) {
22112749a2aSjtc 		row += 2;
222e48af18bSblymn 		for (i = 0; i < ndrive; i++)
223e48af18bSblymn 			if (cur.select[i]) {
2248fd3f56fSjtc 				if (row > getmaxy(wnd) - linesperregion)
22512749a2aSjtc 					break;
22612749a2aSjtc 				row = stats(row, INSET, i);
22712749a2aSjtc 			}
22812749a2aSjtc 		return;
22912749a2aSjtc 	}
23012749a2aSjtc 	col = 0;
23112749a2aSjtc 	wmove(wnd, row + linesperregion, 0);
23212749a2aSjtc 	wdeleteln(wnd);
23312749a2aSjtc 	wmove(wnd, row + 3, 0);
23412749a2aSjtc 	winsertln(wnd);
235e48af18bSblymn 	for (i = 0; i < ndrive; i++)
236e48af18bSblymn 		if (cur.select[i]) {
237132bb1feSblymn 			if (col + COLWIDTH - 1 > getmaxx(wnd)) {
238132bb1feSblymn 				col = 0, row += linesperregion + 1;
239132bb1feSblymn 				if (row > getmaxy(wnd) - (linesperregion + 1))
240132bb1feSblymn 					break;
241132bb1feSblymn 				wmove(wnd, row + linesperregion, 0);
242132bb1feSblymn 				wdeleteln(wnd);
243132bb1feSblymn 				wmove(wnd, row + 3, 0);
244132bb1feSblymn 				winsertln(wnd);
245132bb1feSblymn 			}
246132bb1feSblymn 			(void) stats(row + 3, col, i);
247132bb1feSblymn 			col += COLWIDTH;
248132bb1feSblymn 		}
24912749a2aSjtc }
25012749a2aSjtc 
25112749a2aSjtc static int
stats(int row,int col,int dn)252fc391547Sad stats(int row, int col, int dn)
25312749a2aSjtc {
2549368f38eSmlelstv 	double atime, dtime, rwords, wwords;
255ff927e70Sdsl 	uint64_t rxfer;
25612749a2aSjtc 
2579368f38eSmlelstv 	/* elapsed time for disk stats */
2589368f38eSmlelstv 	dtime = etime;
2599368f38eSmlelstv 	if (cur.timestamp[dn].tv_sec || cur.timestamp[dn].tv_usec)
2609368f38eSmlelstv 		dtime = (double)cur.timestamp[dn].tv_sec +
2619368f38eSmlelstv 			((double)cur.timestamp[dn].tv_usec / (double)1000000);
2629368f38eSmlelstv 
2631eaf5ee3Sthorpej 	/* time busy in disk activity */
264e48af18bSblymn 	atime = (double)cur.time[dn].tv_sec +
265e48af18bSblymn 		((double)cur.time[dn].tv_usec / (double)1000000);
2661eaf5ee3Sthorpej 
2673cf4c73dSmrg 	/* # of k transferred */
268e48af18bSblymn 	rwords = cur.rbytes[dn] / 1024.0;
269e48af18bSblymn 	wwords = cur.wbytes[dn] / 1024.0;
270e48af18bSblymn 	rxfer = cur.rxfer[dn];
271ff927e70Sdsl 	if (!read_write) {
272efc0bc90Sdsl 		rwords += wwords;
273e48af18bSblymn 		rxfer += cur.wxfer[dn];
274ff927e70Sdsl 	}
27512749a2aSjtc 	if (numbers) {
276f62ff76fSdsl 		mvwprintw(wnd, row, col, "%5.0f%4.0f",
2779368f38eSmlelstv 		    rwords / dtime, rxfer / dtime);
278ff927e70Sdsl 		if (secs)
2799368f38eSmlelstv 			wprintw(wnd, "%5.1f", atime / dtime);
2803cf4c73dSmrg 		if (read_write)
281f62ff76fSdsl 			wprintw(wnd, " %5.0f%4.0f",
2829368f38eSmlelstv 			    wwords / dtime, cur.wxfer[dn] / dtime);
28312749a2aSjtc 		return (row);
28412749a2aSjtc 	}
2853cf4c73dSmrg 
28612749a2aSjtc 	wmove(wnd, row++, col);
2879368f38eSmlelstv 	histogram(rwords / dtime, 50, 0.5);
28812749a2aSjtc 	wmove(wnd, row++, col);
2899368f38eSmlelstv 	histogram(rxfer / dtime, 50, 0.5);
290ff927e70Sdsl 	if (read_write) {
2913cf4c73dSmrg 		wmove(wnd, row++, col);
2929368f38eSmlelstv 		histogram(wwords / dtime, 50, 0.5);
2933cf4c73dSmrg 		wmove(wnd, row++, col);
2949368f38eSmlelstv 		histogram(cur.wxfer[dn] / dtime, 50, 0.5);
295132bb1feSblymn 	}
296132bb1feSblymn 
297132bb1feSblymn 	if (secs) {
298132bb1feSblymn 		wmove(wnd, row++, col);
299132bb1feSblymn 		atime *= 1000;	/* In milliseconds */
3009368f38eSmlelstv 		histogram(atime / dtime, 50, 0.5);
301132bb1feSblymn 	}
302132bb1feSblymn 	return (row);
303132bb1feSblymn }
304132bb1feSblymn 
30512749a2aSjtc static void
stat1(int row,int o)306fc391547Sad stat1(int row, int o)
30712749a2aSjtc {
308e7a39c4fSlukem 	size_t i;
309ff927e70Sdsl 	double total_time;
31012749a2aSjtc 
311ff927e70Sdsl 	total_time = 0;
31212749a2aSjtc 	for (i = 0; i < CPUSTATES; i++)
313ff927e70Sdsl 		total_time += cur.cp_time[i];
314ff927e70Sdsl 	if (total_time == 0.0)
315ff927e70Sdsl 		total_time = 1.0;
31612749a2aSjtc 	wmove(wnd, row, INSET);
31712749a2aSjtc #define CPUSCALE	0.5
318ff927e70Sdsl 	histogram(100.0 * cur.cp_time[o] / total_time, 50, CPUSCALE);
31912749a2aSjtc }
32012749a2aSjtc 
32112749a2aSjtc static void
histogram(double val,int colwidth,double scale)322fc391547Sad histogram(double val, int colwidth, double scale)
32312749a2aSjtc {
324b3467bbfSdsl 	int v = (int)(val * scale + 0.5);
325b3467bbfSdsl 	int factor = 1;
326b3467bbfSdsl 	int y, x;
32712749a2aSjtc 
328b3467bbfSdsl 	while (v > colwidth) {
329b3467bbfSdsl 		v = (v + 5) / 10;
330b3467bbfSdsl 		factor *= 10;
33112749a2aSjtc 	}
332b3467bbfSdsl 	getyx(wnd, y, x);
33312749a2aSjtc 	wclrtoeol(wnd);
334b3467bbfSdsl 	whline(wnd, 'X', v);
335b3467bbfSdsl 	if (factor != 1)
336b3467bbfSdsl 		mvwprintw(wnd, y, x + colwidth + 1, "* %d ", factor);
33712749a2aSjtc }
33812749a2aSjtc 
3394c0fbd4cSjwise void
iostat_bars(char * args)340fc391547Sad iostat_bars(char *args)
34112749a2aSjtc {
34212749a2aSjtc 	numbers = 0;
34312749a2aSjtc 	wclear(wnd);
34412749a2aSjtc 	labeliostat();
34512749a2aSjtc 	refresh();
3464c0fbd4cSjwise }
3474c0fbd4cSjwise 
3484c0fbd4cSjwise void
iostat_numbers(char * args)349fc391547Sad iostat_numbers(char *args)
3504c0fbd4cSjwise {
3514c0fbd4cSjwise 	numbers = 1;
3524c0fbd4cSjwise 	wclear(wnd);
3534c0fbd4cSjwise 	labeliostat();
3544c0fbd4cSjwise 	refresh();
3554c0fbd4cSjwise }
3564c0fbd4cSjwise 
3574c0fbd4cSjwise void
iostat_secs(char * args)358fc391547Sad iostat_secs(char *args)
3594c0fbd4cSjwise {
3604c0fbd4cSjwise 	secs = !secs;
3614c0fbd4cSjwise 	wclear(wnd);
3624c0fbd4cSjwise 	labeliostat();
3634c0fbd4cSjwise 	refresh();
36412749a2aSjtc }
3653cf4c73dSmrg 
3663cf4c73dSmrg void
iostat_rw(char * args)3673cf4c73dSmrg iostat_rw(char *args)
3683cf4c73dSmrg {
369ff927e70Sdsl 	read_write ^= 1;
3703cf4c73dSmrg 	wclear(wnd);
3713cf4c73dSmrg 	labeliostat();
3723cf4c73dSmrg 	refresh();
3733cf4c73dSmrg }
3743cf4c73dSmrg 
3753cf4c73dSmrg void
iostat_all(char * args)3763cf4c73dSmrg iostat_all(char *args)
3773cf4c73dSmrg {
3783cf4c73dSmrg 	read_write = 0;
3793cf4c73dSmrg 	wclear(wnd);
3803cf4c73dSmrg 	labeliostat();
3813cf4c73dSmrg 	refresh();
3823cf4c73dSmrg }
383