iostat.c revision 1.34 1 /* $NetBSD: iostat.c,v 1.34 2006/02/05 09:58:39 dsl 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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93";
36 #endif
37 __RCSID("$NetBSD: iostat.c,v 1.34 2006/02/05 09:58:39 dsl Exp $");
38 #endif /* not lint */
39
40 #include <sys/param.h>
41
42 #include <string.h>
43
44 #include "systat.h"
45 #include "extern.h"
46 #include "dkstats.h"
47 #include "tpstats.h"
48
49 static int linesperregion;
50 static double etime;
51 static int numbers = 0; /* default display bar graphs */
52 static int secs = 0; /* default seconds shown */
53 static int read_write = 0; /* default read/write shown */
54
55 static int barlabels(int);
56 static void histogram(double, int, double);
57 static int numlabels(int);
58 static int stats(int, int, int);
59 static int tpstats(int, int, int);
60 static void stat1(int, int);
61
62
63 WINDOW *
64 openiostat(void)
65 {
66
67 return (subwin(stdscr, -1, 0, 5, 0));
68 }
69
70 void
71 closeiostat(WINDOW *w)
72 {
73
74 if (w == NULL)
75 return;
76 wclear(w);
77 wrefresh(w);
78 delwin(w);
79 }
80
81 int
82 initiostat(void)
83 {
84
85 dkinit(1);
86 tpinit(1);
87 cpureadstats();
88 dkreadstats();
89 tpreadstats();
90 return(1);
91 }
92
93 void
94 fetchiostat(void)
95 {
96
97 cpureadstats();
98
99 if (dk_ndrive != 0)
100 dkreadstats();
101
102 if (tp_ndrive != 0)
103 tpreadstats();
104 }
105
106 #define INSET 14
107
108 void
109 labeliostat(void)
110 {
111 int row;
112
113 if ((dk_ndrive == 0) && (tp_ndrive == 0)) {
114 error("No drives defined.");
115 return;
116 }
117 row = 0;
118 wmove(wnd, row, 0); wclrtobot(wnd);
119 mvwaddstr(wnd, row++, INSET,
120 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
121 mvwaddstr(wnd, row++, 0, " CPU user|");
122 mvwaddstr(wnd, row++, 0, " nice|");
123 mvwaddstr(wnd, row++, 0, " system|");
124 mvwaddstr(wnd, row++, 0, " interrupt|");
125 mvwaddstr(wnd, row++, 0, " idle|");
126 if (numbers)
127 row = numlabels(row + 1);
128 else
129 row = barlabels(row + 1);
130 }
131
132 static int
133 numlabels(int row)
134 {
135 int i, col, regions, ndrives;
136
137 #define COLWIDTH (9 + secs * 5 + 1 + read_write * 9 + 1)
138 #define DRIVESPERLINE ((getmaxx(wnd) + 1) / COLWIDTH)
139 for (ndrives = 0, i = 0; i < dk_ndrive; i++)
140 if (cur.dk_select[i])
141 ndrives++;
142 for (i = 0; i < tp_ndrive; i++)
143 if (cur_tape.select[i])
144 ndrives++;
145
146 regions = howmany(ndrives, DRIVESPERLINE);
147 /*
148 * Deduct -regions for blank line after each scrolling region.
149 */
150 linesperregion = (getmaxy(wnd) - row - regions + 1) / regions;
151 /*
152 * Minimum region contains space for two
153 * label lines and one line of statistics.
154 */
155 if (linesperregion < 3)
156 linesperregion = 3;
157 col = 0;
158 for (i = 0; i < (dk_ndrive + tp_ndrive); i++)
159 if (((i < dk_ndrive) && (cur.dk_select[i])) ||
160 ((i >= dk_ndrive) && (cur_tape.select[i - dk_ndrive]))) {
161 if (col + COLWIDTH - 1 > getmaxx(wnd)) {
162 col = 0, row += linesperregion + 1;
163 if (row > getmaxy(wnd) - (linesperregion))
164 break;
165 }
166
167 if (i < dk_ndrive)
168 mvwprintw(wnd, row, col + 5, "%s",
169 cur.dk_name[i]);
170 else
171 mvwprintw(wnd, row, col + 5, "%s",
172 cur_tape.name[i - dk_ndrive]);
173
174 if (read_write)
175 mvwprintw(wnd, row, col + 11 + secs * 5,
176 "(write)");
177 mvwprintw(wnd, row + 1, col, " kBps %s",
178 read_write ? "r/s" : "tps");
179 if (secs)
180 waddstr(wnd, " sec");
181 if (read_write)
182 waddstr(wnd, " kBps w/s");
183 col += COLWIDTH;
184 }
185 if (col)
186 row += linesperregion + 1;
187 return (row);
188 }
189
190 static int
191 barlabels(int row)
192 {
193 int i;
194
195 mvwaddstr(wnd, row++, INSET,
196 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
197 linesperregion = 2 + secs + (read_write ? 2 : 0);
198 for (i = 0; i < dk_ndrive; i++)
199 if (cur.dk_select[i]) {
200 if (row > getmaxy(wnd) - linesperregion)
201 break;
202 mvwprintw(wnd, row++, 0, "%7.7s kBps|",
203 cur.dk_name[i]);
204 mvwaddstr(wnd, row++, 0, " tps|");
205 if (read_write) {
206 mvwprintw(wnd, row++, 0, " (write) kBps|");
207 mvwaddstr(wnd, row++, 0, " tps|");
208 }
209 if (secs)
210 mvwaddstr(wnd, row++, 0, " msec|");
211 }
212 for (i = 0; i < tp_ndrive; i++)
213 if (cur_tape.select[i]) {
214 if (row > getmaxy(wnd) - linesperregion)
215 break;
216 mvwprintw(wnd, row++, 0, "%7.7s kBps|",
217 cur_tape.name[i]);
218 mvwaddstr(wnd, row++, 0, " tps|");
219 if (read_write) {
220 mvwprintw(wnd, row++, 0, " (write) kBps|");
221 mvwaddstr(wnd, row++, 0, " tps|");
222 }
223 if (secs)
224 mvwaddstr(wnd, row++, 0, " msec|");
225 }
226 return (row);
227 }
228
229 void
230 showiostat(void)
231 {
232 int i, row, col;
233
234 if (dk_ndrive == 0)
235 return;
236 dkswap();
237 cpuswap();
238 tpswap();
239
240 etime = cur.cp_etime;
241 row = 1;
242
243 /*
244 * Interrupt CPU state not calculated yet.
245 */
246 for (i = 0; i < CPUSTATES; i++)
247 stat1(row++, i);
248 if (!numbers) {
249 row += 2;
250 for (i = 0; i < dk_ndrive; i++)
251 if (cur.dk_select[i]) {
252 if (row > getmaxy(wnd) - linesperregion)
253 break;
254 row = stats(row, INSET, i);
255 }
256 for (i = 0; i < tp_ndrive; i++)
257 if (cur_tape.select[i]) {
258 if (row > getmaxy(wnd) - linesperregion)
259 break;
260 row = tpstats(row, INSET, i);
261 }
262 return;
263 }
264 col = 0;
265 wmove(wnd, row + linesperregion, 0);
266 wdeleteln(wnd);
267 wmove(wnd, row + 3, 0);
268 winsertln(wnd);
269 for (i = 0; i < dk_ndrive; i++)
270 if (cur.dk_select[i]) {
271 if (col + COLWIDTH - 1 > getmaxx(wnd)) {
272 col = 0, row += linesperregion + 1;
273 if (row > getmaxy(wnd) - (linesperregion + 1))
274 break;
275 wmove(wnd, row + linesperregion, 0);
276 wdeleteln(wnd);
277 wmove(wnd, row + 3, 0);
278 winsertln(wnd);
279 }
280 (void) stats(row + 3, col, i);
281 col += COLWIDTH;
282 }
283 for (i = 0; i < tp_ndrive; i++)
284 if (cur_tape.select[i]) {
285 if (col + COLWIDTH - 1 > getmaxx(wnd)) {
286 col = 0, row += linesperregion + 1;
287 if (row > getmaxy(wnd) - (linesperregion + 1))
288 break;
289 wmove(wnd, row + linesperregion, 0);
290 wdeleteln(wnd);
291 wmove(wnd, row + 3, 0);
292 winsertln(wnd);
293 }
294 (void) stats(row + 3, col, i);
295 col += COLWIDTH;
296 }
297 }
298
299 static int
300 stats(int row, int col, int dn)
301 {
302 double atime, rwords, wwords;
303 uint64_t rxfer;
304
305 /* time busy in disk activity */
306 atime = (double)cur.dk_time[dn].tv_sec +
307 ((double)cur.dk_time[dn].tv_usec / (double)1000000);
308
309 /* # of k transferred */
310 rwords = cur.dk_rbytes[dn] / 1024.0;
311 wwords = cur.dk_wbytes[dn] / 1024.0;
312 rxfer = cur.dk_rxfer[dn];
313 if (!read_write) {
314 rwords = wwords;
315 rxfer += cur.dk_wxfer[dn];
316 }
317 if (numbers) {
318 mvwprintw(wnd, row, col, "%5.0f%4.0f",
319 rwords / etime, rxfer / etime);
320 if (secs)
321 wprintw(wnd, "%5.1f", atime / etime);
322 if (read_write)
323 wprintw(wnd, " %5.0f%4.0f",
324 wwords / etime, cur.dk_wxfer[dn] / etime);
325 return (row);
326 }
327
328 wmove(wnd, row++, col);
329 histogram(rwords / etime, 50, 0.5);
330 wmove(wnd, row++, col);
331 histogram(rxfer / etime, 50, 0.5);
332 if (read_write) {
333 wmove(wnd, row++, col);
334 histogram(wwords / etime, 50, 0.5);
335 wmove(wnd, row++, col);
336 histogram(cur.dk_wxfer[dn] / etime, 50, 0.5);
337 }
338
339 if (secs) {
340 wmove(wnd, row++, col);
341 atime *= 1000; /* In milliseconds */
342 histogram(atime / etime, 50, 0.5);
343 }
344 return (row);
345 }
346
347 static int
348 tpstats(int row, int col, int dn)
349 {
350 double atime, rwords, wwords;
351 uint64_t rxfer;
352
353 /* time busy in disk activity */
354 atime = (double)cur_tape.time[dn].tv_sec +
355 ((double)cur_tape.time[dn].tv_usec / (double)1000000);
356
357 /* # of k transferred */
358 rwords = cur_tape.rbytes[dn] / 1024.0;
359 wwords = cur_tape.wbytes[dn] / 1024.0;
360 rxfer = cur_tape.rxfer[dn];
361 if (!read_write) {
362 rwords = wwords;
363 rxfer += cur_tape.wxfer[dn];
364 }
365 if (numbers) {
366 mvwprintw(wnd, row, col, "%5.0f%4.0f",
367 rwords / etime, rxfer / etime);
368 if (secs)
369 wprintw(wnd, "%5.1f", atime / etime);
370 if (read_write)
371 wprintw(wnd, " %5.0f%4.0f",
372 wwords / etime, cur_tape.wxfer[dn] / etime);
373 return (row);
374 }
375
376 wmove(wnd, row++, col);
377 histogram(rwords / etime, 50, 0.5);
378 wmove(wnd, row++, col);
379 histogram(rxfer / etime, 50, 0.5);
380 if (read_write) {
381 wmove(wnd, row++, col);
382 histogram(wwords / etime, 50, 0.5);
383 wmove(wnd, row++, col);
384 histogram(cur_tape.wxfer[dn] / etime, 50, 0.5);
385 }
386
387 if (secs) {
388 wmove(wnd, row++, col);
389 atime *= 1000; /* In milliseconds */
390 histogram(atime / etime, 50, 0.5);
391 }
392 return (row);
393 }
394
395 static void
396 stat1(int row, int o)
397 {
398 int i;
399 double total_time;
400
401 total_time = 0;
402 for (i = 0; i < CPUSTATES; i++)
403 total_time += cur.cp_time[i];
404 if (total_time == 0.0)
405 total_time = 1.0;
406 wmove(wnd, row, INSET);
407 #define CPUSCALE 0.5
408 histogram(100.0 * cur.cp_time[o] / total_time, 50, CPUSCALE);
409 }
410
411 static void
412 histogram(double val, int colwidth, double scale)
413 {
414 int v = (int)(val * scale + 0.5);
415 int factor = 1;
416 int y, x;
417
418 while (v > colwidth) {
419 v = (v + 5) / 10;
420 factor *= 10;
421 }
422 getyx(wnd, y, x);
423 wclrtoeol(wnd);
424 whline(wnd, 'X', v);
425 if (factor != 1)
426 mvwprintw(wnd, y, x + colwidth + 1, "* %d ", factor);
427 }
428
429 void
430 iostat_bars(char *args)
431 {
432 numbers = 0;
433 wclear(wnd);
434 labeliostat();
435 refresh();
436 }
437
438 void
439 iostat_numbers(char *args)
440 {
441 numbers = 1;
442 wclear(wnd);
443 labeliostat();
444 refresh();
445 }
446
447 void
448 iostat_secs(char *args)
449 {
450 secs = !secs;
451 wclear(wnd);
452 labeliostat();
453 refresh();
454 }
455
456 void
457 iostat_rw(char *args)
458 {
459 read_write ^= 1;
460 wclear(wnd);
461 labeliostat();
462 refresh();
463 }
464
465 void
466 iostat_all(char *args)
467 {
468 read_write = 0;
469 wclear(wnd);
470 labeliostat();
471 refresh();
472 }
473