1 /* 2 * Copyright (c) 1980, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char sccsid[] = "@(#)iostat.c 8.1 (Berkeley) 6/6/93"; 36 #endif not lint 37 38 #include <sys/param.h> 39 #include <sys/dkstat.h> 40 #include <sys/buf.h> 41 42 #include <string.h> 43 #include <stdlib.h> 44 #include <nlist.h> 45 #include <paths.h> 46 #include "systat.h" 47 #include "extern.h" 48 49 static struct nlist namelist[] = { 50 #define X_DK_BUSY 0 51 { "_dk_busy" }, 52 #define X_DK_TIME 1 53 { "_dk_time" }, 54 #define X_DK_XFER 2 55 { "_dk_xfer" }, 56 #define X_DK_WDS 3 57 { "_dk_wds" }, 58 #define X_DK_SEEK 4 59 { "_dk_seek" }, 60 #define X_CP_TIME 5 61 { "_cp_time" }, 62 #ifdef vax 63 #define X_MBDINIT (X_CP_TIME+1) 64 { "_mbdinit" }, 65 #define X_UBDINIT (X_CP_TIME+2) 66 { "_ubdinit" }, 67 #endif 68 #ifdef tahoe 69 #define X_VBDINIT (X_CP_TIME+1) 70 { "_vbdinit" }, 71 #endif 72 { "" }, 73 }; 74 75 static struct { 76 int dk_busy; 77 long cp_time[CPUSTATES]; 78 long *dk_time; 79 long *dk_wds; 80 long *dk_seek; 81 long *dk_xfer; 82 } s, s1; 83 84 static int linesperregion; 85 static double etime; 86 static int numbers = 0; /* default display bar graphs */ 87 static int msps = 0; /* default ms/seek shown */ 88 89 static int barlabels __P((int)); 90 static void histogram __P((double, int, double)); 91 static int numlabels __P((int)); 92 static int stats __P((int, int, int)); 93 static void stat1 __P((int, int)); 94 95 96 WINDOW * 97 openiostat() 98 { 99 return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 100 } 101 102 void 103 closeiostat(w) 104 WINDOW *w; 105 { 106 if (w == NULL) 107 return; 108 wclear(w); 109 wrefresh(w); 110 delwin(w); 111 } 112 113 int 114 initiostat() 115 { 116 if (namelist[X_DK_BUSY].n_type == 0) { 117 if (kvm_nlist(kd, namelist)) { 118 nlisterr(namelist); 119 return(0); 120 } 121 if (namelist[X_DK_BUSY].n_type == 0) { 122 error("Disk init information isn't in namelist"); 123 return(0); 124 } 125 } 126 if (! dkinit()) 127 return(0); 128 if (dk_ndrive) { 129 #define allocate(e, t) \ 130 s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \ 131 s1./**/e = (t *)calloc(dk_ndrive, sizeof (t)); 132 allocate(dk_time, long); 133 allocate(dk_wds, long); 134 allocate(dk_seek, long); 135 allocate(dk_xfer, long); 136 #undef allocate 137 } 138 return(1); 139 } 140 141 void 142 fetchiostat() 143 { 144 if (namelist[X_DK_BUSY].n_type == 0) 145 return; 146 NREAD(X_DK_BUSY, &s.dk_busy, LONG); 147 NREAD(X_DK_TIME, s.dk_time, dk_ndrive * LONG); 148 NREAD(X_DK_XFER, s.dk_xfer, dk_ndrive * LONG); 149 NREAD(X_DK_WDS, s.dk_wds, dk_ndrive * LONG); 150 NREAD(X_DK_SEEK, s.dk_seek, dk_ndrive * LONG); 151 NREAD(X_CP_TIME, s.cp_time, sizeof s.cp_time); 152 } 153 154 #define INSET 10 155 156 void 157 labeliostat() 158 { 159 int row; 160 161 if (namelist[X_DK_BUSY].n_type == 0) { 162 error("No dk_busy defined."); 163 return; 164 } 165 row = 0; 166 wmove(wnd, row, 0); wclrtobot(wnd); 167 mvwaddstr(wnd, row++, INSET, 168 "/0 /10 /20 /30 /40 /50 /60 /70 /80 /90 /100"); 169 mvwaddstr(wnd, row++, 0, "cpu user|"); 170 mvwaddstr(wnd, row++, 0, " nice|"); 171 mvwaddstr(wnd, row++, 0, " system|"); 172 mvwaddstr(wnd, row++, 0, "interrupt|"); 173 mvwaddstr(wnd, row++, 0, " idle|"); 174 if (numbers) 175 row = numlabels(row + 1); 176 else 177 row = barlabels(row + 1); 178 } 179 180 static int 181 numlabels(row) 182 int row; 183 { 184 int i, col, regions, ndrives; 185 186 #define COLWIDTH 14 187 #define DRIVESPERLINE ((wnd->maxx - INSET) / COLWIDTH) 188 for (ndrives = 0, i = 0; i < dk_ndrive; i++) 189 if (dk_select[i]) 190 ndrives++; 191 regions = howmany(ndrives, DRIVESPERLINE); 192 /* 193 * Deduct -regions for blank line after each scrolling region. 194 */ 195 linesperregion = (wnd->maxy - row - regions) / regions; 196 /* 197 * Minimum region contains space for two 198 * label lines and one line of statistics. 199 */ 200 if (linesperregion < 3) 201 linesperregion = 3; 202 col = 0; 203 for (i = 0; i < dk_ndrive; i++) 204 if (dk_select[i] && dk_mspw[i] != 0.0) { 205 if (col + COLWIDTH >= wnd->maxx - INSET) { 206 col = 0, row += linesperregion + 1; 207 if (row > wnd->maxy - (linesperregion + 1)) 208 break; 209 } 210 mvwaddstr(wnd, row, col + 4, dr_name[i]); 211 mvwaddstr(wnd, row + 1, col, "bps tps msps"); 212 col += COLWIDTH; 213 } 214 if (col) 215 row += linesperregion + 1; 216 return (row); 217 } 218 219 static int 220 barlabels(row) 221 int row; 222 { 223 int i; 224 225 mvwaddstr(wnd, row++, INSET, 226 "/0 /5 /10 /15 /20 /25 /30 /35 /40 /45 /50"); 227 linesperregion = 2 + msps; 228 for (i = 0; i < dk_ndrive; i++) 229 if (dk_select[i] && dk_mspw[i] != 0.0) { 230 if (row > wnd->maxy - linesperregion) 231 break; 232 mvwprintw(wnd, row++, 0, "%3.3s bps|", dr_name[i]); 233 mvwaddstr(wnd, row++, 0, " tps|"); 234 if (msps) 235 mvwaddstr(wnd, row++, 0, " msps|"); 236 } 237 return (row); 238 } 239 240 241 void 242 showiostat() 243 { 244 register long t; 245 register int i, row, col; 246 247 if (namelist[X_DK_BUSY].n_type == 0) 248 return; 249 for (i = 0; i < dk_ndrive; i++) { 250 #define X(fld) t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t 251 X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time); 252 } 253 etime = 0; 254 for(i = 0; i < CPUSTATES; i++) { 255 X(cp_time); 256 etime += s.cp_time[i]; 257 } 258 if (etime == 0.0) 259 etime = 1.0; 260 etime /= hertz; 261 row = 1; 262 for (i = 0; i < CPUSTATES; i++) 263 stat1(row++, i); 264 if (!numbers) { 265 row += 2; 266 for (i = 0; i < dk_ndrive; i++) 267 if (dk_select[i] && dk_mspw[i] != 0.0) { 268 if (row > wnd->maxy - linesperregion) 269 break; 270 row = stats(row, INSET, i); 271 } 272 return; 273 } 274 col = 0; 275 wmove(wnd, row + linesperregion, 0); 276 wdeleteln(wnd); 277 wmove(wnd, row + 3, 0); 278 winsertln(wnd); 279 for (i = 0; i < dk_ndrive; i++) 280 if (dk_select[i] && dk_mspw[i] != 0.0) { 281 if (col + COLWIDTH >= wnd->maxx) { 282 col = 0, row += linesperregion + 1; 283 if (row > wnd->maxy - (linesperregion + 1)) 284 break; 285 wmove(wnd, row + linesperregion, 0); 286 wdeleteln(wnd); 287 wmove(wnd, row + 3, 0); 288 winsertln(wnd); 289 } 290 (void) stats(row + 3, col, i); 291 col += COLWIDTH; 292 } 293 } 294 295 static int 296 stats(row, col, dn) 297 int row, col, dn; 298 { 299 double atime, words, xtime, itime; 300 301 atime = s.dk_time[dn]; 302 atime /= hertz; 303 words = s.dk_wds[dn]*32.0; /* number of words transferred */ 304 xtime = dk_mspw[dn]*words; /* transfer time */ 305 itime = atime - xtime; /* time not transferring */ 306 if (xtime < 0) 307 itime += xtime, xtime = 0; 308 if (itime < 0) 309 xtime += itime, itime = 0; 310 if (numbers) { 311 mvwprintw(wnd, row, col, "%3.0f%4.0f%5.1f", 312 words / 512 / etime, s.dk_xfer[dn] / etime, 313 s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0.0); 314 return (row); 315 } 316 wmove(wnd, row++, col); 317 histogram(words / 512 / etime, 50, 1.0); 318 wmove(wnd, row++, col); 319 histogram(s.dk_xfer[dn] / etime, 50, 1.0); 320 if (msps) { 321 wmove(wnd, row++, col); 322 histogram(s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0, 323 50, 1.0); 324 } 325 return (row); 326 } 327 328 static void 329 stat1(row, o) 330 int row, o; 331 { 332 register int i; 333 double time; 334 335 time = 0; 336 for (i = 0; i < CPUSTATES; i++) 337 time += s.cp_time[i]; 338 if (time == 0.0) 339 time = 1.0; 340 wmove(wnd, row, INSET); 341 #define CPUSCALE 0.5 342 histogram(100.0 * s.cp_time[o] / time, 50, CPUSCALE); 343 } 344 345 static void 346 histogram(val, colwidth, scale) 347 double val; 348 int colwidth; 349 double scale; 350 { 351 char buf[10]; 352 register int k; 353 register int v = (int)(val * scale) + 0.5; 354 355 k = MIN(v, colwidth); 356 if (v > colwidth) { 357 sprintf(buf, "%4.1f", val); 358 k -= strlen(buf); 359 while (k--) 360 waddch(wnd, 'X'); 361 waddstr(wnd, buf); 362 return; 363 } 364 while (k--) 365 waddch(wnd, 'X'); 366 wclrtoeol(wnd); 367 } 368 369 int 370 cmdiostat(cmd, args) 371 char *cmd, *args; 372 { 373 374 if (prefix(cmd, "msps")) 375 msps = !msps; 376 else if (prefix(cmd, "numbers")) 377 numbers = 1; 378 else if (prefix(cmd, "bars")) 379 numbers = 0; 380 else if (!dkcmd(cmd, args)) 381 return (0); 382 wclear(wnd); 383 labeliostat(); 384 refresh(); 385 return (1); 386 } 387