xref: /original-bsd/usr.bin/systat/iostat.c (revision d272e02a)
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.6 (Berkeley) 02/04/91";
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 static int numlabels(), barlabels(), stats();
75 static void stat1();
76 
77 initiostat()
78 {
79 	if (nlst[X_DK_BUSY].n_type == 0) {
80 		nlist(_PATH_UNIX, nlst);
81 		if (nlst[X_DK_BUSY].n_type == 0) {
82 			error("Disk init information isn't in namelist");
83 			return(0);
84 		}
85 	}
86 	if (! dkinit())
87 		return(0);
88 	if (dk_ndrive) {
89 #define	allocate(e, t) \
90     s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
91     s1./**/e = (t *)calloc(dk_ndrive, sizeof (t));
92 		allocate(dk_time, long);
93 		allocate(dk_wds, long);
94 		allocate(dk_seek, long);
95 		allocate(dk_xfer, long);
96 #undef allocate
97 	}
98 	return(1);
99 }
100 
101 fetchiostat()
102 {
103 	if (nlst[X_DK_BUSY].n_type == 0)
104 		return;
105 	s.dk_busy = getword(nlst[X_DK_BUSY].n_value);
106 	lseek(kmem, (long)nlst[X_DK_TIME].n_value, L_SET);
107 	read(kmem, s.dk_time, dk_ndrive * sizeof (long));
108 	lseek(kmem, (long)nlst[X_DK_XFER].n_value, L_SET);
109 	read(kmem, s.dk_xfer, dk_ndrive * sizeof (long));
110 	lseek(kmem, (long)nlst[X_DK_WDS].n_value, L_SET);
111 	read(kmem, s.dk_wds, dk_ndrive * sizeof (long));
112 	lseek(kmem, (long)nlst[X_DK_SEEK].n_value, L_SET);
113 	read(kmem, s.dk_seek, dk_ndrive * sizeof (long));
114 	lseek(kmem, (long)nlst[X_CP_TIME].n_value, L_SET);
115 	read(kmem, s.cp_time, sizeof s.cp_time);
116 }
117 
118 #define	INSET	10
119 
120 labeliostat()
121 {
122 	int row;
123 
124 	if (nlst[X_DK_BUSY].n_type == 0) {
125 		error("No dk_busy defined.");
126 		return;
127 	}
128 	row = 0;
129 	wmove(wnd, row, 0); wclrtobot(wnd);
130 	mvwaddstr(wnd, row++, INSET,
131 	    "/0   /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
132 	mvwaddstr(wnd, row++, 0, "cpu  user|");
133 	mvwaddstr(wnd, row++, 0, "     nice|");
134 	mvwaddstr(wnd, row++, 0, "   system|");
135 	mvwaddstr(wnd, row++, 0, "     idle|");
136 	if (numbers)
137 		row = numlabels(row + 1);
138 	else
139 		row = barlabels(row + 1);
140 }
141 
142 static int
143 numlabels(row)
144 	int row;
145 {
146 	int i, col, regions, ndrives;
147 
148 #define COLWIDTH	14
149 #define DRIVESPERLINE	((wnd->_maxx - INSET) / COLWIDTH)
150 	for (ndrives = 0, i = 0; i < dk_ndrive; i++)
151 		if (dk_select[i])
152 			ndrives++;
153 	regions = howmany(ndrives, DRIVESPERLINE);
154 	/*
155 	 * Deduct -regions for blank line after each scrolling region.
156 	 */
157 	linesperregion = (wnd->_maxy - row - regions) / regions;
158 	/*
159 	 * Minimum region contains space for two
160 	 * label lines and one line of statistics.
161 	 */
162 	if (linesperregion < 3)
163 		linesperregion = 3;
164 	col = 0;
165 	for (i = 0; i < dk_ndrive; i++)
166 		if (dk_select[i] && dk_mspw[i] != 0.0) {
167 			if (col + COLWIDTH >= wnd->_maxx - INSET) {
168 				col = 0, row += linesperregion + 1;
169 				if (row > wnd->_maxy - (linesperregion + 1))
170 					break;
171 			}
172 			mvwaddstr(wnd, row, col + 4, dr_name[i]);
173 			mvwaddstr(wnd, row + 1, col, "bps tps msps");
174 			col += COLWIDTH;
175 		}
176 	if (col)
177 		row += linesperregion + 1;
178 	return (row);
179 }
180 
181 static int
182 barlabels(row)
183 	int row;
184 {
185 	int i;
186 
187 	mvwaddstr(wnd, row++, INSET,
188 	    "/0   /5   /10  /15  /20  /25  /30  /35  /40  /45  /50");
189 	linesperregion = 2 + msps;
190 	for (i = 0; i < dk_ndrive; i++)
191 		if (dk_select[i] && dk_mspw[i] != 0.0) {
192 			if (row > wnd->_maxy - linesperregion)
193 				break;
194 			mvwprintw(wnd, row++, 0, "%3.3s   bps|", dr_name[i]);
195 			mvwaddstr(wnd, row++, 0, "      tps|");
196 			if (msps)
197 				mvwaddstr(wnd, row++, 0, "     msps|");
198 		}
199 	return (row);
200 }
201 
202 showiostat()
203 {
204 	register int i, row, col;
205 	register long t;
206 
207 	if (nlst[X_DK_BUSY].n_type == 0)
208 		return;
209 	for (i = 0; i < dk_ndrive; i++) {
210 #define X(fld)	t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t
211 		X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time);
212 	}
213 	etime = 0;
214 	for(i = 0; i < CPUSTATES; i++) {
215 		X(cp_time);
216 		etime += s.cp_time[i];
217 	}
218 	if (etime == 0.0)
219 		etime = 1.0;
220 	etime /= (float) hz;
221 	row = 1;
222 	for (i = 0; i < CPUSTATES; i++)
223 		stat1(row++, i);
224 	if (!numbers) {
225 		row += 2;
226 		for (i = 0; i < dk_ndrive; i++)
227 			if (dk_select[i] && dk_mspw[i] != 0.0) {
228 				if (row > wnd->_maxy - linesperregion)
229 					break;
230 				row = stats(row, INSET, i);
231 			}
232 		return;
233 	}
234 	col = 0;
235 	wmove(wnd, row + linesperregion, 0);
236 	wdeleteln(wnd);
237 	wmove(wnd, row + 3, 0);
238 	winsertln(wnd);
239 	for (i = 0; i < dk_ndrive; i++)
240 		if (dk_select[i] && dk_mspw[i] != 0.0) {
241 			if (col + COLWIDTH >= wnd->_maxx) {
242 				col = 0, row += linesperregion + 1;
243 				if (row > wnd->_maxy - (linesperregion + 1))
244 					break;
245 				wmove(wnd, row + linesperregion, 0);
246 				wdeleteln(wnd);
247 				wmove(wnd, row + 3, 0);
248 				winsertln(wnd);
249 			}
250 			(void) stats(row + 3, col, i);
251 			col += COLWIDTH;
252 		}
253 }
254 
255 static int
256 stats(row, col, dn)
257 	int row, col, dn;
258 {
259 	double atime, words, xtime, itime;
260 
261 	atime = s.dk_time[dn];
262 	atime /= (float) hz;
263 	words = s.dk_wds[dn]*32.0;	/* number of words transferred */
264 	xtime = dk_mspw[dn]*words;	/* transfer time */
265 	itime = atime - xtime;		/* time not transferring */
266 	if (xtime < 0)
267 		itime += xtime, xtime = 0;
268 	if (itime < 0)
269 		xtime += itime, itime = 0;
270 	if (numbers) {
271 		mvwprintw(wnd, row, col, "%3.0f%4.0f%5.1f",
272 		    words / 512 / etime, s.dk_xfer[dn] / etime,
273 		    s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0.0);
274 		return (row);
275 	}
276 	wmove(wnd, row++, col);
277 	histogram(words / 512 / etime, 50, 1.0);
278 	wmove(wnd, row++, col);
279 	histogram(s.dk_xfer[dn] / etime, 50, 1.0);
280 	if (msps) {
281 		wmove(wnd, row++, col);
282 		histogram(s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0,
283 		   50, 1.0);
284 	}
285 	return (row);
286 }
287 
288 static void
289 stat1(row, o)
290 	int row, o;
291 {
292 	register i;
293 	double time;
294 
295 	time = 0;
296 	for (i = 0; i < CPUSTATES; i++)
297 		time += s.cp_time[i];
298 	if (time == 0.0)
299 		time = 1.0;
300 	wmove(wnd, row, INSET);
301 #define CPUSCALE	0.5
302 	histogram(100.0 * s.cp_time[o] / time, 50, CPUSCALE);
303 }
304 
305 histogram(val, colwidth, scale)
306 	double val;
307 	int colwidth;
308 	double scale;
309 {
310 	char buf[10];
311 	register int k;
312 	register int v = (int)(val * scale) + 0.5;
313 
314 	k = MIN(v, colwidth);
315 	if (v > colwidth) {
316 		sprintf(buf, "%4.1f", val);
317 		k -= strlen(buf);
318 		while (k--)
319 			waddch(wnd, 'X');
320 		waddstr(wnd, buf);
321 		return;
322 	}
323 	while (k--)
324 		waddch(wnd, 'X');
325 	wclrtoeol(wnd);
326 }
327 
328 cmdiostat(cmd, args)
329 	char *cmd, *args;
330 {
331 
332 	if (prefix(cmd, "msps"))
333 		msps = !msps;
334 	else if (prefix(cmd, "numbers"))
335 		numbers = 1;
336 	else if (prefix(cmd, "bars"))
337 		numbers = 0;
338 	else if (!dkcmd(cmd, args))
339 		return (0);
340 	wclear(wnd);
341 	labeliostat();
342 	refresh();
343 	return (1);
344 }
345