1 /* $OpenBSD: iostat.c,v 1.18 2003/06/26 19:47:09 deraadt Exp $ */ 2 /* $NetBSD: iostat.c,v 1.10 1996/10/25 18:21:58 scottr Exp $ */ 3 4 /* 5 * Copyright (c) 1996 John M. Vinopal 6 * 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 for the NetBSD Project 19 * by John M. Vinopal. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 /*- 37 * Copyright (c) 1986, 1991, 1993 38 * The Regents of the University of California. All rights reserved. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 */ 64 65 #ifndef lint 66 static char copyright[] = 67 "@(#) Copyright (c) 1986, 1991, 1993\n\ 68 The Regents of the University of California. All rights reserved.\n"; 69 #endif /* not lint */ 70 71 #ifndef lint 72 #if 0 73 static char sccsid[] = "@(#)iostat.c 8.2 (Berkeley) 1/26/94"; 74 #else 75 static char *rcsid = "$NetBSD: iostat.c,v 1.10 1996/10/25 18:21:58 scottr Exp $" 76 ; 77 #endif 78 #endif /* not lint */ 79 80 #include <sys/dkstat.h> 81 #include <sys/time.h> 82 83 #include <err.h> 84 #include <ctype.h> 85 #include <signal.h> 86 #include <stdio.h> 87 #include <stdlib.h> 88 #include <string.h> 89 #include <unistd.h> 90 #include <kvm.h> 91 92 #include "dkstats.h" 93 94 /* Defined in dkstats.c */ 95 extern struct _disk cur, last; 96 extern int dk_ndrive; 97 98 /* Namelist and memory files. */ 99 kvm_t *kd; 100 char *nlistf, *memf; 101 102 int hz, reps, interval; 103 static int todo = 0; 104 105 volatile sig_atomic_t wantheader; 106 107 #define ISSET(x, a) ((x) & (a)) 108 #define SHOW_CPU 0x0001 109 #define SHOW_TTY 0x0002 110 #define SHOW_STATS_1 0x0004 111 #define SHOW_STATS_2 0x0008 112 #define SHOW_TOTALS 0x0080 113 114 static void cpustats(void); 115 static void disk_stats(double); 116 static void disk_stats2(double); 117 static void sigheader(int); 118 static void header(void); 119 static void usage(void); 120 static void display(void); 121 static void selectdrives(int, char **); 122 123 void dkswap(void); 124 void dkreadstats(void); 125 int dkinit(int); 126 127 int 128 main(int argc, char *argv[]) 129 { 130 int ch, hdrcnt; 131 struct timeval tv; 132 133 while ((ch = getopt(argc, argv, "Cc:dDIM:N:Tw:")) != -1) 134 switch(ch) { 135 case 'c': 136 if ((reps = atoi(optarg)) <= 0) 137 errx(1, "repetition count <= 0."); 138 break; 139 case 'C': 140 todo |= SHOW_CPU; 141 break; 142 case 'd': 143 todo |= SHOW_STATS_1; 144 break; 145 case 'D': 146 todo |= SHOW_STATS_2; 147 break; 148 case 'I': 149 todo |= SHOW_TOTALS; 150 break; 151 case 'M': 152 memf = optarg; 153 break; 154 case 'N': 155 nlistf = optarg; 156 break; 157 case 'T': 158 todo |= SHOW_TTY; 159 break; 160 case 'w': 161 if ((interval = atoi(optarg)) <= 0) 162 errx(1, "interval <= 0."); 163 break; 164 case '?': 165 default: 166 usage(); 167 } 168 argc -= optind; 169 argv += optind; 170 171 if (!ISSET(todo, SHOW_CPU | SHOW_TTY | SHOW_STATS_1 | SHOW_STATS_2)) 172 todo |= SHOW_CPU | SHOW_TTY | SHOW_STATS_1; 173 174 dkinit(0); 175 dkreadstats(); 176 selectdrives(argc, argv); 177 178 tv.tv_sec = interval; 179 tv.tv_usec = 0; 180 181 /* print a new header on sigcont */ 182 (void)signal(SIGCONT, sigheader); 183 184 for (hdrcnt = 1;;) { 185 if (!--hdrcnt || wantheader) { 186 header(); 187 hdrcnt = 20; 188 wantheader = 0; 189 } 190 191 if (!ISSET(todo, SHOW_TOTALS)) 192 dkswap(); 193 display(); 194 195 if (reps >= 0 && --reps <= 0) 196 break; 197 select(0, NULL, NULL, NULL, &tv); 198 dkreadstats(); 199 if (last.dk_ndrive != cur.dk_ndrive) wantheader = 1; 200 } 201 exit(0); 202 } 203 204 static void 205 sigheader(signo) 206 int signo; 207 { 208 wantheader = 1; 209 } 210 211 static void 212 header(void) 213 { 214 int i; 215 216 /* Main Headers. */ 217 if (ISSET(todo, SHOW_TTY)) 218 (void)printf(" tty"); 219 220 if (ISSET(todo, SHOW_STATS_1)) 221 for (i = 0; i < dk_ndrive; i++) 222 if (cur.dk_select[i]) 223 (void)printf(" %14.14s ", cur.dk_name[i]); 224 225 if (ISSET(todo, SHOW_STATS_2)) 226 for (i = 0; i < dk_ndrive; i++) 227 if (cur.dk_select[i]) 228 (void)printf(" %13.13s ", cur.dk_name[i]); 229 230 if (ISSET(todo, SHOW_CPU)) 231 (void)printf(" cpu"); 232 printf("\n"); 233 234 /* Sub-Headers. */ 235 if (ISSET(todo, SHOW_TTY)) 236 printf(" tin tout"); 237 238 if (ISSET(todo, SHOW_STATS_1)) 239 for (i = 0; i < dk_ndrive; i++) 240 if (cur.dk_select[i]) 241 if (ISSET(todo, SHOW_TOTALS)) 242 (void)printf(" KB/t xfr MB "); 243 else 244 (void)printf(" KB/t t/s MB/s "); 245 246 if (ISSET(todo, SHOW_STATS_2)) 247 for (i = 0; i < dk_ndrive; i++) 248 if (cur.dk_select[i]) 249 (void)printf(" KB xfr time "); 250 251 if (ISSET(todo, SHOW_CPU)) 252 (void)printf(" us ni sy in id"); 253 printf("\n"); 254 } 255 256 static void 257 disk_stats(etime) 258 double etime; 259 { 260 int dn; 261 double atime, mbps; 262 263 for (dn = 0; dn < dk_ndrive; ++dn) { 264 if (!cur.dk_select[dn]) 265 continue; 266 267 /* average Kbytes per transfer. */ 268 if (cur.dk_xfer[dn]) 269 mbps = (cur.dk_bytes[dn] / (1024.0)) / cur.dk_xfer[dn]; 270 else 271 mbps = 0.0; 272 (void)printf(" %5.2f", mbps); 273 274 /* average transfers per second. */ 275 (void)printf(" %3.0f", cur.dk_xfer[dn] / etime); 276 277 /* time busy in disk activity */ 278 atime = (double)cur.dk_time[dn].tv_sec + 279 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 280 281 /* Megabytes per second. */ 282 if (atime != 0.0) 283 mbps = cur.dk_bytes[dn] / (double)(1024 * 1024); 284 else 285 mbps = 0; 286 (void)printf(" %4.2f ", mbps / etime); 287 } 288 } 289 290 static void 291 disk_stats2(etime) 292 double etime; 293 { 294 int dn; 295 double atime; 296 297 for (dn = 0; dn < dk_ndrive; ++dn) { 298 if (!cur.dk_select[dn]) 299 continue; 300 301 /* average kbytes per second. */ 302 (void)printf(" %4.0f", cur.dk_bytes[dn] / (1024.0) / etime); 303 304 /* average transfers per second. */ 305 (void)printf(" %3.0f", cur.dk_xfer[dn] / etime); 306 307 /* average time busy in disk activity. */ 308 atime = (double)cur.dk_time[dn].tv_sec + 309 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 310 (void)printf(" %4.2f ", atime / etime); 311 } 312 } 313 314 static void 315 cpustats() 316 { 317 int state; 318 double time; 319 320 time = 0; 321 for (state = 0; state < CPUSTATES; ++state) 322 time += cur.cp_time[state]; 323 if (!time) 324 time = 1.0; 325 /* States are generally never 100% and can use %3.0f. */ 326 for (state = 0; state < CPUSTATES; ++state) 327 printf("%3.0f", 100. * cur.cp_time[state] / time); 328 } 329 330 static void 331 usage() 332 { 333 (void)fprintf(stderr, 334 "usage: iostat [-CdDIT] [-c count] [-M core] [-N system] [-w wait] [drives]\n"); 335 exit(1); 336 } 337 338 static void 339 display() 340 { 341 int i; 342 double etime; 343 344 /* Sum up the elapsed ticks. */ 345 etime = 0.0; 346 for (i = 0; i < CPUSTATES; i++) { 347 etime += cur.cp_time[i]; 348 } 349 if (etime == 0.0) 350 etime = 1.0; 351 /* Convert to seconds. */ 352 etime /= (float)hz; 353 354 /* If we're showing totals only, then don't divide by the 355 * system time. 356 */ 357 if (ISSET(todo, SHOW_TOTALS)) 358 etime = 1.0; 359 360 if (ISSET(todo, SHOW_TTY)) 361 printf("%4.0f %4.0f", cur.tk_nin / etime, cur.tk_nout / etime); 362 363 if (ISSET(todo, SHOW_STATS_1)) 364 disk_stats(etime); 365 366 if (ISSET(todo, SHOW_STATS_2)) 367 disk_stats2(etime); 368 369 if (ISSET(todo, SHOW_CPU)) 370 cpustats(); 371 372 (void)printf("\n"); 373 (void)fflush(stdout); 374 } 375 376 static void 377 selectdrives(argc, argv) 378 int argc; 379 char *argv[]; 380 { 381 int i, ndrives; 382 383 /* 384 * Choose drives to be displayed. Priority goes to (in order) drives 385 * supplied as arguments and default drives. If everything isn't 386 * filled in and there are drives not taken care of, display the first 387 * few that fit. 388 * 389 * The backward compatibility #ifdefs permit the syntax: 390 * iostat [ drives ] [ interval [ count ] ] 391 */ 392 #define BACKWARD_COMPATIBILITY 393 for (ndrives = 0; *argv; ++argv) { 394 #ifdef BACKWARD_COMPATIBILITY 395 if (isdigit(**argv)) 396 break; 397 #endif 398 for (i = 0; i < dk_ndrive; i++) { 399 if (strcmp(cur.dk_name[i], *argv)) 400 continue; 401 cur.dk_select[i] = 1; 402 ++ndrives; 403 } 404 } 405 #ifdef BACKWARD_COMPATIBILITY 406 if (*argv) { 407 interval = atoi(*argv); 408 if (*++argv) 409 reps = atoi(*argv); 410 } 411 #endif 412 413 if (interval) { 414 if (!reps) 415 reps = -1; 416 } else 417 if (reps) 418 interval = 1; 419 420 /* Pick up to 4 drives if none specified. */ 421 if (ndrives == 0) 422 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 423 if (cur.dk_select[i]) 424 continue; 425 cur.dk_select[i] = 1; 426 ++ndrives; 427 } 428 } 429