1 /* $OpenBSD: iostat.c,v 1.9 2001/05/14 07:22:06 angelos 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. All advertising materials mentioning features or use of this software 49 * must display the following acknowledgement: 50 * This product includes software developed by the University of 51 * California, Berkeley and its contributors. 52 * 4. Neither the name of the University nor the names of its contributors 53 * may be used to endorse or promote products derived from this software 54 * without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66 * SUCH DAMAGE. 67 */ 68 69 #ifndef lint 70 static char copyright[] = 71 "@(#) Copyright (c) 1986, 1991, 1993\n\ 72 The Regents of the University of California. All rights reserved.\n"; 73 #endif /* not lint */ 74 75 #ifndef lint 76 #if 0 77 static char sccsid[] = "@(#)iostat.c 8.2 (Berkeley) 1/26/94"; 78 #else 79 static char *rcsid = "$NetBSD: iostat.c,v 1.10 1996/10/25 18:21:58 scottr Exp $" 80 ; 81 #endif 82 #endif /* not lint */ 83 84 #include <sys/dkstat.h> 85 #include <sys/time.h> 86 87 #include <err.h> 88 #include <ctype.h> 89 #include <signal.h> 90 #include <stdio.h> 91 #include <stdlib.h> 92 #include <string.h> 93 #include <unistd.h> 94 95 #include "dkstats.h" 96 97 /* Defined in dkstats.c */ 98 extern struct _disk cur; 99 extern int dk_ndrive; 100 101 /* Namelist and memory files. */ 102 char *nlistf, *memf; 103 104 int hz, reps, interval; 105 static int todo = 0; 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 __P((void)); 115 static void disk_stats __P((double)); 116 static void disk_stats2 __P((double)); 117 static void header __P((int)); 118 static void usage __P((void)); 119 static void display __P((void)); 120 static void selectdrives __P((int, char **)); 121 122 void dkswap __P((void)); 123 void dkreadstats __P((void)); 124 int dkinit __P((int)); 125 126 int 127 main(argc, argv) 128 int argc; 129 char *argv[]; 130 { 131 int ch, hdrcnt; 132 struct timeval tv; 133 134 while ((ch = getopt(argc, argv, "Cc:dDIM:N:Tw:")) != -1) 135 switch(ch) { 136 case 'c': 137 if ((reps = atoi(optarg)) <= 0) 138 errx(1, "repetition count <= 0."); 139 break; 140 case 'C': 141 todo |= SHOW_CPU; 142 break; 143 case 'd': 144 todo |= SHOW_STATS_1; 145 break; 146 case 'D': 147 todo |= SHOW_STATS_2; 148 break; 149 case 'I': 150 todo |= SHOW_TOTALS; 151 break; 152 case 'M': 153 memf = optarg; 154 break; 155 case 'N': 156 nlistf = optarg; 157 break; 158 case 'T': 159 todo |= SHOW_TTY; 160 break; 161 case 'w': 162 if ((interval = atoi(optarg)) <= 0) 163 errx(1, "interval <= 0."); 164 break; 165 case '?': 166 default: 167 usage(); 168 } 169 argc -= optind; 170 argv += optind; 171 172 if (!ISSET(todo, SHOW_CPU | SHOW_TTY | SHOW_STATS_1 | SHOW_STATS_2)) 173 todo |= SHOW_CPU | SHOW_TTY | SHOW_STATS_1; 174 175 dkinit(0); 176 dkreadstats(); 177 selectdrives(argc, argv); 178 179 tv.tv_sec = interval; 180 tv.tv_usec = 0; 181 182 /* print a new header on sigcont */ 183 (void)signal(SIGCONT, header); 184 185 for (hdrcnt = 1;;) { 186 if (!--hdrcnt) { 187 header(0); 188 hdrcnt = 20; 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 } 200 exit(0); 201 } 202 203 static void 204 header(signo) 205 int signo; 206 { 207 register int i; 208 209 /* Main Headers. */ 210 if (ISSET(todo, SHOW_TTY)) 211 (void)printf(" tty"); 212 213 if (ISSET(todo, SHOW_STATS_1)) 214 for (i = 0; i < dk_ndrive; i++) 215 if (cur.dk_select[i]) 216 (void)printf(" %14.14s ", cur.dk_name[i]); 217 218 if (ISSET(todo, SHOW_STATS_2)) 219 for (i = 0; i < dk_ndrive; i++) 220 if (cur.dk_select[i]) 221 (void)printf(" %13.13s ", cur.dk_name[i]); 222 223 if (ISSET(todo, SHOW_CPU)) 224 (void)printf(" cpu"); 225 printf("\n"); 226 227 /* Sub-Headers. */ 228 if (ISSET(todo, SHOW_TTY)) 229 printf(" tin tout"); 230 231 if (ISSET(todo, SHOW_STATS_1)) 232 for (i = 0; i < dk_ndrive; i++) 233 if (cur.dk_select[i]) 234 if (ISSET(todo, SHOW_TOTALS)) 235 (void)printf(" KB/t xfr MB "); 236 else 237 (void)printf(" KB/t t/s MB/s "); 238 239 if (ISSET(todo, SHOW_STATS_2)) 240 for (i = 0; i < dk_ndrive; i++) 241 if (cur.dk_select[i]) 242 (void)printf(" KB xfr time "); 243 244 if (ISSET(todo, SHOW_CPU)) 245 (void)printf(" us ni sy in id"); 246 printf("\n"); 247 } 248 249 static void 250 disk_stats(etime) 251 double etime; 252 { 253 register int dn; 254 double atime, mbps; 255 256 for (dn = 0; dn < dk_ndrive; ++dn) { 257 if (!cur.dk_select[dn]) 258 continue; 259 260 /* average Kbytes per transfer. */ 261 if (cur.dk_xfer[dn]) 262 mbps = (cur.dk_bytes[dn] / (1024.0)) / cur.dk_xfer[dn]; 263 else 264 mbps = 0.0; 265 (void)printf(" %5.2f", mbps); 266 267 /* average transfers per second. */ 268 (void)printf(" %3.0f", cur.dk_xfer[dn] / etime); 269 270 /* time busy in disk activity */ 271 atime = (double)cur.dk_time[dn].tv_sec + 272 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 273 274 /* Megabytes per second. */ 275 if (atime != 0.0) 276 mbps = cur.dk_bytes[dn] / (double)(1024 * 1024); 277 else 278 mbps = 0; 279 (void)printf(" %4.2f ", mbps / etime); 280 } 281 } 282 283 static void 284 disk_stats2(etime) 285 double etime; 286 { 287 register int dn; 288 double atime; 289 290 for (dn = 0; dn < dk_ndrive; ++dn) { 291 if (!cur.dk_select[dn]) 292 continue; 293 294 /* average kbytes per second. */ 295 (void)printf(" %4.0f", cur.dk_bytes[dn] / (1024.0) / etime); 296 297 /* average transfers per second. */ 298 (void)printf(" %3.0f", cur.dk_xfer[dn] / etime); 299 300 /* average time busy in disk activity. */ 301 atime = (double)cur.dk_time[dn].tv_sec + 302 ((double)cur.dk_time[dn].tv_usec / (double)1000000); 303 (void)printf(" %4.2f ", atime / etime); 304 } 305 } 306 307 static void 308 cpustats() 309 { 310 register int state; 311 double time; 312 313 time = 0; 314 for (state = 0; state < CPUSTATES; ++state) 315 time += cur.cp_time[state]; 316 if (!time) 317 time = 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] / time); 321 } 322 323 static void 324 usage() 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() 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(argc, argv) 371 int argc; 372 char *argv[]; 373 { 374 int i, ndrives; 375 376 /* 377 * Choose drives to be displayed. Priority goes to (in order) drives 378 * supplied as arguments and default drives. If everything isn't 379 * filled in and there are drives not taken care of, display the first 380 * few that fit. 381 * 382 * The backward compatibility #ifdefs permit the syntax: 383 * iostat [ drives ] [ interval [ count ] ] 384 */ 385 #define BACKWARD_COMPATIBILITY 386 for (ndrives = 0; *argv; ++argv) { 387 #ifdef BACKWARD_COMPATIBILITY 388 if (isdigit(**argv)) 389 break; 390 #endif 391 for (i = 0; i < dk_ndrive; i++) { 392 if (strcmp(cur.dk_name[i], *argv)) 393 continue; 394 cur.dk_select[i] = 1; 395 ++ndrives; 396 } 397 } 398 #ifdef BACKWARD_COMPATIBILITY 399 if (*argv) { 400 interval = atoi(*argv); 401 if (*++argv) 402 reps = atoi(*argv); 403 } 404 #endif 405 406 if (interval) { 407 if (!reps) 408 reps = -1; 409 } else 410 if (reps) 411 interval = 1; 412 413 /* Pick up to 4 drives if none specified. */ 414 if (ndrives == 0) 415 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 416 if (cur.dk_select[i]) 417 continue; 418 cur.dk_select[i] = 1; 419 ++ndrives; 420 } 421 } 422