Annotation of src/usr.bin/systat/iostat.c, Revision 1.24
1.24 ! deraadt 1: /* $OpenBSD: iostat.c,v 1.23 2004/02/15 22:56:12 tedu Exp $ */
1.3 deraadt 2: /* $NetBSD: iostat.c,v 1.5 1996/05/10 23:16:35 thorpej Exp $ */
1.1 deraadt 3:
4: /*
5: * Copyright (c) 1980, 1992, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
1.21 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: #ifndef lint
34: #if 0
35: static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93";
36: #endif
1.24 ! deraadt 37: static char rcsid[] = "$OpenBSD: iostat.c,v 1.23 2004/02/15 22:56:12 tedu Exp $";
1.12 heko 38: #endif /* not lint */
1.1 deraadt 39:
40: #include <sys/param.h>
41: #include <sys/dkstat.h>
42: #include <sys/buf.h>
1.3 deraadt 43: #include <sys/time.h>
1.1 deraadt 44:
45: #include <string.h>
46: #include <stdlib.h>
47: #include <paths.h>
48: #include "systat.h"
49: #include "extern.h"
50:
1.3 deraadt 51: #include "dkstats.h"
1.19 tdeval 52: extern struct _disk cur, last;
1.1 deraadt 53:
54: static int linesperregion;
55: static double etime;
56: static int numbers = 0; /* default display bar graphs */
1.3 deraadt 57: static int secs = 0; /* default seconds shown */
1.23 tedu 58: static int split = 0; /* whether to split r/w stats */
1.1 deraadt 59:
1.17 millert 60: static int barlabels(int);
61: static void histogram(double, int, double);
62: static int numlabels(int);
63: static int stats(int, int, int);
64: static void stat1(int, int);
1.1 deraadt 65:
66:
67: WINDOW *
1.18 deraadt 68: openiostat(void)
1.1 deraadt 69: {
70: return (subwin(stdscr, LINES-1-5, 0, 5, 0));
71: }
72:
73: void
1.18 deraadt 74: closeiostat(WINDOW *w)
1.1 deraadt 75: {
76: if (w == NULL)
77: return;
78: wclear(w);
79: wrefresh(w);
80: delwin(w);
81: }
82:
83: int
1.18 deraadt 84: initiostat(void)
1.1 deraadt 85: {
1.3 deraadt 86: dkinit(1);
87: dkreadstats();
1.9 kstailey 88: return (1);
1.1 deraadt 89: }
90:
91: void
1.18 deraadt 92: fetchiostat(void)
1.1 deraadt 93: {
1.19 tdeval 94: if (cur.dk_ndrive == 0)
1.1 deraadt 95: return;
1.3 deraadt 96: dkreadstats();
1.1 deraadt 97: }
98:
99: #define INSET 10
100:
101: void
1.18 deraadt 102: labeliostat(void)
1.1 deraadt 103: {
104: int row;
105:
106: row = 0;
107: wmove(wnd, row, 0); wclrtobot(wnd);
108: mvwaddstr(wnd, row++, INSET,
109: "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
110: mvwaddstr(wnd, row++, 0, "cpu user|");
111: mvwaddstr(wnd, row++, 0, " nice|");
112: mvwaddstr(wnd, row++, 0, " system|");
113: mvwaddstr(wnd, row++, 0, "interrupt|");
114: mvwaddstr(wnd, row++, 0, " idle|");
115: if (numbers)
116: row = numlabels(row + 1);
117: else
118: row = barlabels(row + 1);
119: }
120:
121: static int
1.18 deraadt 122: numlabels(int row)
1.1 deraadt 123: {
124: int i, col, regions, ndrives;
125:
1.19 tdeval 126: if (cur.dk_ndrive == 0) {
1.7 kstailey 127: mvwaddstr(wnd, row++, INSET, "No drives attached.");
128: return (row);
129: }
1.23 tedu 130: #define COLWIDTH (split ? 30 : 17)
1.4 mickey 131: #define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH)
1.19 tdeval 132: for (ndrives = 0, i = 0; i < cur.dk_ndrive; i++)
1.3 deraadt 133: if (cur.dk_select[i])
1.1 deraadt 134: ndrives++;
135: regions = howmany(ndrives, DRIVESPERLINE);
136: /*
137: * Deduct -regions for blank line after each scrolling region.
138: */
1.4 mickey 139: linesperregion = (wnd->_maxy - row - regions) / regions;
1.1 deraadt 140: /*
141: * Minimum region contains space for two
142: * label lines and one line of statistics.
143: */
144: if (linesperregion < 3)
145: linesperregion = 3;
1.11 deraadt 146: col = INSET;
1.19 tdeval 147: for (i = 0; i < cur.dk_ndrive; i++)
1.3 deraadt 148: if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
1.11 deraadt 149: if (col + COLWIDTH >= wnd->_maxx) {
150: col = INSET, row += linesperregion + 1;
1.4 mickey 151: if (row > wnd->_maxy - (linesperregion + 1))
1.1 deraadt 152: break;
153: }
1.3 deraadt 154: mvwaddstr(wnd, row, col + 4, cur.dk_name[i]);
1.23 tedu 155: if (split)
156: mvwaddstr(wnd, row + 1, col, " rKBps wKBps "
157: "rtps wtps sec");
158: else
159: mvwaddstr(wnd, row + 1, col, " KBps tps sec");
1.1 deraadt 160: col += COLWIDTH;
161: }
162: if (col)
163: row += linesperregion + 1;
164: return (row);
165: }
166:
167: static int
1.18 deraadt 168: barlabels(int row)
1.1 deraadt 169: {
170: int i;
171:
1.19 tdeval 172: if (cur.dk_ndrive == 0) {
1.7 kstailey 173: mvwaddstr(wnd, row++, INSET, "No drives attached.");
174: return (row);
175: }
1.1 deraadt 176: mvwaddstr(wnd, row++, INSET,
1.3 deraadt 177: "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100");
178: linesperregion = 2 + secs;
1.1 deraadt 179: for (i = 0; i < dk_ndrive; i++)
1.3 deraadt 180: if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
1.4 mickey 181: if (row > wnd->_maxy - linesperregion)
1.1 deraadt 182: break;
1.23 tedu 183: if (split) {
184: mvwprintw(wnd, row++, 0, "%4.4s rKps|",
185: cur.dk_name[i]);
186: mvwaddstr(wnd, row++, 0, " wKps|");
187: mvwaddstr(wnd, row++, 0, " rtps|");
188: mvwaddstr(wnd, row++, 0, " wtps|");
189: } else {
190: mvwprintw(wnd, row++, 0, "%4.4s Kps|",
191: cur.dk_name[i]);
192: mvwaddstr(wnd, row++, 0, " tps|");
193: }
1.3 deraadt 194: if (secs)
195: mvwaddstr(wnd, row++, 0, " msec|");
1.1 deraadt 196: }
197: return (row);
198: }
199:
200:
201: void
1.18 deraadt 202: showiostat(void)
1.1 deraadt 203: {
1.13 mpech 204: int i, row, col;
1.1 deraadt 205:
1.3 deraadt 206: dkswap();
207:
1.1 deraadt 208: etime = 0;
1.18 deraadt 209: for (i = 0; i < CPUSTATES; i++) {
1.3 deraadt 210: etime += cur.cp_time[i];
1.1 deraadt 211: }
212: if (etime == 0.0)
213: etime = 1.0;
214: etime /= (float) hz;
215: row = 1;
216:
217: /*
218: * Interrupt CPU state not calculated yet.
1.16 deraadt 219: */
1.1 deraadt 220: for (i = 0; i < CPUSTATES; i++)
221: stat1(row++, i);
1.7 kstailey 222:
1.19 tdeval 223: if (last.dk_ndrive != cur.dk_ndrive)
224: labeliostat();
225:
226: if (cur.dk_ndrive == 0)
1.7 kstailey 227: return;
228:
1.1 deraadt 229: if (!numbers) {
230: row += 2;
1.19 tdeval 231: for (i = 0; i < cur.dk_ndrive; i++)
1.3 deraadt 232: if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
1.4 mickey 233: if (row > wnd->_maxy - linesperregion)
1.1 deraadt 234: break;
235: row = stats(row, INSET, i);
236: }
237: return;
238: }
1.11 deraadt 239: col = INSET;
1.1 deraadt 240: wmove(wnd, row + linesperregion, 0);
241: wdeleteln(wnd);
242: wmove(wnd, row + 3, 0);
243: winsertln(wnd);
1.19 tdeval 244: for (i = 0; i < cur.dk_ndrive; i++)
1.3 deraadt 245: if (cur.dk_select[i] /*&& cur.dk_bytes[i] != 0.0*/) {
1.4 mickey 246: if (col + COLWIDTH >= wnd->_maxx) {
1.11 deraadt 247: col = INSET, row += linesperregion + 1;
1.4 mickey 248: if (row > wnd->_maxy - (linesperregion + 1))
1.1 deraadt 249: break;
250: wmove(wnd, row + linesperregion, 0);
251: wdeleteln(wnd);
252: wmove(wnd, row + 3, 0);
253: winsertln(wnd);
254: }
255: (void) stats(row + 3, col, i);
256: col += COLWIDTH;
257: }
258: }
259:
260: static int
1.18 deraadt 261: stats(int row, int col, int dn)
1.1 deraadt 262: {
1.23 tedu 263: double atime, rwords, wwords;
1.3 deraadt 264:
265: /* time busy in disk activity */
266: atime = (double)cur.dk_time[dn].tv_sec +
267: ((double)cur.dk_time[dn].tv_usec / (double)1000000);
1.1 deraadt 268:
1.23 tedu 269: rwords = cur.dk_rbytes[dn] / 1024.0; /* # of K read */
270: wwords = cur.dk_wbytes[dn] / 1024.0; /* # of K written */
1.1 deraadt 271: if (numbers) {
1.23 tedu 272: if (split)
273: mvwprintw(wnd, row, col, "%6.0f%6.0f%5.0f%5.0f%5.1f",
274: rwords / etime, wwords / etime, cur.dk_rxfer[dn] /
275: etime, cur.dk_wxfer[dn] / etime, atime / etime);
276: else
277: mvwprintw(wnd, row, col, "%5.0f%4.0f%5.1f",
278: (rwords + wwords) / etime,
279: (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime,
280: atime / etime);
1.1 deraadt 281: return (row);
282: }
1.23 tedu 283: if (split) {
284: wmove(wnd, row++, col);
285: histogram(rwords / etime, 50, 0.5);
286: wmove(wnd, row++, col);
287: histogram(wwords / etime, 50, 0.5);
288: wmove(wnd, row++, col);
289: histogram(cur.dk_rxfer[dn] / etime, 50, 0.5);
290: wmove(wnd, row++, col);
291: histogram(cur.dk_wxfer[dn] / etime, 50, 0.5);
292: } else {
293: wmove(wnd, row++, col);
294: histogram((rwords + wwords) / etime, 50, 0.5);
295: wmove(wnd, row++, col);
296: histogram((cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime, 50,
297: 0.5);
298: }
1.3 deraadt 299: if (secs) {
1.1 deraadt 300: wmove(wnd, row++, col);
1.3 deraadt 301: atime *= 1000; /* In milliseconds */
302: histogram(atime / etime, 50, 0.5);
1.1 deraadt 303: }
304: return (row);
305: }
306:
307: static void
1.18 deraadt 308: stat1(int row, int o)
1.1 deraadt 309: {
1.13 mpech 310: int i;
1.24 ! deraadt 311: double tim;
1.1 deraadt 312:
1.24 ! deraadt 313: tim = 0;
1.1 deraadt 314: for (i = 0; i < CPUSTATES; i++)
1.24 ! deraadt 315: tim += cur.cp_time[i];
! 316: if (tim == 0.0)
! 317: tim = 1.0;
1.1 deraadt 318: wmove(wnd, row, INSET);
319: #define CPUSCALE 0.5
1.24 ! deraadt 320: histogram(100.0 * cur.cp_time[o] / tim, 50, CPUSCALE);
1.1 deraadt 321: }
322:
323: static void
1.18 deraadt 324: histogram(double val, int colwidth, double scale)
1.1 deraadt 325: {
1.20 henning 326: int v = (int)(val * scale + 0.5);
327: int factor = 1;
328: int y, x;
329:
330: while (v > colwidth) {
331: v = (v + 5) / 10;
332: factor *= 10;
1.1 deraadt 333: }
1.20 henning 334: getyx(wnd, y, x);
1.1 deraadt 335: wclrtoeol(wnd);
1.20 henning 336: whline(wnd, 'X', v);
337: if (factor != 1)
338: mvwprintw(wnd, y, x + colwidth + 1, "* %d ", factor);
1.1 deraadt 339: }
340:
341: int
1.18 deraadt 342: cmdiostat(char *cmd, char *args)
1.1 deraadt 343: {
344:
1.3 deraadt 345: if (prefix(cmd, "secs"))
346: secs = !secs;
1.1 deraadt 347: else if (prefix(cmd, "numbers"))
348: numbers = 1;
349: else if (prefix(cmd, "bars"))
350: numbers = 0;
1.23 tedu 351: else if (prefix(cmd, "split"))
352: split = ~split;
1.1 deraadt 353: else if (!dkcmd(cmd, args))
354: return (0);
355: wclear(wnd);
356: labeliostat();
357: refresh();
358: return (1);
359: }