1 /* $OpenBSD: iostat.c,v 1.27 2009/11/22 22:22:14 tedu 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 #include <sys/dkstat.h> 66 #include <sys/time.h> 67 68 #include <err.h> 69 #include <ctype.h> 70 #include <signal.h> 71 #include <stdio.h> 72 #include <stdlib.h> 73 #include <string.h> 74 #include <unistd.h> 75 #include <kvm.h> 76 77 #include "dkstats.h" 78 79 /* Defined in dkstats.c */ 80 extern struct _disk cur, last; 81 extern int dk_ndrive; 82 83 /* Namelist and memory files. */ 84 kvm_t *kd; 85 char *nlistf, *memf; 86 87 int hz, reps, interval; 88 static int todo = 0; 89 90 volatile sig_atomic_t wantheader; 91 92 #define ISSET(x, a) ((x) & (a)) 93 #define SHOW_CPU 0x0001 94 #define SHOW_TTY 0x0002 95 #define SHOW_STATS_1 0x0004 96 #define SHOW_STATS_2 0x0008 97 #define SHOW_TOTALS 0x0080 98 99 static void cpustats(void); 100 static void disk_stats(double); 101 static void disk_stats2(double); 102 static void sigheader(int); 103 static void header(void); 104 static void usage(void); 105 static void display(void); 106 static void selectdrives(char **); 107 108 void dkswap(void); 109 void dkreadstats(void); 110 int dkinit(int); 111 112 int 113 main(int argc, char *argv[]) 114 { 115 int ch, hdrcnt; 116 struct timeval tv; 117 118 while ((ch = getopt(argc, argv, "Cc:dDIM:N:Tw:")) != -1) 119 switch(ch) { 120 case 'c': 121 if ((reps = atoi(optarg)) <= 0) 122 errx(1, "repetition count <= 0."); 123 break; 124 case 'C': 125 todo |= SHOW_CPU; 126 break; 127 case 'd': 128 todo |= SHOW_STATS_1; 129 break; 130 case 'D': 131 todo |= SHOW_STATS_2; 132 break; 133 case 'I': 134 todo |= SHOW_TOTALS; 135 break; 136 case 'M': 137 memf = optarg; 138 break; 139 case 'N': 140 nlistf = optarg; 141 break; 142 case 'T': 143 todo |= SHOW_TTY; 144 break; 145 case 'w': 146 if ((interval = atoi(optarg)) <= 0) 147 errx(1, "interval <= 0."); 148 break; 149 case '?': 150 default: 151 usage(); 152 } 153 argc -= optind; 154 argv += optind; 155 156 if (!ISSET(todo, SHOW_CPU | SHOW_TTY | SHOW_STATS_1 | SHOW_STATS_2)) 157 todo |= SHOW_CPU | SHOW_TTY | SHOW_STATS_1; 158 159 dkinit(0); 160 dkreadstats(); 161 selectdrives(argv); 162 163 tv.tv_sec = interval; 164 tv.tv_usec = 0; 165 166 /* print a new header on sigcont */ 167 (void)signal(SIGCONT, sigheader); 168 169 for (hdrcnt = 1;;) { 170 if (!--hdrcnt || wantheader) { 171 header(); 172 hdrcnt = 20; 173 wantheader = 0; 174 } 175 176 if (!ISSET(todo, SHOW_TOTALS)) 177 dkswap(); 178 display(); 179 180 if (reps >= 0 && --reps <= 0) 181 break; 182 select(0, NULL, NULL, NULL, &tv); 183 dkreadstats(); 184 if (last.dk_ndrive != cur.dk_ndrive) 185 wantheader = 1; 186 } 187 exit(0); 188 } 189 190 /*ARGSUSED*/ 191 static void 192 sigheader(int signo) 193 { 194 wantheader = 1; 195 } 196 197 static void 198 header(void) 199 { 200 int i; 201 static int printedheader = 0; 202 203 if (printedheader && !isatty(STDOUT_FILENO)) 204 return; 205 206 /* Main Headers. */ 207 if (ISSET(todo, SHOW_TTY)) 208 (void)printf(" tty"); 209 210 if (ISSET(todo, SHOW_STATS_1)) 211 for (i = 0; i < dk_ndrive; i++) 212 if (cur.dk_select[i]) 213 (void)printf(" %14.14s ", cur.dk_name[i]); 214 215 if (ISSET(todo, SHOW_STATS_2)) 216 for (i = 0; i < dk_ndrive; i++) 217 if (cur.dk_select[i]) 218 (void)printf(" %13.13s ", cur.dk_name[i]); 219 220 if (ISSET(todo, SHOW_CPU)) 221 (void)printf(" cpu"); 222 printf("\n"); 223 224 /* Sub-Headers. */ 225 if (ISSET(todo, SHOW_TTY)) 226 printf(" tin tout"); 227 228 if (ISSET(todo, SHOW_STATS_1)) 229 for (i = 0; i < dk_ndrive; i++) 230 if (cur.dk_select[i]) { 231 if (ISSET(todo, SHOW_TOTALS)) 232 (void)printf(" KB/t xfr MB "); 233 else 234 (void)printf(" KB/t t/s MB/s "); 235 } 236 if (ISSET(todo, SHOW_STATS_2)) 237 for (i = 0; i < dk_ndrive; i++) 238 if (cur.dk_select[i]) { 239 (void)printf(" KB xfr time "); 240 } 241 if (ISSET(todo, SHOW_CPU)) 242 (void)printf(" us ni sy in id"); 243 printf("\n"); 244 } 245 246 static void 247 disk_stats(double etime) 248 { 249 int dn; 250 double atime, mbps; 251 252 for (dn = 0; dn < dk_ndrive; ++dn) { 253 if (!cur.dk_select[dn]) 254 continue; 255 256 /* average Kbytes per transfer. */ 257 if (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) 258 mbps = ((cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / 259 (1024.0)) / (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]); 260 else 261 mbps = 0.0; 262 263 (void)printf(" %5.2f", mbps); 264 265 /* average transfers per second. */ 266 (void)printf(" %3.0f", 267 (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime); 268 269 /* time busy in disk activity */ 270 atime = (double)cur.dk_time[dn].tv_sec + 271 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 272 273 /* Megabytes per second. */ 274 if (atime != 0.0) 275 mbps = (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / 276 (double)(1024 * 1024); 277 else 278 mbps = 0; 279 (void)printf(" %4.2f ", mbps / etime); 280 } 281 } 282 283 static void 284 disk_stats2(double etime) 285 { 286 int dn; 287 double atime; 288 289 for (dn = 0; dn < dk_ndrive; ++dn) { 290 if (!cur.dk_select[dn]) 291 continue; 292 293 /* average kbytes per second. */ 294 (void)printf(" %4.0f", 295 (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / (1024.0) / etime); 296 297 /* average transfers per second. */ 298 (void)printf(" %3.0f", 299 (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime); 300 301 /* average time busy in disk activity. */ 302 atime = (double)cur.dk_time[dn].tv_sec + 303 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 304 (void)printf(" %4.2f ", atime / etime); 305 } 306 } 307 308 static void 309 cpustats(void) 310 { 311 int state; 312 double t = 0; 313 314 for (state = 0; state < CPUSTATES; ++state) 315 t += cur.cp_time[state]; 316 if (!t) 317 t = 1.0; 318 /* States are generally never 100% and can use %3.0f. */ 319 for (state = 0; state < CPUSTATES; ++state) 320 printf("%3.0f", 100. * cur.cp_time[state] / t); 321 } 322 323 static void 324 usage(void) 325 { 326 (void)fprintf(stderr, 327 "usage: iostat [-CDdIT] [-c count] [-M core] [-N system] [-w wait] [drives]\n"); 328 exit(1); 329 } 330 331 static void 332 display(void) 333 { 334 int i; 335 double etime; 336 337 /* Sum up the elapsed ticks. */ 338 etime = 0.0; 339 for (i = 0; i < CPUSTATES; i++) { 340 etime += cur.cp_time[i]; 341 } 342 if (etime == 0.0) 343 etime = 1.0; 344 /* Convert to seconds. */ 345 etime /= (float)hz; 346 347 /* If we're showing totals only, then don't divide by the 348 * system time. 349 */ 350 if (ISSET(todo, SHOW_TOTALS)) 351 etime = 1.0; 352 353 if (ISSET(todo, SHOW_TTY)) 354 printf("%4.0f %4.0f", cur.tk_nin / etime, cur.tk_nout / etime); 355 356 if (ISSET(todo, SHOW_STATS_1)) 357 disk_stats(etime); 358 359 if (ISSET(todo, SHOW_STATS_2)) 360 disk_stats2(etime); 361 362 if (ISSET(todo, SHOW_CPU)) 363 cpustats(); 364 365 (void)printf("\n"); 366 (void)fflush(stdout); 367 } 368 369 static void 370 selectdrives(char *argv[]) 371 { 372 int i, ndrives; 373 374 /* 375 * Choose drives to be displayed. Priority goes to (in order) drives 376 * supplied as arguments and default drives. If everything isn't 377 * filled in and there are drives not taken care of, display the first 378 * few that fit. 379 * 380 * The backward compatibility #ifdefs permit the syntax: 381 * iostat [ drives ] [ interval [ count ] ] 382 */ 383 #define BACKWARD_COMPATIBILITY 384 for (ndrives = 0; *argv; ++argv) { 385 #ifdef BACKWARD_COMPATIBILITY 386 if (isdigit(**argv)) 387 break; 388 #endif 389 for (i = 0; i < dk_ndrive; i++) { 390 if (strcmp(cur.dk_name[i], *argv)) 391 continue; 392 cur.dk_select[i] = 1; 393 ++ndrives; 394 } 395 } 396 #ifdef BACKWARD_COMPATIBILITY 397 if (*argv) { 398 interval = atoi(*argv); 399 if (*++argv) 400 reps = atoi(*argv); 401 } 402 #endif 403 404 if (interval) { 405 if (!reps) 406 reps = -1; 407 } else 408 if (reps) 409 interval = 1; 410 411 /* Pick up to 4 drives if none specified. */ 412 if (ndrives == 0) 413 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 414 if (cur.dk_select[i]) 415 continue; 416 cur.dk_select[i] = 1; 417 ++ndrives; 418 } 419 } 420