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.2 (Berkeley) 12/11/85"; 9: #endif not lint 10: 11: /* 12: * iostat 13: */ 14: #include "systat.h" 15: #include <sys/buf.h> 16: 17: WINDOW * 18: openiostat() 19: { 20: 21: return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 22: } 23: 24: closeiostat(w) 25: WINDOW *w; 26: { 27: 28: if (w == NULL) 29: return; 30: wclear(w); 31: wrefresh(w); 32: delwin(w); 33: } 34: 35: static struct nlist nlst[] = { 36: #define X_DK_BUSY 0 37: { "_dk_busy" }, 38: #define X_DK_TIME 1 39: { "_dk_time" }, 40: #define X_DK_XFER 2 41: { "_dk_xfer" }, 42: #define X_DK_WDS 3 43: { "_dk_wds" }, 44: #define X_DK_SEEK 4 45: { "_dk_seek" }, 46: #define X_CP_TIME 5 47: { "_cp_time" }, 48: #ifdef vax 49: #define X_MBDINIT 6 50: { "_mbdinit" }, 51: #define X_UBDINIT 7 52: { "_ubdinit" }, 53: #endif 54: { "" }, 55: }; 56: 57: static struct { 58: int dk_busy; 59: long cp_time[CPUSTATES]; 60: long *dk_time; 61: long *dk_wds; 62: long *dk_seek; 63: long *dk_xfer; 64: } s, s1; 65: 66: static int linesperregion; 67: static double etime; 68: static int numbers = 0; /* default display bar graphs */ 69: static int msps = 0; /* default ms/seek shown */ 70: 71: initiostat() 72: { 73: 74: if (nlst[X_DK_BUSY].n_type == 0) { 75: nlist("/vmunix", nlst); 76: if (nlst[X_DK_BUSY].n_type == 0) { 77: error("Disk init information isn't in namelist"); 78: return(0); 79: } 80: } 81: if (! dkinit()) 82: return(0); 83: if (dk_ndrive) { 84: #define allocate(e, t) \ 85: s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \ 86: s1./**/e = (t *)calloc(dk_ndrive, sizeof (t)); 87: allocate(dk_time, long); 88: allocate(dk_wds, long); 89: allocate(dk_seek, long); 90: allocate(dk_xfer, long); 91: #undef allocate 92: } 93: return(1); 94: } 95: 96: fetchiostat() 97: { 98: 99: if (nlst[X_DK_BUSY].n_type == 0) 100: return; 101: s.dk_busy = getw(nlst[X_DK_BUSY].n_value); 102: lseek(kmem, (long)nlst[X_DK_TIME].n_value, L_SET); 103: read(kmem, s.dk_time, dk_ndrive * sizeof (long)); 104: lseek(kmem, (long)nlst[X_DK_XFER].n_value, L_SET); 105: read(kmem, s.dk_xfer, dk_ndrive * sizeof (long)); 106: lseek(kmem, (long)nlst[X_DK_WDS].n_value, L_SET); 107: read(kmem, s.dk_wds, dk_ndrive * sizeof (long)); 108: lseek(kmem, (long)nlst[X_DK_SEEK].n_value, L_SET); 109: read(kmem, s.dk_seek, dk_ndrive * sizeof (long)); 110: lseek(kmem, (long)nlst[X_CP_TIME].n_value, L_SET); 111: read(kmem, s.cp_time, sizeof s.cp_time); 112: } 113: 114: #define INSET 10 115: 116: labeliostat() 117: { 118: int row; 119: 120: if (nlst[X_DK_BUSY].n_type == 0) { 121: error("No dk_busy defined."); 122: return; 123: } 124: row = 0; 125: wmove(wnd, row, 0); wclrtobot(wnd); 126: mvwaddstr(wnd, row++, INSET, 127: "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 128: mvwaddstr(wnd, row++, 0, "cpu user|"); 129: mvwaddstr(wnd, row++, 0, " nice|"); 130: mvwaddstr(wnd, row++, 0, " system|"); 131: mvwaddstr(wnd, row++, 0, " idle|"); 132: if (numbers) 133: row = numlabels(row + 1); 134: else 135: row = barlabels(row + 1); 136: } 137: 138: static 139: numlabels(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 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 251: stats(row, col, dn) 252: int row, 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 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 * 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: }