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