iostat.c revision 1590
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 35static 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 49static 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 75static 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 84static int linesperregion; 85static double etime; 86static int numbers = 0; /* default display bar graphs */ 87static int msps = 0; /* default ms/seek shown */ 88 89static int barlabels __P((int)); 90static void histogram __P((double, int, double)); 91static int numlabels __P((int)); 92static int stats __P((int, int, int)); 93static void stat1 __P((int, int)); 94 95 96WINDOW * 97openiostat() 98{ 99 return (subwin(stdscr, LINES-1-5, 0, 5, 0)); 100} 101 102void 103closeiostat(w) 104 WINDOW *w; 105{ 106 if (w == NULL) 107 return; 108 wclear(w); 109 wrefresh(w); 110 delwin(w); 111} 112 113int 114initiostat() 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 141void 142fetchiostat() 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 156void 157labeliostat() 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, " idle|"); 173 if (numbers) 174 row = numlabels(row + 1); 175 else 176 row = barlabels(row + 1); 177} 178 179static int 180numlabels(row) 181 int row; 182{ 183 int i, col, regions, ndrives; 184 185#define COLWIDTH 14 186#define DRIVESPERLINE ((wnd->maxx - INSET) / COLWIDTH) 187 for (ndrives = 0, i = 0; i < dk_ndrive; i++) 188 if (dk_select[i]) 189 ndrives++; 190 regions = howmany(ndrives, DRIVESPERLINE); 191 /* 192 * Deduct -regions for blank line after each scrolling region. 193 */ 194 linesperregion = (wnd->maxy - row - regions) / regions; 195 /* 196 * Minimum region contains space for two 197 * label lines and one line of statistics. 198 */ 199 if (linesperregion < 3) 200 linesperregion = 3; 201 col = 0; 202 for (i = 0; i < dk_ndrive; i++) 203 if (dk_select[i] && dk_mspw[i] != 0.0) { 204 if (col + COLWIDTH >= wnd->maxx - INSET) { 205 col = 0, row += linesperregion + 1; 206 if (row > wnd->maxy - (linesperregion + 1)) 207 break; 208 } 209 mvwaddstr(wnd, row, col + 4, dr_name[i]); 210 mvwaddstr(wnd, row + 1, col, "bps tps msps"); 211 col += COLWIDTH; 212 } 213 if (col) 214 row += linesperregion + 1; 215 return (row); 216} 217 218static int 219barlabels(row) 220 int row; 221{ 222 int i; 223 224 mvwaddstr(wnd, row++, INSET, 225 "/0 /5 /10 /15 /20 /25 /30 /35 /40 /45 /50"); 226 linesperregion = 2 + msps; 227 for (i = 0; i < dk_ndrive; i++) 228 if (dk_select[i] && dk_mspw[i] != 0.0) { 229 if (row > wnd->maxy - linesperregion) 230 break; 231 mvwprintw(wnd, row++, 0, "%3.3s bps|", dr_name[i]); 232 mvwaddstr(wnd, row++, 0, " tps|"); 233 if (msps) 234 mvwaddstr(wnd, row++, 0, " msps|"); 235 } 236 return (row); 237} 238 239 240void 241showiostat() 242{ 243 register long t; 244 register int i, row, col; 245 246 if (namelist[X_DK_BUSY].n_type == 0) 247 return; 248 for (i = 0; i < dk_ndrive; i++) { 249#define X(fld) t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t 250 X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time); 251 } 252 etime = 0; 253 for(i = 0; i < CPUSTATES; i++) { 254 X(cp_time); 255 etime += s.cp_time[i]; 256 } 257 if (etime == 0.0) 258 etime = 1.0; 259 etime /= (float) hz; 260 row = 1; 261 262 /* 263 * Last CPU state not calculated yet. 264 */ 265 for (i = 0; i < CPUSTATES - 1; i++) 266 stat1(row++, i); 267 if (!numbers) { 268 row += 2; 269 for (i = 0; i < dk_ndrive; i++) 270 if (dk_select[i] && dk_mspw[i] != 0.0) { 271 if (row > wnd->maxy - linesperregion) 272 break; 273 row = stats(row, INSET, i); 274 } 275 return; 276 } 277 col = 0; 278 wmove(wnd, row + linesperregion, 0); 279 wdeleteln(wnd); 280 wmove(wnd, row + 3, 0); 281 winsertln(wnd); 282 for (i = 0; i < dk_ndrive; i++) 283 if (dk_select[i] && dk_mspw[i] != 0.0) { 284 if (col + COLWIDTH >= wnd->maxx) { 285 col = 0, row += linesperregion + 1; 286 if (row > wnd->maxy - (linesperregion + 1)) 287 break; 288 wmove(wnd, row + linesperregion, 0); 289 wdeleteln(wnd); 290 wmove(wnd, row + 3, 0); 291 winsertln(wnd); 292 } 293 (void) stats(row + 3, col, i); 294 col += COLWIDTH; 295 } 296} 297 298static int 299stats(row, col, dn) 300 int row, col, dn; 301{ 302 double atime, words, xtime, itime; 303 304 atime = s.dk_time[dn]; 305 atime /= (float) hz; 306 words = s.dk_wds[dn]*32.0; /* number of words transferred */ 307 xtime = dk_mspw[dn]*words; /* transfer time */ 308 itime = atime - xtime; /* time not transferring */ 309 if (xtime < 0) 310 itime += xtime, xtime = 0; 311 if (itime < 0) 312 xtime += itime, itime = 0; 313 if (numbers) { 314 mvwprintw(wnd, row, col, "%3.0f%4.0f%5.1f", 315 words / 512 / etime, s.dk_xfer[dn] / etime, 316 s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0.0); 317 return (row); 318 } 319 wmove(wnd, row++, col); 320 histogram(words / 512 / etime, 50, 1.0); 321 wmove(wnd, row++, col); 322 histogram(s.dk_xfer[dn] / etime, 50, 1.0); 323 if (msps) { 324 wmove(wnd, row++, col); 325 histogram(s.dk_seek[dn] ? itime * 1000. / s.dk_seek[dn] : 0, 326 50, 1.0); 327 } 328 return (row); 329} 330 331static void 332stat1(row, o) 333 int row, o; 334{ 335 register int i; 336 double time; 337 338 time = 0; 339 for (i = 0; i < CPUSTATES; i++) 340 time += s.cp_time[i]; 341 if (time == 0.0) 342 time = 1.0; 343 wmove(wnd, row, INSET); 344#define CPUSCALE 0.5 345 histogram(100.0 * s.cp_time[o] / time, 50, CPUSCALE); 346} 347 348static void 349histogram(val, colwidth, scale) 350 double val; 351 int colwidth; 352 double scale; 353{ 354 char buf[10]; 355 register int k; 356 register int v = (int)(val * scale) + 0.5; 357 358 k = MIN(v, colwidth); 359 if (v > colwidth) { 360 sprintf(buf, "%4.1f", val); 361 k -= strlen(buf); 362 while (k--) 363 waddch(wnd, 'X'); 364 waddstr(wnd, buf); 365 return; 366 } 367 while (k--) 368 waddch(wnd, 'X'); 369 wclrtoeol(wnd); 370} 371 372int 373cmdiostat(cmd, args) 374 char *cmd, *args; 375{ 376 377 if (prefix(cmd, "msps")) 378 msps = !msps; 379 else if (prefix(cmd, "numbers")) 380 numbers = 1; 381 else if (prefix(cmd, "bars")) 382 numbers = 0; 383 else if (!dkcmd(cmd, args)) 384 return (0); 385 wclear(wnd); 386 labeliostat(); 387 refresh(); 388 return (1); 389} 390