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