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