iostat.c revision 1.1 1 /*
2 * Copyright (c) 1980, 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93";
36 #endif not lint
37
38 #include <sys/param.h>
39 #include <sys/dkstat.h>
40 #include <sys/buf.h>
41
42 #include <string.h>
43 #include <stdlib.h>
44 #include <nlist.h>
45 #include <paths.h>
46 #include "systat.h"
47 #include "extern.h"
48
49 static struct nlist namelist[] = {
50 #define X_DK_BUSY 0
51 { "_dk_busy" },
52 #define X_DK_TIME 1
53 { "_dk_time" },
54 #define X_DK_XFER 2
55 { "_dk_xfer" },
56 #define X_DK_WDS 3
57 { "_dk_wds" },
58 #define X_DK_SEEK 4
59 { "_dk_seek" },
60 #define X_CP_TIME 5
61 { "_cp_time" },
62 #ifdef vax
63 #define X_MBDINIT (X_CP_TIME+1)
64 { "_mbdinit" },
65 #define X_UBDINIT (X_CP_TIME+2)
66 { "_ubdinit" },
67 #endif
68 #ifdef tahoe
69 #define X_VBDINIT (X_CP_TIME+1)
70 { "_vbdinit" },
71 #endif
72 { "" },
73 };
74
75 static struct {
76 int dk_busy;
77 long cp_time[CPUSTATES];
78 long *dk_time;
79 long *dk_wds;
80 long *dk_seek;
81 long *dk_xfer;
82 } s, s1;
83
84 static int linesperregion;
85 static double etime;
86 static int numbers = 0; /* default display bar graphs */
87 static int msps = 0; /* default ms/seek shown */
88
89 static int barlabels __P((int));
90 static void histogram __P((double, int, double));
91 static int numlabels __P((int));
92 static int stats __P((int, int, int));
93 static void stat1 __P((int, int));
94
95
96 WINDOW *
97 openiostat()
98 {
99 return (subwin(stdscr, LINES-1-5, 0, 5, 0));
100 }
101
102 void
103 closeiostat(w)
104 WINDOW *w;
105 {
106 if (w == NULL)
107 return;
108 wclear(w);
109 wrefresh(w);
110 delwin(w);
111 }
112
113 int
114 initiostat()
115 {
116 if (namelist[X_DK_BUSY].n_type == 0) {
117 if (kvm_nlist(kd, namelist)) {
118 nlisterr(namelist);
119 return(0);
120 }
121 if (namelist[X_DK_BUSY].n_type == 0) {
122 error("Disk init information isn't in namelist");
123 return(0);
124 }
125 }
126 if (! dkinit())
127 return(0);
128 if (dk_ndrive) {
129 #define allocate(e, t) \
130 s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
131 s1./**/e = (t *)calloc(dk_ndrive, sizeof (t));
132 allocate(dk_time, long);
133 allocate(dk_wds, long);
134 allocate(dk_seek, long);
135 allocate(dk_xfer, long);
136 #undef allocate
137 }
138 return(1);
139 }
140
141 void
142 fetchiostat()
143 {
144 if (namelist[X_DK_BUSY].n_type == 0)
145 return;
146 NREAD(X_DK_BUSY, &s.dk_busy, LONG);
147 NREAD(X_DK_TIME, s.dk_time, dk_ndrive * LONG);
148 NREAD(X_DK_XFER, s.dk_xfer, dk_ndrive * LONG);
149 NREAD(X_DK_WDS, s.dk_wds, dk_ndrive * LONG);
150 NREAD(X_DK_SEEK, s.dk_seek, dk_ndrive * LONG);
151 NREAD(X_CP_TIME, s.cp_time, sizeof s.cp_time);
152 }
153
154 #define INSET 10
155
156 void
157 labeliostat()
158 {
159 int row;
160
161 if (namelist[X_DK_BUSY].n_type == 0) {
162 error("No dk_busy defined.");
163 return;
164 }
165 row = 0;
166 wmove(wnd, row, 0); wclrtobot(wnd);
167 mvwaddstr(wnd, row++, INSET,
168 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
169 mvwaddstr(wnd, row++, 0, "cpu user|");
170 mvwaddstr(wnd, row++, 0, " nice|");
171 mvwaddstr(wnd, row++, 0, " system|");
172 mvwaddstr(wnd, row++, 0, " idle|");
173 if (numbers)
174 row = numlabels(row + 1);
175 else
176 row = barlabels(row + 1);
177 }
178
179 static int
180 numlabels(row)
181 int row;
182 {
183 int i, col, regions, ndrives;
184
185 #define COLWIDTH 14
186 #define DRIVESPERLINE ((wnd->maxx - INSET) / COLWIDTH)
187 for (ndrives = 0, i = 0; i < dk_ndrive; i++)
188 if (dk_select[i])
189 ndrives++;
190 regions = howmany(ndrives, DRIVESPERLINE);
191 /*
192 * Deduct -regions for blank line after each scrolling region.
193 */
194 linesperregion = (wnd->maxy - row - regions) / regions;
195 /*
196 * Minimum region contains space for two
197 * label lines and one line of statistics.
198 */
199 if (linesperregion < 3)
200 linesperregion = 3;
201 col = 0;
202 for (i = 0; i < dk_ndrive; i++)
203 if (dk_select[i] && dk_mspw[i] != 0.0) {
204 if (col + COLWIDTH >= wnd->maxx - INSET) {
205 col = 0, row += linesperregion + 1;
206 if (row > wnd->maxy - (linesperregion + 1))
207 break;
208 }
209 mvwaddstr(wnd, row, col + 4, dr_name[i]);
210 mvwaddstr(wnd, row + 1, col, "bps tps msps");
211 col += COLWIDTH;
212 }
213 if (col)
214 row += linesperregion + 1;
215 return (row);
216 }
217
218 static int
219 barlabels(row)
220 int row;
221 {
222 int i;
223
224 mvwaddstr(wnd, row++, INSET,
225 "/0 /5 /10 /15 /20 /25 /30 /35 /40 /45 /50");
226 linesperregion = 2 + msps;
227 for (i = 0; i < dk_ndrive; i++)
228 if (dk_select[i] && dk_mspw[i] != 0.0) {
229 if (row > wnd->maxy - linesperregion)
230 break;
231 mvwprintw(wnd, row++, 0, "%3.3s bps|", dr_name[i]);
232 mvwaddstr(wnd, row++, 0, " tps|");
233 if (msps)
234 mvwaddstr(wnd, row++, 0, " msps|");
235 }
236 return (row);
237 }
238
239
240 void
241 showiostat()
242 {
243 register long t;
244 register int i, row, col;
245
246 if (namelist[X_DK_BUSY].n_type == 0)
247 return;
248 for (i = 0; i < dk_ndrive; i++) {
249 #define X(fld) t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t
250 X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time);
251 }
252 etime = 0;
253 for(i = 0; i < CPUSTATES; i++) {
254 X(cp_time);
255 etime += s.cp_time[i];
256 }
257 if (etime == 0.0)
258 etime = 1.0;
259 etime /= (float) hz;
260 row = 1;
261
262 /*
263 * Last CPU state not calculated yet.
264 */
265 for (i = 0; i < CPUSTATES - 1; i++)
266 stat1(row++, i);
267 if (!numbers) {
268 row += 2;
269 for (i = 0; i < dk_ndrive; i++)
270 if (dk_select[i] && dk_mspw[i] != 0.0) {
271 if (row > wnd->maxy - linesperregion)
272 break;
273 row = stats(row, INSET, i);
274 }
275 return;
276 }
277 col = 0;
278 wmove(wnd, row + linesperregion, 0);
279 wdeleteln(wnd);
280 wmove(wnd, row + 3, 0);
281 winsertln(wnd);
282 for (i = 0; i < dk_ndrive; i++)
283 if (dk_select[i] && dk_mspw[i] != 0.0) {
284 if (col + COLWIDTH >= wnd->maxx) {
285 col = 0, row += linesperregion + 1;
286 if (row > wnd->maxy - (linesperregion + 1))
287 break;
288 wmove(wnd, row + linesperregion, 0);
289 wdeleteln(wnd);
290 wmove(wnd, row + 3, 0);
291 winsertln(wnd);
292 }
293 (void) stats(row + 3, col, i);
294 col += COLWIDTH;
295 }
296 }
297
298 static int
299 stats(row, col, dn)
300 int row, col, dn;
301 {
302 double atime, words, xtime, itime;
303
304 atime = s.dk_time[dn];
305 atime /= (float) hz;
306 words = s.dk_wds[dn]*32.0; /* number of words transferred */
307 xtime = dk_mspw[dn]*words; /* transfer time */
308 itime = atime - xtime; /* time not transferring */
309 if (xtime < 0)
310 itime += xtime, xtime = 0;
311 if (itime < 0)
312 xtime += itime, itime = 0;
313 if (numbers) {
314 mvwprintw(wnd, row, col, "%3.0f%4.0f%5.1f",
315 words / 512 / etime, s.dk_xfer[dn] / etime,
316 s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0.0);
317 return (row);
318 }
319 wmove(wnd, row++, col);
320 histogram(words / 512 / etime, 50, 1.0);
321 wmove(wnd, row++, col);
322 histogram(s.dk_xfer[dn] / etime, 50, 1.0);
323 if (msps) {
324 wmove(wnd, row++, col);
325 histogram(s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0,
326 50, 1.0);
327 }
328 return (row);
329 }
330
331 static void
332 stat1(row, o)
333 int row, o;
334 {
335 register int i;
336 double time;
337
338 time = 0;
339 for (i = 0; i < CPUSTATES; i++)
340 time += s.cp_time[i];
341 if (time == 0.0)
342 time = 1.0;
343 wmove(wnd, row, INSET);
344 #define CPUSCALE 0.5
345 histogram(100.0 * s.cp_time[o] / time, 50, CPUSCALE);
346 }
347
348 static void
349 histogram(val, colwidth, scale)
350 double val;
351 int colwidth;
352 double scale;
353 {
354 char buf[10];
355 register int k;
356 register int v = (int)(val * scale) + 0.5;
357
358 k = MIN(v, colwidth);
359 if (v > colwidth) {
360 sprintf(buf, "%4.1f", val);
361 k -= strlen(buf);
362 while (k--)
363 waddch(wnd, 'X');
364 waddstr(wnd, buf);
365 return;
366 }
367 while (k--)
368 waddch(wnd, 'X');
369 wclrtoeol(wnd);
370 }
371
372 int
373 cmdiostat(cmd, args)
374 char *cmd, *args;
375 {
376
377 if (prefix(cmd, "msps"))
378 msps = !msps;
379 else if (prefix(cmd, "numbers"))
380 numbers = 1;
381 else if (prefix(cmd, "bars"))
382 numbers = 0;
383 else if (!dkcmd(cmd, args))
384 return (0);
385 wclear(wnd);
386 labeliostat();
387 refresh();
388 return (1);
389 }
390