iostat.c revision 1.4
1/*	$NetBSD: iostat.c,v 1.5 1996/05/10 23:16:35 thorpej 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. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#ifndef lint
37#if 0
38static char sccsid[] = "@(#)iostat.c	8.1 (Berkeley) 6/6/93";
39#endif
40static char rcsid[] = "$NetBSD: iostat.c,v 1.5 1996/05/10 23:16:35 thorpej Exp $";
41#endif not lint
42
43#include <sys/param.h>
44#include <sys/dkstat.h>
45#include <sys/buf.h>
46#include <sys/time.h>
47
48#include <string.h>
49#include <stdlib.h>
50#include <nlist.h>
51#include <paths.h>
52#include "systat.h"
53#include "extern.h"
54
55#include "dkstats.h"
56extern struct _disk	cur;
57
58static  int linesperregion;
59static  double etime;
60static  int numbers = 0;		/* default display bar graphs */
61static  int secs = 0;			/* default seconds shown */
62
63static int barlabels __P((int));
64static void histogram __P((double, int, double));
65static int numlabels __P((int));
66static int stats __P((int, int, int));
67static void stat1 __P((int, int));
68
69
70WINDOW *
71openiostat()
72{
73	return (subwin(stdscr, LINES-1-5, 0, 5, 0));
74}
75
76void
77closeiostat(w)
78	WINDOW *w;
79{
80	if (w == NULL)
81		return;
82	wclear(w);
83	wrefresh(w);
84	delwin(w);
85}
86
87int
88initiostat()
89{
90	dkinit(1);
91	dkreadstats();
92}
93
94void
95fetchiostat()
96{
97	if (dk_ndrive == 0)
98		return;
99	dkreadstats();
100}
101
102#define	INSET	10
103
104void
105labeliostat()
106{
107	int row;
108
109	if (dk_ndrive == 0) {
110		error("No drives defined.");
111		return;
112	}
113	row = 0;
114	wmove(wnd, row, 0); wclrtobot(wnd);
115	mvwaddstr(wnd, row++, INSET,
116	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
117	mvwaddstr(wnd, row++, 0, "cpu  user|");
118	mvwaddstr(wnd, row++, 0, "     nice|");
119	mvwaddstr(wnd, row++, 0, "   system|");
120	mvwaddstr(wnd, row++, 0, "interrupt|");
121	mvwaddstr(wnd, row++, 0, "     idle|");
122	if (numbers)
123		row = numlabels(row + 1);
124	else
125		row = barlabels(row + 1);
126}
127
128static int
129numlabels(row)
130	int row;
131{
132	int i, col, regions, ndrives;
133
134#define COLWIDTH	14
135#define DRIVESPERLINE	((wnd->_maxx - INSET) / COLWIDTH)
136	for (ndrives = 0, i = 0; i < dk_ndrive; i++)
137		if (cur.dk_select[i])
138			ndrives++;
139	regions = howmany(ndrives, DRIVESPERLINE);
140	/*
141	 * Deduct -regions for blank line after each scrolling region.
142	 */
143	linesperregion = (wnd->_maxy - row - regions) / regions;
144	/*
145	 * Minimum region contains space for two
146	 * label lines and one line of statistics.
147	 */
148	if (linesperregion < 3)
149		linesperregion = 3;
150	col = 0;
151	for (i = 0; i < dk_ndrive; i++)
152		if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
153			if (col + COLWIDTH >= wnd->_maxx - INSET) {
154				col = 0, row += linesperregion + 1;
155				if (row > wnd->_maxy - (linesperregion + 1))
156					break;
157			}
158			mvwaddstr(wnd, row, col + 4, cur.dk_name[i]);
159			mvwaddstr(wnd, row + 1, col, "Kps tps  sec");
160			col += COLWIDTH;
161		}
162	if (col)
163		row += linesperregion + 1;
164	return (row);
165}
166
167static int
168barlabels(row)
169	int row;
170{
171	int i;
172
173	mvwaddstr(wnd, row++, INSET,
174	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
175	linesperregion = 2 + secs;
176	for (i = 0; i < dk_ndrive; i++)
177		if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
178			if (row > wnd->_maxy - linesperregion)
179				break;
180			mvwprintw(wnd, row++, 0, "%3.3s   Kps|", cur.dk_name[i]);
181			mvwaddstr(wnd, row++, 0, "      tps|");
182			if (secs)
183				mvwaddstr(wnd, row++, 0, "     msec|");
184		}
185	return (row);
186}
187
188
189void
190showiostat()
191{
192	register u_int64_t t;
193	register int i, row, col;
194
195	if (dk_ndrive == 0)
196		return;
197	dkswap();
198
199	etime = 0;
200	for(i = 0; i < CPUSTATES; i++) {
201		etime += cur.cp_time[i];
202	}
203	if (etime == 0.0)
204		etime = 1.0;
205	etime /= (float) hz;
206	row = 1;
207
208	/*
209	 * Interrupt CPU state not calculated yet.
210	 */
211	for (i = 0; i < CPUSTATES; i++)
212		stat1(row++, i);
213	if (!numbers) {
214		row += 2;
215		for (i = 0; i < dk_ndrive; i++)
216			if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
217				if (row > wnd->_maxy - linesperregion)
218					break;
219				row = stats(row, INSET, i);
220			}
221		return;
222	}
223	col = 0;
224	wmove(wnd, row + linesperregion, 0);
225	wdeleteln(wnd);
226	wmove(wnd, row + 3, 0);
227	winsertln(wnd);
228	for (i = 0; i < dk_ndrive; i++)
229		if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
230			if (col + COLWIDTH >= wnd->_maxx) {
231				col = 0, row += linesperregion + 1;
232				if (row > wnd->_maxy - (linesperregion + 1))
233					break;
234				wmove(wnd, row + linesperregion, 0);
235				wdeleteln(wnd);
236				wmove(wnd, row + 3, 0);
237				winsertln(wnd);
238			}
239			(void) stats(row + 3, col, i);
240			col += COLWIDTH;
241		}
242}
243
244static int
245stats(row, col, dn)
246	int row, col, dn;
247{
248	double atime, words;
249
250	/* time busy in disk activity */
251	atime = (double)cur.dk_time[dn].tv_sec +
252		((double)cur.dk_time[dn].tv_usec / (double)1000000);
253
254	words = cur.dk_bytes[dn] / 1024.0;	/* # of K transferred */
255	if (numbers) {
256		mvwprintw(wnd, row, col, "%3.0f%4.0f%5.1f",
257		    words / etime, cur.dk_xfer[dn] / etime, atime / etime);
258		return (row);
259	}
260	wmove(wnd, row++, col);
261	histogram(words / etime, 50, 0.5);
262	wmove(wnd, row++, col);
263	histogram(cur.dk_xfer[dn] / etime, 50, 0.5);
264	if (secs) {
265		wmove(wnd, row++, col);
266		atime *= 1000;	/* In milliseconds */
267		histogram(atime / etime, 50, 0.5);
268	}
269	return (row);
270}
271
272static void
273stat1(row, o)
274	int row, o;
275{
276	register int i;
277	double time;
278
279	time = 0;
280	for (i = 0; i < CPUSTATES; i++)
281		time += cur.cp_time[i];
282	if (time == 0.0)
283		time = 1.0;
284	wmove(wnd, row, INSET);
285#define CPUSCALE	0.5
286	histogram(100.0 * cur.cp_time[o] / time, 50, CPUSCALE);
287}
288
289static void
290histogram(val, colwidth, scale)
291	double val;
292	int colwidth;
293	double scale;
294{
295	char buf[10];
296	register int k;
297	register int v = (int)(val * scale) + 0.5;
298
299	k = MIN(v, colwidth);
300	if (v > colwidth) {
301		sprintf(buf, "%4.1f", val);
302		k -= strlen(buf);
303		while (k--)
304			waddch(wnd, 'X');
305		waddstr(wnd, buf);
306		wclrtoeol(wnd);
307		return;
308	}
309	while (k--)
310		waddch(wnd, 'X');
311	wclrtoeol(wnd);
312}
313
314int
315cmdiostat(cmd, args)
316	char *cmd, *args;
317{
318
319	if (prefix(cmd, "secs"))
320		secs = !secs;
321	else if (prefix(cmd, "numbers"))
322		numbers = 1;
323	else if (prefix(cmd, "bars"))
324		numbers = 0;
325	else if (!dkcmd(cmd, args))
326		return (0);
327	wclear(wnd);
328	labeliostat();
329	refresh();
330	return (1);
331}
332