1 /*- 2 * Copyright (c) 1986, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 char copyright[] = 36 "@(#) Copyright (c) 1986, 1991 The Regents of the University of California.\n\ 37 All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 static char sccsid[] = "@(#)iostat.c 5.9 (Berkeley) 6/27/91"; 42 #endif /* not lint */ 43 44 #include <sys/param.h> 45 #include <sys/buf.h> 46 #include <sys/dkstat.h> 47 #include <signal.h> 48 #include <fcntl.h> 49 #include <nlist.h> 50 #include <unistd.h> 51 #include <stdio.h> 52 #include <ctype.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <paths.h> 56 #include <kvm.h> 57 58 struct nlist nl[] = { 59 #define X_DK_TIME 0 60 { "_dk_time" }, 61 #define X_DK_XFER 1 62 { "_dk_xfer" }, 63 #define X_DK_WDS 2 64 { "_dk_wds" }, 65 #define X_TK_NIN 3 66 { "_tk_nin" }, 67 #define X_TK_NOUT 4 68 { "_tk_nout" }, 69 #define X_DK_SEEK 5 70 { "_dk_seek" }, 71 #define X_CP_TIME 6 72 { "_cp_time" }, 73 #define X_DK_WPMS 7 74 { "_dk_wpms" }, 75 #define X_HZ 8 76 { "_hz" }, 77 #define X_PHZ 9 78 { "_phz" }, 79 #define X_DK_NDRIVE 10 80 { "_dk_ndrive" }, 81 #define X_END 10 82 #ifdef hp300 83 #define X_HPDINIT (X_END+1) 84 { "_hp_dinit" }, 85 #endif 86 #ifdef tahoe 87 #define X_VBDINIT (X_END+1) 88 { "_vbdinit" }, 89 #endif 90 #ifdef vax 91 { "_mbdinit" }, 92 #define X_MBDINIT (X_END+1) 93 { "_ubdinit" }, 94 #define X_UBDINIT (X_END+2) 95 #endif 96 #ifdef __386BSD__ 97 #define X_ISA_BIO (X_END+1) 98 { "_isa_subdev" }, 99 #endif /* __386BSD__ */ 100 { NULL }, 101 }; 102 103 struct _disk { 104 long cp_time[CPUSTATES]; 105 long *dk_time; 106 long *dk_wds; 107 long *dk_seek; 108 long *dk_xfer; 109 long tk_nin; 110 long tk_nout; 111 } cur, last; 112 113 double etime; 114 long *dk_wpms; 115 int dk_ndrive, *dr_select, hz, kmemfd, ndrives; 116 char **dr_name; 117 118 #define nlread(x, v) \ 119 kvm_read((void *)nl[x].n_value, (void *)&(v), sizeof(v)) 120 121 #include "names.c" /* XXX */ 122 123 static void cpustats __P((void)), dkstats __P((void)), phdr __P((int)); 124 static void usage __P((void)), err __P((const char *, ...)); 125 126 main(argc, argv) 127 int argc; 128 char **argv; 129 { 130 register int i; 131 long tmp; 132 int ch, hdrcnt, reps, interval, phz, ndrives; 133 char **cp, *memfile, *namelist, buf[30]; 134 135 interval = reps = 0; 136 namelist = memfile = NULL; 137 while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF) 138 switch(ch) { 139 case 'c': 140 reps = atoi(optarg); 141 break; 142 case 'M': 143 memfile = optarg; 144 break; 145 case 'N': 146 namelist = optarg; 147 break; 148 case 'w': 149 interval = atoi(optarg); 150 break; 151 case '?': 152 default: 153 usage(); 154 } 155 argc -= optind; 156 argv += optind; 157 158 if (kvm_openfiles(namelist, memfile, NULL) == -1) 159 err("kvm_openfiles: %s", kvm_geterr()); 160 if (kvm_nlist(nl) == -1) 161 err("kvm_nlist: %s", kvm_geterr()); 162 if (nl[X_DK_NDRIVE].n_type == 0) 163 err("dk_ndrive not found in namelist"); 164 (void)nlread(X_DK_NDRIVE, dk_ndrive); 165 if (dk_ndrive <= 0) 166 err("invalid dk_ndrive %d\n", dk_ndrive); 167 168 cur.dk_time = calloc(dk_ndrive, sizeof(long)); 169 cur.dk_wds = calloc(dk_ndrive, sizeof(long)); 170 cur.dk_seek = calloc(dk_ndrive, sizeof(long)); 171 cur.dk_xfer = calloc(dk_ndrive, sizeof(long)); 172 last.dk_time = calloc(dk_ndrive, sizeof(long)); 173 last.dk_wds = calloc(dk_ndrive, sizeof(long)); 174 last.dk_seek = calloc(dk_ndrive, sizeof(long)); 175 last.dk_xfer = calloc(dk_ndrive, sizeof(long)); 176 dr_select = calloc(dk_ndrive, sizeof(int)); 177 dr_name = calloc(dk_ndrive, sizeof(char *)); 178 dk_wpms = calloc(dk_ndrive, sizeof(long)); 179 180 for (i = 0; i < dk_ndrive; i++) { 181 (void)sprintf(buf, "dk%d", i); 182 dr_name[i] = strdup(buf); 183 } 184 read_names(); 185 (void)nlread(X_HZ, hz); 186 (void)nlread(X_PHZ, phz); 187 if (phz) 188 hz = phz; 189 (void)kvm_read((void *)nl[X_DK_WPMS].n_value, dk_wpms, 190 dk_ndrive * sizeof(dk_wpms)); 191 192 /* 193 * Choose drives to be displayed. Priority goes to (in order) drives 194 * supplied as arguments and default drives. If everything isn't 195 * filled in and there are drives not taken care of, display the first 196 * few that fit. 197 * 198 * The backward compatibility #ifdefs permit the syntax: 199 * iostat [ drives ] [ interval [ count ] ] 200 */ 201 #define BACKWARD_COMPATIBILITY 202 for (ndrives = 0; *argv; ++argv) { 203 #ifdef BACKWARD_COMPATIBILITY 204 if (isdigit(**argv)) 205 break; 206 #endif 207 for (i = 0; i < dk_ndrive; i++) { 208 if (strcmp(dr_name[i], *argv)) 209 continue; 210 dr_select[i] = 1; 211 ++ndrives; 212 } 213 } 214 #ifdef BACKWARD_COMPATIBILITY 215 if (*argv) { 216 interval = atoi(*argv); 217 if (*++argv) 218 reps = atoi(*argv); 219 } 220 #endif 221 222 if (interval) { 223 if (!reps) 224 reps = -1; 225 } else 226 if (reps) 227 interval = 1; 228 229 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 230 if (dr_select[i] || dk_wpms[i] == 0) 231 continue; 232 for (cp = defdrives; *cp; cp++) 233 if (strcmp(dr_name[i], *cp) == 0) { 234 dr_select[i] = 1; 235 ++ndrives; 236 break; 237 } 238 } 239 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 240 if (dr_select[i]) 241 continue; 242 dr_select[i] = 1; 243 ++ndrives; 244 } 245 246 (void)signal(SIGCONT, phdr); 247 248 for (hdrcnt = 1;;) { 249 if (!--hdrcnt) { 250 phdr(0); 251 hdrcnt = 20; 252 } 253 (void)kvm_read((void *)nl[X_DK_TIME].n_value, 254 cur.dk_time, dk_ndrive * sizeof(long)); 255 (void)kvm_read((void *)nl[X_DK_XFER].n_value, 256 cur.dk_xfer, dk_ndrive * sizeof(long)); 257 (void)kvm_read((void *)nl[X_DK_WDS].n_value, 258 cur.dk_wds, dk_ndrive * sizeof(long)); 259 (void)kvm_read((void *)nl[X_DK_SEEK].n_value, 260 cur.dk_seek, dk_ndrive * sizeof(long)); 261 (void)kvm_read((void *)nl[X_TK_NIN].n_value, 262 &cur.tk_nin, sizeof(cur.tk_nin)); 263 (void)kvm_read((void *)nl[X_TK_NOUT].n_value, 264 &cur.tk_nout, sizeof(cur.tk_nout)); 265 (void)kvm_read((void *)nl[X_CP_TIME].n_value, 266 cur.cp_time, sizeof(cur.cp_time)); 267 for (i = 0; i < dk_ndrive; i++) { 268 if (!dr_select[i]) 269 continue; 270 #define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp 271 X(dk_xfer); 272 X(dk_seek); 273 X(dk_wds); 274 X(dk_time); 275 } 276 tmp = cur.tk_nin; 277 cur.tk_nin -= last.tk_nin; 278 last.tk_nin = tmp; 279 tmp = cur.tk_nout; 280 cur.tk_nout -= last.tk_nout; 281 last.tk_nout = tmp; 282 etime = 0; 283 for (i = 0; i < CPUSTATES; i++) { 284 X(cp_time); 285 etime += cur.cp_time[i]; 286 } 287 if (etime == 0.0) 288 etime = 1.0; 289 etime /= (float)hz; 290 (void)printf("%4.0f%5.0f", 291 cur.tk_nin / etime, cur.tk_nout / etime); 292 dkstats(); 293 cpustats(); 294 (void)printf("\n"); 295 (void)fflush(stdout); 296 297 if (reps >= 0 && --reps <= 0) 298 break; 299 (void)sleep(interval); 300 } 301 exit(0); 302 } 303 304 /* ARGUSED */ 305 void 306 phdr(notused) 307 int notused; 308 { 309 register int i; 310 311 (void)printf(" tty"); 312 for (i = 0; i < dk_ndrive; i++) 313 if (dr_select[i]) 314 (void)printf(" %5.5s ", dr_name[i]); 315 (void)printf(" cpu\n tin tout"); 316 for (i = 0; i < dk_ndrive; i++) 317 if (dr_select[i]) 318 (void)printf(" sps tps msps "); 319 (void)printf(" us ni sy id\n"); 320 } 321 322 void 323 dkstats() 324 { 325 register int dn; 326 double atime, itime, msps, words, xtime; 327 328 for (dn = 0; dn < dk_ndrive; ++dn) { 329 if (!dr_select[dn]) 330 continue; 331 words = cur.dk_wds[dn] * 32; /* words xfer'd */ 332 (void)printf("%4.0f", /* sectors */ 333 words / (DEV_BSIZE / 2) / etime); 334 335 (void)printf("%4.0f", cur.dk_xfer[dn] / etime); 336 337 if (dk_wpms[dn] && cur.dk_xfer[dn]) { 338 atime = cur.dk_time[dn]; /* ticks disk busy */ 339 atime /= (float)hz; /* ticks to seconds */ 340 xtime = words / dk_wpms[dn]; /* transfer time */ 341 itime = atime - xtime; /* time not xfer'ing */ 342 if (itime < 0) 343 msps = 0; 344 else 345 msps = itime * 1000 / cur.dk_xfer[dn]; 346 } else 347 msps = 0; 348 (void)printf("%5.1f ", msps); 349 } 350 } 351 352 void 353 cpustats() 354 { 355 register int state; 356 double time; 357 358 time = 0; 359 for (state = 0; state < CPUSTATES; ++state) 360 time += cur.cp_time[state]; 361 for (state = 0; state < CPUSTATES; ++state) 362 (void)printf("%3.0f", 363 100. * cur.cp_time[state] / (time ? time : 1)); 364 } 365 366 void 367 usage() 368 { 369 (void)fprintf(stderr, 370 "usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n"); 371 exit(1); 372 } 373 374 #if __STDC__ 375 #include <stdarg.h> 376 #else 377 #include <varargs.h> 378 #endif 379 380 void 381 #if __STDC__ 382 err(const char *fmt, ...) 383 #else 384 err(fmt, va_alist) 385 char *fmt; 386 va_dcl 387 #endif 388 { 389 va_list ap; 390 #if __STDC__ 391 va_start(ap, fmt); 392 #else 393 va_start(ap); 394 #endif 395 (void)fprintf(stderr, "iostat: "); 396 (void)vfprintf(stderr, fmt, ap); 397 va_end(ap); 398 (void)fprintf(stderr, "\n"); 399 exit(1); 400 /* NOTREACHED */ 401 } 402