xref: /netbsd-src/usr.bin/systat/iostat.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
1 /*	$NetBSD: iostat.c,v 1.2 1995/01/20 08:51:57 jtc 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
38 static char sccsid[] = "@(#)iostat.c	8.1 (Berkeley) 6/6/93";
39 #endif
40 static char rcsid[] = "$NetBSD: iostat.c,v 1.2 1995/01/20 08:51:57 jtc Exp $";
41 #endif not lint
42 
43 #include <sys/param.h>
44 #include <sys/dkstat.h>
45 #include <sys/buf.h>
46 
47 #include <string.h>
48 #include <stdlib.h>
49 #include <nlist.h>
50 #include <paths.h>
51 #include "systat.h"
52 #include "extern.h"
53 
54 static struct nlist namelist[] = {
55 #define X_DK_BUSY	0
56 	{ "_dk_busy" },
57 #define X_DK_TIME	1
58 	{ "_dk_time" },
59 #define X_DK_XFER	2
60 	{ "_dk_xfer" },
61 #define X_DK_WDS	3
62 	{ "_dk_wds" },
63 #define X_DK_SEEK	4
64 	{ "_dk_seek" },
65 #define X_CP_TIME	5
66 	{ "_cp_time" },
67 #ifdef vax
68 #define X_MBDINIT	(X_CP_TIME+1)
69 	{ "_mbdinit" },
70 #define X_UBDINIT	(X_CP_TIME+2)
71 	{ "_ubdinit" },
72 #endif
73 #ifdef tahoe
74 #define	X_VBDINIT	(X_CP_TIME+1)
75 	{ "_vbdinit" },
76 #endif
77 	{ "" },
78 };
79 
80 static struct {
81 	int	dk_busy;
82 	long	cp_time[CPUSTATES];
83 	long	*dk_time;
84 	long	*dk_wds;
85 	long	*dk_seek;
86 	long	*dk_xfer;
87 } s, s1;
88 
89 static  int linesperregion;
90 static  double etime;
91 static  int numbers = 0;		/* default display bar graphs */
92 static  int msps = 0;			/* default ms/seek shown */
93 
94 static int barlabels __P((int));
95 static void histogram __P((double, int, double));
96 static int numlabels __P((int));
97 static int stats __P((int, int, int));
98 static void stat1 __P((int, int));
99 
100 
101 WINDOW *
102 openiostat()
103 {
104 	return (subwin(stdscr, LINES-1-5, 0, 5, 0));
105 }
106 
107 void
108 closeiostat(w)
109 	WINDOW *w;
110 {
111 	if (w == NULL)
112 		return;
113 	wclear(w);
114 	wrefresh(w);
115 	delwin(w);
116 }
117 
118 int
119 initiostat()
120 {
121 	if (namelist[X_DK_BUSY].n_type == 0) {
122 		if (kvm_nlist(kd, namelist)) {
123 			nlisterr(namelist);
124 			return(0);
125 		}
126 		if (namelist[X_DK_BUSY].n_type == 0) {
127 			error("Disk init information isn't in namelist");
128 			return(0);
129 		}
130 	}
131 	if (! dkinit())
132 		return(0);
133 	if (dk_ndrive) {
134 #define	allocate(e, t) \
135     s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
136     s1./**/e = (t *)calloc(dk_ndrive, sizeof (t));
137 		allocate(dk_time, long);
138 		allocate(dk_wds, long);
139 		allocate(dk_seek, long);
140 		allocate(dk_xfer, long);
141 #undef allocate
142 	}
143 	return(1);
144 }
145 
146 void
147 fetchiostat()
148 {
149 	if (namelist[X_DK_BUSY].n_type == 0)
150 		return;
151 	NREAD(X_DK_BUSY, &s.dk_busy, LONG);
152 	NREAD(X_DK_TIME, s.dk_time, dk_ndrive * LONG);
153 	NREAD(X_DK_XFER, s.dk_xfer, dk_ndrive * LONG);
154 	NREAD(X_DK_WDS, s.dk_wds, dk_ndrive * LONG);
155 	NREAD(X_DK_SEEK, s.dk_seek, dk_ndrive * LONG);
156 	NREAD(X_CP_TIME, s.cp_time, sizeof s.cp_time);
157 }
158 
159 #define	INSET	10
160 
161 void
162 labeliostat()
163 {
164 	int row;
165 
166 	if (namelist[X_DK_BUSY].n_type == 0) {
167 		error("No dk_busy defined.");
168 		return;
169 	}
170 	row = 0;
171 	wmove(wnd, row, 0); wclrtobot(wnd);
172 	mvwaddstr(wnd, row++, INSET,
173 	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
174 	mvwaddstr(wnd, row++, 0, "cpu  user|");
175 	mvwaddstr(wnd, row++, 0, "     nice|");
176 	mvwaddstr(wnd, row++, 0, "   system|");
177 	mvwaddstr(wnd, row++, 0, "     idle|");
178 	if (numbers)
179 		row = numlabels(row + 1);
180 	else
181 		row = barlabels(row + 1);
182 }
183 
184 static int
185 numlabels(row)
186 	int row;
187 {
188 	int i, col, regions, ndrives;
189 
190 #define COLWIDTH	14
191 #define DRIVESPERLINE	((wnd->maxx - INSET) / COLWIDTH)
192 	for (ndrives = 0, i = 0; i < dk_ndrive; i++)
193 		if (dk_select[i])
194 			ndrives++;
195 	regions = howmany(ndrives, DRIVESPERLINE);
196 	/*
197 	 * Deduct -regions for blank line after each scrolling region.
198 	 */
199 	linesperregion = (wnd->maxy - row - regions) / regions;
200 	/*
201 	 * Minimum region contains space for two
202 	 * label lines and one line of statistics.
203 	 */
204 	if (linesperregion < 3)
205 		linesperregion = 3;
206 	col = 0;
207 	for (i = 0; i < dk_ndrive; i++)
208 		if (dk_select[i] && dk_mspw[i] != 0.0) {
209 			if (col + COLWIDTH >= wnd->maxx - INSET) {
210 				col = 0, row += linesperregion + 1;
211 				if (row > wnd->maxy - (linesperregion + 1))
212 					break;
213 			}
214 			mvwaddstr(wnd, row, col + 4, dr_name[i]);
215 			mvwaddstr(wnd, row + 1, col, "bps tps msps");
216 			col += COLWIDTH;
217 		}
218 	if (col)
219 		row += linesperregion + 1;
220 	return (row);
221 }
222 
223 static int
224 barlabels(row)
225 	int row;
226 {
227 	int i;
228 
229 	mvwaddstr(wnd, row++, INSET,
230 	    "/0   /5   /10  /15  /20  /25  /30  /35  /40  /45  /50");
231 	linesperregion = 2 + msps;
232 	for (i = 0; i < dk_ndrive; i++)
233 		if (dk_select[i] && dk_mspw[i] != 0.0) {
234 			if (row > wnd->maxy - linesperregion)
235 				break;
236 			mvwprintw(wnd, row++, 0, "%3.3s   bps|", dr_name[i]);
237 			mvwaddstr(wnd, row++, 0, "      tps|");
238 			if (msps)
239 				mvwaddstr(wnd, row++, 0, "     msps|");
240 		}
241 	return (row);
242 }
243 
244 
245 void
246 showiostat()
247 {
248 	register long t;
249 	register int i, row, col;
250 
251 	if (namelist[X_DK_BUSY].n_type == 0)
252 		return;
253 	for (i = 0; i < dk_ndrive; i++) {
254 #define X(fld)	t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t
255 		X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time);
256 	}
257 	etime = 0;
258 	for(i = 0; i < CPUSTATES; i++) {
259 		X(cp_time);
260 		etime += s.cp_time[i];
261 	}
262 	if (etime == 0.0)
263 		etime = 1.0;
264 	etime /= (float) hz;
265 	row = 1;
266 
267 	/*
268 	 * Last CPU state not calculated yet.
269 	 */
270 	for (i = 0; i < CPUSTATES - 1; i++)
271 		stat1(row++, i);
272 	if (!numbers) {
273 		row += 2;
274 		for (i = 0; i < dk_ndrive; i++)
275 			if (dk_select[i] && dk_mspw[i] != 0.0) {
276 				if (row > wnd->maxy - linesperregion)
277 					break;
278 				row = stats(row, INSET, i);
279 			}
280 		return;
281 	}
282 	col = 0;
283 	wmove(wnd, row + linesperregion, 0);
284 	wdeleteln(wnd);
285 	wmove(wnd, row + 3, 0);
286 	winsertln(wnd);
287 	for (i = 0; i < dk_ndrive; i++)
288 		if (dk_select[i] && dk_mspw[i] != 0.0) {
289 			if (col + COLWIDTH >= wnd->maxx) {
290 				col = 0, row += linesperregion + 1;
291 				if (row > wnd->maxy - (linesperregion + 1))
292 					break;
293 				wmove(wnd, row + linesperregion, 0);
294 				wdeleteln(wnd);
295 				wmove(wnd, row + 3, 0);
296 				winsertln(wnd);
297 			}
298 			(void) stats(row + 3, col, i);
299 			col += COLWIDTH;
300 		}
301 }
302 
303 static int
304 stats(row, col, dn)
305 	int row, col, dn;
306 {
307 	double atime, words, xtime, itime;
308 
309 	atime = s.dk_time[dn];
310 	atime /= (float) hz;
311 	words = s.dk_wds[dn]*32.0;	/* number of words transferred */
312 	xtime = dk_mspw[dn]*words;	/* transfer time */
313 	itime = atime - xtime;		/* time not transferring */
314 	if (xtime < 0)
315 		itime += xtime, xtime = 0;
316 	if (itime < 0)
317 		xtime += itime, itime = 0;
318 	if (numbers) {
319 		mvwprintw(wnd, row, col, "%3.0f%4.0f%5.1f",
320 		    words / 512 / etime, s.dk_xfer[dn] / etime,
321 		    s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0.0);
322 		return (row);
323 	}
324 	wmove(wnd, row++, col);
325 	histogram(words / 512 / etime, 50, 1.0);
326 	wmove(wnd, row++, col);
327 	histogram(s.dk_xfer[dn] / etime, 50, 1.0);
328 	if (msps) {
329 		wmove(wnd, row++, col);
330 		histogram(s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0,
331 		   50, 1.0);
332 	}
333 	return (row);
334 }
335 
336 static void
337 stat1(row, o)
338 	int row, o;
339 {
340 	register int i;
341 	double time;
342 
343 	time = 0;
344 	for (i = 0; i < CPUSTATES; i++)
345 		time += s.cp_time[i];
346 	if (time == 0.0)
347 		time = 1.0;
348 	wmove(wnd, row, INSET);
349 #define CPUSCALE	0.5
350 	histogram(100.0 * s.cp_time[o] / time, 50, CPUSCALE);
351 }
352 
353 static void
354 histogram(val, colwidth, scale)
355 	double val;
356 	int colwidth;
357 	double scale;
358 {
359 	char buf[10];
360 	register int k;
361 	register int v = (int)(val * scale) + 0.5;
362 
363 	k = MIN(v, colwidth);
364 	if (v > colwidth) {
365 		sprintf(buf, "%4.1f", val);
366 		k -= strlen(buf);
367 		while (k--)
368 			waddch(wnd, 'X');
369 		waddstr(wnd, buf);
370 		return;
371 	}
372 	while (k--)
373 		waddch(wnd, 'X');
374 	wclrtoeol(wnd);
375 }
376 
377 int
378 cmdiostat(cmd, args)
379 	char *cmd, *args;
380 {
381 
382 	if (prefix(cmd, "msps"))
383 		msps = !msps;
384 	else if (prefix(cmd, "numbers"))
385 		numbers = 1;
386 	else if (prefix(cmd, "bars"))
387 		numbers = 0;
388 	else if (!dkcmd(cmd, args))
389 		return (0);
390 	wclear(wnd);
391 	labeliostat();
392 	refresh();
393 	return (1);
394 }
395