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