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