iostat.c revision 1.2 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