1 /* $OpenBSD: iostat.c,v 1.25 2007/02/18 20:41:34 jmc 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(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(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) 200 wantheader = 1; 201 } 202 exit(0); 203 } 204 205 /*ARGSUSED*/ 206 static void 207 sigheader(int signo) 208 { 209 wantheader = 1; 210 } 211 212 static void 213 header(void) 214 { 215 int i; 216 217 /* Main Headers. */ 218 if (ISSET(todo, SHOW_TTY)) 219 (void)printf(" tty"); 220 221 if (ISSET(todo, SHOW_STATS_1)) 222 for (i = 0; i < dk_ndrive; i++) 223 if (cur.dk_select[i]) 224 (void)printf(" %14.14s ", cur.dk_name[i]); 225 226 if (ISSET(todo, SHOW_STATS_2)) 227 for (i = 0; i < dk_ndrive; i++) 228 if (cur.dk_select[i]) 229 (void)printf(" %13.13s ", cur.dk_name[i]); 230 231 if (ISSET(todo, SHOW_CPU)) 232 (void)printf(" cpu"); 233 printf("\n"); 234 235 /* Sub-Headers. */ 236 if (ISSET(todo, SHOW_TTY)) 237 printf(" tin tout"); 238 239 if (ISSET(todo, SHOW_STATS_1)) 240 for (i = 0; i < dk_ndrive; i++) 241 if (cur.dk_select[i]) { 242 if (ISSET(todo, SHOW_TOTALS)) 243 (void)printf(" KB/t xfr MB "); 244 else 245 (void)printf(" KB/t t/s MB/s "); 246 } 247 if (ISSET(todo, SHOW_STATS_2)) 248 for (i = 0; i < dk_ndrive; i++) 249 if (cur.dk_select[i]) { 250 (void)printf(" KB xfr time "); 251 } 252 if (ISSET(todo, SHOW_CPU)) 253 (void)printf(" us ni sy in id"); 254 printf("\n"); 255 } 256 257 static void 258 disk_stats(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_rxfer[dn] + cur.dk_wxfer[dn]) 269 mbps = ((cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / 270 (1024.0)) / (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]); 271 else 272 mbps = 0.0; 273 274 (void)printf(" %5.2f", mbps); 275 276 /* average transfers per second. */ 277 (void)printf(" %3.0f", 278 (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime); 279 280 /* time busy in disk activity */ 281 atime = (double)cur.dk_time[dn].tv_sec + 282 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 283 284 /* Megabytes per second. */ 285 if (atime != 0.0) 286 mbps = (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / 287 (double)(1024 * 1024); 288 else 289 mbps = 0; 290 (void)printf(" %4.2f ", mbps / etime); 291 } 292 } 293 294 static void 295 disk_stats2(double etime) 296 { 297 int dn; 298 double atime; 299 300 for (dn = 0; dn < dk_ndrive; ++dn) { 301 if (!cur.dk_select[dn]) 302 continue; 303 304 /* average kbytes per second. */ 305 (void)printf(" %4.0f", 306 (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / (1024.0) / etime); 307 308 /* average transfers per second. */ 309 (void)printf(" %3.0f", 310 (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime); 311 312 /* average time busy in disk activity. */ 313 atime = (double)cur.dk_time[dn].tv_sec + 314 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 315 (void)printf(" %4.2f ", atime / etime); 316 } 317 } 318 319 static void 320 cpustats(void) 321 { 322 int state; 323 double t = 0; 324 325 for (state = 0; state < CPUSTATES; ++state) 326 t += cur.cp_time[state]; 327 if (!t) 328 t = 1.0; 329 /* States are generally never 100% and can use %3.0f. */ 330 for (state = 0; state < CPUSTATES; ++state) 331 printf("%3.0f", 100. * cur.cp_time[state] / t); 332 } 333 334 static void 335 usage(void) 336 { 337 (void)fprintf(stderr, 338 "usage: iostat [-CDdIT] [-c count] [-M core] [-N system] [-w wait] [drives]\n"); 339 exit(1); 340 } 341 342 static void 343 display(void) 344 { 345 int i; 346 double etime; 347 348 /* Sum up the elapsed ticks. */ 349 etime = 0.0; 350 for (i = 0; i < CPUSTATES; i++) { 351 etime += cur.cp_time[i]; 352 } 353 if (etime == 0.0) 354 etime = 1.0; 355 /* Convert to seconds. */ 356 etime /= (float)hz; 357 358 /* If we're showing totals only, then don't divide by the 359 * system time. 360 */ 361 if (ISSET(todo, SHOW_TOTALS)) 362 etime = 1.0; 363 364 if (ISSET(todo, SHOW_TTY)) 365 printf("%4.0f %4.0f", cur.tk_nin / etime, cur.tk_nout / etime); 366 367 if (ISSET(todo, SHOW_STATS_1)) 368 disk_stats(etime); 369 370 if (ISSET(todo, SHOW_STATS_2)) 371 disk_stats2(etime); 372 373 if (ISSET(todo, SHOW_CPU)) 374 cpustats(); 375 376 (void)printf("\n"); 377 (void)fflush(stdout); 378 } 379 380 static void 381 selectdrives(char *argv[]) 382 { 383 int i, ndrives; 384 385 /* 386 * Choose drives to be displayed. Priority goes to (in order) drives 387 * supplied as arguments and default drives. If everything isn't 388 * filled in and there are drives not taken care of, display the first 389 * few that fit. 390 * 391 * The backward compatibility #ifdefs permit the syntax: 392 * iostat [ drives ] [ interval [ count ] ] 393 */ 394 #define BACKWARD_COMPATIBILITY 395 for (ndrives = 0; *argv; ++argv) { 396 #ifdef BACKWARD_COMPATIBILITY 397 if (isdigit(**argv)) 398 break; 399 #endif 400 for (i = 0; i < dk_ndrive; i++) { 401 if (strcmp(cur.dk_name[i], *argv)) 402 continue; 403 cur.dk_select[i] = 1; 404 ++ndrives; 405 } 406 } 407 #ifdef BACKWARD_COMPATIBILITY 408 if (*argv) { 409 interval = atoi(*argv); 410 if (*++argv) 411 reps = atoi(*argv); 412 } 413 #endif 414 415 if (interval) { 416 if (!reps) 417 reps = -1; 418 } else 419 if (reps) 420 interval = 1; 421 422 /* Pick up to 4 drives if none specified. */ 423 if (ndrives == 0) 424 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 425 if (cur.dk_select[i]) 426 continue; 427 cur.dk_select[i] = 1; 428 ++ndrives; 429 } 430 } 431