iostat.c revision 1.31
1/*	$NetBSD: iostat.c,v 1.31 2005/02/26 22:11:06 dsl Exp $	*/
2
3/*
4 * Copyright (c) 1980, 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#ifndef lint
34#if 0
35static char sccsid[] = "@(#)iostat.c	8.1 (Berkeley) 6/6/93";
36#endif
37__RCSID("$NetBSD: iostat.c,v 1.31 2005/02/26 22:11:06 dsl Exp $");
38#endif /* not lint */
39
40#include <sys/param.h>
41
42#include <string.h>
43
44#include "systat.h"
45#include "extern.h"
46#include "dkstats.h"
47
48static  int linesperregion;
49static  double etime;
50static  int numbers = 0;		/* default display bar graphs */
51static  int secs = 0;			/* default seconds shown */
52static  int read_write = 0;		/* default read/write shown */
53
54static int barlabels(int);
55static void histogram(double, int, double);
56static int numlabels(int);
57static int stats(int, int, int);
58static void stat1(int, int);
59
60
61WINDOW *
62openiostat(void)
63{
64
65	return (subwin(stdscr, -1, 0, 5, 0));
66}
67
68void
69closeiostat(WINDOW *w)
70{
71
72	if (w == NULL)
73		return;
74	wclear(w);
75	wrefresh(w);
76	delwin(w);
77}
78
79int
80initiostat(void)
81{
82
83	dkinit(1);
84	dkreadstats();
85	return(1);
86}
87
88void
89fetchiostat(void)
90{
91
92	if (dk_ndrive == 0)
93		return;
94	dkreadstats();
95}
96
97#define	INSET	14
98
99void
100labeliostat(void)
101{
102	int row;
103
104	if (dk_ndrive == 0) {
105		error("No drives defined.");
106		return;
107	}
108	row = 0;
109	wmove(wnd, row, 0); wclrtobot(wnd);
110	mvwaddstr(wnd, row++, INSET,
111	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
112	mvwaddstr(wnd, row++, 0, "    CPU  user|");
113	mvwaddstr(wnd, row++, 0, "         nice|");
114	mvwaddstr(wnd, row++, 0, "       system|");
115	mvwaddstr(wnd, row++, 0, "    interrupt|");
116	mvwaddstr(wnd, row++, 0, "         idle|");
117	if (numbers)
118		row = numlabels(row + 1);
119	else
120		row = barlabels(row + 1);
121}
122
123static int
124numlabels(int row)
125{
126	int i, col, regions, ndrives;
127
128#define COLWIDTH	(8 + secs * 5 + read_write * 9 + 2)
129#define DRIVESPERLINE	((getmaxx(wnd) + 1) / COLWIDTH)
130	for (ndrives = 0, i = 0; i < dk_ndrive; i++)
131		if (cur.dk_select[i])
132			ndrives++;
133	regions = howmany(ndrives, DRIVESPERLINE);
134	/*
135	 * Deduct -regions for blank line after each scrolling region.
136	 */
137	linesperregion = (getmaxy(wnd) - row - regions + 1) / regions;
138	/*
139	 * Minimum region contains space for two
140	 * label lines and one line of statistics.
141	 */
142	if (linesperregion < 3)
143		linesperregion = 3;
144	col = 0;
145	for (i = 0; i < dk_ndrive; i++)
146		if (cur.dk_select[i]) {
147			if (col + COLWIDTH - 1 > getmaxx(wnd)) {
148				col = 0, row += linesperregion + 1;
149				if (row > getmaxy(wnd) - (linesperregion))
150					break;
151			}
152			mvwprintw(wnd, row, col + 4, "%s", cur.dk_name[i]);
153			if (read_write)
154				mvwprintw(wnd, row, col + 9 + secs * 5,
155				    "(write)");
156			mvwprintw(wnd, row + 1, col, "kBps %s",
157				read_write ? "r/s" : "tps");
158			if (secs)
159				waddstr(wnd, "  sec");
160			if (read_write)
161				waddstr(wnd, " kBps w/s");
162			col += COLWIDTH;
163		}
164	if (col)
165		row += linesperregion + 1;
166	return (row);
167}
168
169static int
170barlabels(int row)
171{
172	int i;
173
174	mvwaddstr(wnd, row++, INSET,
175	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
176	linesperregion = 2 + secs + (read_write ? 2 : 0);
177	for (i = 0; i < dk_ndrive; i++)
178		if (cur.dk_select[i]) {
179			if (row > getmaxy(wnd) - linesperregion)
180				break;
181			mvwprintw(wnd, row++, 0, "%7.7s  kBps|",
182			    cur.dk_name[i]);
183			mvwaddstr(wnd, row++, 0, "          tps|");
184			if (read_write) {
185				mvwprintw(wnd, row++, 0, " (write) kBps|");
186				mvwaddstr(wnd, row++, 0, "          tps|");
187			}
188			if (secs)
189				mvwaddstr(wnd, row++, 0, "         msec|");
190		}
191	return (row);
192}
193
194void
195showiostat(void)
196{
197	int i, row, col;
198
199	if (dk_ndrive == 0)
200		return;
201	dkswap();
202
203	etime = cur.cp_etime;
204	row = 1;
205
206	/*
207	 * Interrupt CPU state not calculated yet.
208	 */
209	for (i = 0; i < CPUSTATES; i++)
210		stat1(row++, i);
211	if (!numbers) {
212		row += 2;
213		for (i = 0; i < dk_ndrive; i++)
214			if (cur.dk_select[i]) {
215				if (row > getmaxy(wnd) - linesperregion)
216					break;
217				row = stats(row, INSET, i);
218			}
219		return;
220	}
221	col = 0;
222	wmove(wnd, row + linesperregion, 0);
223	wdeleteln(wnd);
224	wmove(wnd, row + 3, 0);
225	winsertln(wnd);
226	for (i = 0; i < dk_ndrive; i++)
227		if (cur.dk_select[i]) {
228			if (col + COLWIDTH - 1 > getmaxx(wnd)) {
229				col = 0, row += linesperregion + 1;
230				if (row > getmaxy(wnd) - (linesperregion + 1))
231					break;
232				wmove(wnd, row + linesperregion, 0);
233				wdeleteln(wnd);
234				wmove(wnd, row + 3, 0);
235				winsertln(wnd);
236			}
237			(void) stats(row + 3, col, i);
238			col += COLWIDTH;
239		}
240}
241
242static int
243stats(int row, int col, int dn)
244{
245	double atime, rwords, wwords;
246	uint64_t rxfer;
247
248	/* time busy in disk activity */
249	atime = (double)cur.dk_time[dn].tv_sec +
250		((double)cur.dk_time[dn].tv_usec / (double)1000000);
251
252	/* # of k transferred */
253	rwords = cur.dk_rbytes[dn] / 1024.0;
254	wwords = cur.dk_wbytes[dn] / 1024.0;
255	rxfer = cur.dk_rxfer[dn];
256	if (!read_write) {
257		rwords = wwords;
258		rxfer += cur.dk_wxfer[dn];
259	}
260	if (numbers) {
261		mvwprintw(wnd, row, col, "%4.0f%4.0f",
262		    rwords / etime, rxfer / etime);
263		if (secs)
264			wprintw(wnd, "%5.1f", atime / etime);
265		if (read_write)
266			wprintw(wnd, " %4.0f%4.0f",
267			    wwords / etime, cur.dk_wxfer[dn] / etime);
268		return (row);
269	}
270
271	wmove(wnd, row++, col);
272	histogram(rwords / etime, 50, 0.5);
273	wmove(wnd, row++, col);
274	histogram(rxfer / etime, 50, 0.5);
275	if (read_write) {
276		wmove(wnd, row++, col);
277		histogram(wwords / etime, 50, 0.5);
278		wmove(wnd, row++, col);
279		histogram(cur.dk_wxfer[dn] / etime, 50, 0.5);
280	}
281
282	if (secs) {
283		wmove(wnd, row++, col);
284		atime *= 1000;	/* In milliseconds */
285		histogram(atime / etime, 50, 0.5);
286	}
287	return (row);
288}
289
290static void
291stat1(int row, int o)
292{
293	int i;
294	double total_time;
295
296	total_time = 0;
297	for (i = 0; i < CPUSTATES; i++)
298		total_time += cur.cp_time[i];
299	if (total_time == 0.0)
300		total_time = 1.0;
301	wmove(wnd, row, INSET);
302#define CPUSCALE	0.5
303	histogram(100.0 * cur.cp_time[o] / total_time, 50, CPUSCALE);
304}
305
306static void
307histogram(double val, int colwidth, double scale)
308{
309	int v = (int)(val * scale + 0.5);
310	int factor = 1;
311	int y, x;
312
313	while (v > colwidth) {
314		v = (v + 5) / 10;
315		factor *= 10;
316	}
317	getyx(wnd, y, x);
318	wclrtoeol(wnd);
319	whline(wnd, 'X', v);
320	if (factor != 1)
321		mvwprintw(wnd, y, x + colwidth + 1, "* %d ", factor);
322}
323
324void
325iostat_bars(char *args)
326{
327	numbers = 0;
328	wclear(wnd);
329	labeliostat();
330	refresh();
331}
332
333void
334iostat_numbers(char *args)
335{
336	numbers = 1;
337	wclear(wnd);
338	labeliostat();
339	refresh();
340}
341
342void
343iostat_secs(char *args)
344{
345	secs = !secs;
346	wclear(wnd);
347	labeliostat();
348	refresh();
349}
350
351void
352iostat_rw(char *args)
353{
354	read_write ^= 1;
355	wclear(wnd);
356	labeliostat();
357	refresh();
358}
359
360void
361iostat_all(char *args)
362{
363	read_write = 0;
364	wclear(wnd);
365	labeliostat();
366	refresh();
367}
368