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