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