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