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.6 (Berkeley) 02/04/91"; 9 #endif not lint 10 11 /* 12 * iostat 13 */ 14 #include "systat.h" 15 #include <sys/buf.h> 16 #include <paths.h> 17 18 WINDOW * 19 openiostat() 20 { 21 return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 22 } 23 24 closeiostat(w) 25 WINDOW *w; 26 { 27 if (w == NULL) 28 return; 29 wclear(w); 30 wrefresh(w); 31 delwin(w); 32 } 33 34 static struct nlist nlst[] = { 35 #define X_DK_BUSY 0 36 { "_dk_busy" }, 37 #define X_DK_TIME 1 38 { "_dk_time" }, 39 #define X_DK_XFER 2 40 { "_dk_xfer" }, 41 #define X_DK_WDS 3 42 { "_dk_wds" }, 43 #define X_DK_SEEK 4 44 { "_dk_seek" }, 45 #define X_CP_TIME 5 46 { "_cp_time" }, 47 #ifdef vax 48 #define X_MBDINIT (X_CP_TIME+1) 49 { "_mbdinit" }, 50 #define X_UBDINIT (X_CP_TIME+2) 51 { "_ubdinit" }, 52 #endif 53 #ifdef tahoe 54 #define X_VBDINIT (X_CP_TIME+1) 55 { "_vbdinit" }, 56 #endif 57 { "" }, 58 }; 59 60 static struct { 61 int dk_busy; 62 long cp_time[CPUSTATES]; 63 long *dk_time; 64 long *dk_wds; 65 long *dk_seek; 66 long *dk_xfer; 67 } s, s1; 68 69 static int linesperregion; 70 static double etime; 71 static int numbers = 0; /* default display bar graphs */ 72 static int msps = 0; /* default ms/seek shown */ 73 74 static int numlabels(), barlabels(), stats(); 75 static void stat1(); 76 77 initiostat() 78 { 79 if (nlst[X_DK_BUSY].n_type == 0) { 80 nlist(_PATH_UNIX, nlst); 81 if (nlst[X_DK_BUSY].n_type == 0) { 82 error("Disk init information isn't in namelist"); 83 return(0); 84 } 85 } 86 if (! dkinit()) 87 return(0); 88 if (dk_ndrive) { 89 #define allocate(e, t) \ 90 s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \ 91 s1./**/e = (t *)calloc(dk_ndrive, sizeof (t)); 92 allocate(dk_time, long); 93 allocate(dk_wds, long); 94 allocate(dk_seek, long); 95 allocate(dk_xfer, long); 96 #undef allocate 97 } 98 return(1); 99 } 100 101 fetchiostat() 102 { 103 if (nlst[X_DK_BUSY].n_type == 0) 104 return; 105 s.dk_busy = getword(nlst[X_DK_BUSY].n_value); 106 lseek(kmem, (long)nlst[X_DK_TIME].n_value, L_SET); 107 read(kmem, s.dk_time, dk_ndrive * sizeof (long)); 108 lseek(kmem, (long)nlst[X_DK_XFER].n_value, L_SET); 109 read(kmem, s.dk_xfer, dk_ndrive * sizeof (long)); 110 lseek(kmem, (long)nlst[X_DK_WDS].n_value, L_SET); 111 read(kmem, s.dk_wds, dk_ndrive * sizeof (long)); 112 lseek(kmem, (long)nlst[X_DK_SEEK].n_value, L_SET); 113 read(kmem, s.dk_seek, dk_ndrive * sizeof (long)); 114 lseek(kmem, (long)nlst[X_CP_TIME].n_value, L_SET); 115 read(kmem, s.cp_time, sizeof s.cp_time); 116 } 117 118 #define INSET 10 119 120 labeliostat() 121 { 122 int row; 123 124 if (nlst[X_DK_BUSY].n_type == 0) { 125 error("No dk_busy defined."); 126 return; 127 } 128 row = 0; 129 wmove(wnd, row, 0); wclrtobot(wnd); 130 mvwaddstr(wnd, row++, INSET, 131 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 132 mvwaddstr(wnd, row++, 0, "cpu user|"); 133 mvwaddstr(wnd, row++, 0, " nice|"); 134 mvwaddstr(wnd, row++, 0, " system|"); 135 mvwaddstr(wnd, row++, 0, " idle|"); 136 if (numbers) 137 row = numlabels(row + 1); 138 else 139 row = barlabels(row + 1); 140 } 141 142 static int 143 numlabels(row) 144 int row; 145 { 146 int i, col, regions, ndrives; 147 148 #define COLWIDTH 14 149 #define DRIVESPERLINE ((wnd->_maxx - INSET) / COLWIDTH) 150 for (ndrives = 0, i = 0; i < dk_ndrive; i++) 151 if (dk_select[i]) 152 ndrives++; 153 regions = howmany(ndrives, DRIVESPERLINE); 154 /* 155 * Deduct -regions for blank line after each scrolling region. 156 */ 157 linesperregion = (wnd->_maxy - row - regions) / regions; 158 /* 159 * Minimum region contains space for two 160 * label lines and one line of statistics. 161 */ 162 if (linesperregion < 3) 163 linesperregion = 3; 164 col = 0; 165 for (i = 0; i < dk_ndrive; i++) 166 if (dk_select[i] && dk_mspw[i] != 0.0) { 167 if (col + COLWIDTH >= wnd->_maxx - INSET) { 168 col = 0, row += linesperregion + 1; 169 if (row > wnd->_maxy - (linesperregion + 1)) 170 break; 171 } 172 mvwaddstr(wnd, row, col + 4, dr_name[i]); 173 mvwaddstr(wnd, row + 1, col, "bps tps msps"); 174 col += COLWIDTH; 175 } 176 if (col) 177 row += linesperregion + 1; 178 return (row); 179 } 180 181 static int 182 barlabels(row) 183 int row; 184 { 185 int i; 186 187 mvwaddstr(wnd, row++, INSET, 188 "/0 /5 /10 /15 /20 /25 /30 /35 /40 /45 /50"); 189 linesperregion = 2 + msps; 190 for (i = 0; i < dk_ndrive; i++) 191 if (dk_select[i] && dk_mspw[i] != 0.0) { 192 if (row > wnd->_maxy - linesperregion) 193 break; 194 mvwprintw(wnd, row++, 0, "%3.3s bps|", dr_name[i]); 195 mvwaddstr(wnd, row++, 0, " tps|"); 196 if (msps) 197 mvwaddstr(wnd, row++, 0, " msps|"); 198 } 199 return (row); 200 } 201 202 showiostat() 203 { 204 register int i, row, col; 205 register long t; 206 207 if (nlst[X_DK_BUSY].n_type == 0) 208 return; 209 for (i = 0; i < dk_ndrive; i++) { 210 #define X(fld) t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t 211 X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time); 212 } 213 etime = 0; 214 for(i = 0; i < CPUSTATES; i++) { 215 X(cp_time); 216 etime += s.cp_time[i]; 217 } 218 if (etime == 0.0) 219 etime = 1.0; 220 etime /= (float) hz; 221 row = 1; 222 for (i = 0; i < CPUSTATES; i++) 223 stat1(row++, i); 224 if (!numbers) { 225 row += 2; 226 for (i = 0; i < dk_ndrive; i++) 227 if (dk_select[i] && dk_mspw[i] != 0.0) { 228 if (row > wnd->_maxy - linesperregion) 229 break; 230 row = stats(row, INSET, i); 231 } 232 return; 233 } 234 col = 0; 235 wmove(wnd, row + linesperregion, 0); 236 wdeleteln(wnd); 237 wmove(wnd, row + 3, 0); 238 winsertln(wnd); 239 for (i = 0; i < dk_ndrive; i++) 240 if (dk_select[i] && dk_mspw[i] != 0.0) { 241 if (col + COLWIDTH >= wnd->_maxx) { 242 col = 0, row += linesperregion + 1; 243 if (row > wnd->_maxy - (linesperregion + 1)) 244 break; 245 wmove(wnd, row + linesperregion, 0); 246 wdeleteln(wnd); 247 wmove(wnd, row + 3, 0); 248 winsertln(wnd); 249 } 250 (void) stats(row + 3, col, i); 251 col += COLWIDTH; 252 } 253 } 254 255 static int 256 stats(row, col, dn) 257 int row, col, dn; 258 { 259 double atime, words, xtime, itime; 260 261 atime = s.dk_time[dn]; 262 atime /= (float) hz; 263 words = s.dk_wds[dn]*32.0; /* number of words transferred */ 264 xtime = dk_mspw[dn]*words; /* transfer time */ 265 itime = atime - xtime; /* time not transferring */ 266 if (xtime < 0) 267 itime += xtime, xtime = 0; 268 if (itime < 0) 269 xtime += itime, itime = 0; 270 if (numbers) { 271 mvwprintw(wnd, row, col, "%3.0f%4.0f%5.1f", 272 words / 512 / etime, s.dk_xfer[dn] / etime, 273 s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0.0); 274 return (row); 275 } 276 wmove(wnd, row++, col); 277 histogram(words / 512 / etime, 50, 1.0); 278 wmove(wnd, row++, col); 279 histogram(s.dk_xfer[dn] / etime, 50, 1.0); 280 if (msps) { 281 wmove(wnd, row++, col); 282 histogram(s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0, 283 50, 1.0); 284 } 285 return (row); 286 } 287 288 static void 289 stat1(row, o) 290 int row, o; 291 { 292 register i; 293 double time; 294 295 time = 0; 296 for (i = 0; i < CPUSTATES; i++) 297 time += s.cp_time[i]; 298 if (time == 0.0) 299 time = 1.0; 300 wmove(wnd, row, INSET); 301 #define CPUSCALE 0.5 302 histogram(100.0 * s.cp_time[o] / time, 50, CPUSCALE); 303 } 304 305 histogram(val, colwidth, scale) 306 double val; 307 int colwidth; 308 double scale; 309 { 310 char buf[10]; 311 register int k; 312 register int v = (int)(val * scale) + 0.5; 313 314 k = MIN(v, colwidth); 315 if (v > colwidth) { 316 sprintf(buf, "%4.1f", val); 317 k -= strlen(buf); 318 while (k--) 319 waddch(wnd, 'X'); 320 waddstr(wnd, buf); 321 return; 322 } 323 while (k--) 324 waddch(wnd, 'X'); 325 wclrtoeol(wnd); 326 } 327 328 cmdiostat(cmd, args) 329 char *cmd, *args; 330 { 331 332 if (prefix(cmd, "msps")) 333 msps = !msps; 334 else if (prefix(cmd, "numbers")) 335 numbers = 1; 336 else if (prefix(cmd, "bars")) 337 numbers = 0; 338 else if (!dkcmd(cmd, args)) 339 return (0); 340 wclear(wnd); 341 labeliostat(); 342 refresh(); 343 return (1); 344 } 345