1 /*- 2 * Copyright (c) 1986, 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1986, 1991 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)iostat.c 5.9 (Berkeley) 06/27/91"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/buf.h> 20 #include <sys/dkstat.h> 21 #include <signal.h> 22 #include <fcntl.h> 23 #include <nlist.h> 24 #include <unistd.h> 25 #include <stdio.h> 26 #include <ctype.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <paths.h> 30 #include <kvm.h> 31 32 struct nlist nl[] = { 33 #define X_DK_TIME 0 34 { "_dk_time" }, 35 #define X_DK_XFER 1 36 { "_dk_xfer" }, 37 #define X_DK_WDS 2 38 { "_dk_wds" }, 39 #define X_TK_NIN 3 40 { "_tk_nin" }, 41 #define X_TK_NOUT 4 42 { "_tk_nout" }, 43 #define X_DK_SEEK 5 44 { "_dk_seek" }, 45 #define X_CP_TIME 6 46 { "_cp_time" }, 47 #define X_DK_WPMS 7 48 { "_dk_wpms" }, 49 #define X_HZ 8 50 { "_hz" }, 51 #define X_PHZ 9 52 { "_phz" }, 53 #define X_DK_NDRIVE 10 54 { "_dk_ndrive" }, 55 #define X_END 11 56 #ifdef hp300 57 #define X_HPDINIT (X_END+1) 58 { "_hp_dinit" }, 59 #endif 60 #ifdef tahoe 61 #define X_VBDINIT (X_END+1) 62 { "_vbdinit" }, 63 #endif 64 #ifdef vax 65 { "_mbdinit" }, 66 #define X_MBDINIT (X_END+1) 67 { "_ubdinit" }, 68 #define X_UBDINIT (X_END+2) 69 #endif 70 { NULL }, 71 }; 72 73 struct _disk { 74 long cp_time[CPUSTATES]; 75 long *dk_time; 76 long *dk_wds; 77 long *dk_seek; 78 long *dk_xfer; 79 long tk_nin; 80 long tk_nout; 81 } cur, last; 82 83 double etime; 84 long *dk_wpms; 85 int dk_ndrive, *dr_select, hz, kmemfd, ndrives; 86 char **dr_name; 87 88 #define nlread(x, v) \ 89 kvm_read((void *)nl[x].n_value, (void *)&(v), sizeof(v)) 90 91 #include "names.c" /* XXX */ 92 93 static void cpustats __P((void)), dkstats __P((void)), phdr __P((int)); 94 static void usage __P((void)), err __P((const char *, ...)); 95 96 main(argc, argv) 97 int argc; 98 char **argv; 99 { 100 register int i; 101 long tmp; 102 int ch, hdrcnt, reps, interval, phz, ndrives; 103 char **cp, *memfile, *namelist, buf[30]; 104 105 interval = reps = 0; 106 namelist = memfile = NULL; 107 while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF) 108 switch(ch) { 109 case 'c': 110 reps = atoi(optarg); 111 break; 112 case 'M': 113 memfile = optarg; 114 break; 115 case 'N': 116 namelist = optarg; 117 break; 118 case 'w': 119 interval = atoi(optarg); 120 break; 121 case '?': 122 default: 123 usage(); 124 } 125 argc -= optind; 126 argv += optind; 127 128 if (kvm_openfiles(namelist, memfile, NULL) == -1) 129 err("kvm_openfiles: %s", kvm_geterr()); 130 if (kvm_nlist(nl) == -1) 131 err("kvm_nlist: %s", kvm_geterr()); 132 if (nl[X_DK_NDRIVE].n_type == 0) 133 err("dk_ndrive not found in namelist"); 134 (void)nlread(X_DK_NDRIVE, dk_ndrive); 135 if (dk_ndrive <= 0) 136 err("invalid dk_ndrive %d\n", dk_ndrive); 137 138 cur.dk_time = calloc(dk_ndrive, sizeof(long)); 139 cur.dk_wds = calloc(dk_ndrive, sizeof(long)); 140 cur.dk_seek = calloc(dk_ndrive, sizeof(long)); 141 cur.dk_xfer = calloc(dk_ndrive, sizeof(long)); 142 last.dk_time = calloc(dk_ndrive, sizeof(long)); 143 last.dk_wds = calloc(dk_ndrive, sizeof(long)); 144 last.dk_seek = calloc(dk_ndrive, sizeof(long)); 145 last.dk_xfer = calloc(dk_ndrive, sizeof(long)); 146 dr_select = calloc(dk_ndrive, sizeof(int)); 147 dr_name = calloc(dk_ndrive, sizeof(char *)); 148 dk_wpms = calloc(dk_ndrive, sizeof(long)); 149 150 for (i = 0; i < dk_ndrive; i++) { 151 (void)sprintf(buf, "dk%d", i); 152 dr_name[i] = strdup(buf); 153 } 154 read_names(); 155 (void)nlread(X_HZ, hz); 156 (void)nlread(X_PHZ, phz); 157 if (phz) 158 hz = phz; 159 (void)kvm_read((void *)nl[X_DK_WPMS].n_value, dk_wpms, 160 dk_ndrive * sizeof(dk_wpms)); 161 162 /* 163 * Choose drives to be displayed. Priority goes to (in order) drives 164 * supplied as arguments and default drives. If everything isn't 165 * filled in and there are drives not taken care of, display the first 166 * few that fit. 167 * 168 * The backward compatibility #ifdefs permit the syntax: 169 * iostat [ drives ] [ interval [ count ] ] 170 */ 171 #define BACKWARD_COMPATIBILITY 172 for (ndrives = 0; *argv; ++argv) { 173 #ifdef BACKWARD_COMPATIBILITY 174 if (isdigit(**argv)) 175 break; 176 #endif 177 for (i = 0; i < dk_ndrive; i++) { 178 if (strcmp(dr_name[i], *argv)) 179 continue; 180 dr_select[i] = 1; 181 ++ndrives; 182 } 183 } 184 #ifdef BACKWARD_COMPATIBILITY 185 if (*argv) { 186 interval = atoi(*argv); 187 if (*++argv) 188 reps = atoi(*argv); 189 } 190 #endif 191 192 if (interval) { 193 if (!reps) 194 reps = -1; 195 } else 196 if (reps) 197 interval = 1; 198 199 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 200 if (dr_select[i] || dk_wpms[i] == 0) 201 continue; 202 for (cp = defdrives; *cp; cp++) 203 if (strcmp(dr_name[i], *cp) == 0) { 204 dr_select[i] = 1; 205 ++ndrives; 206 break; 207 } 208 } 209 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 210 if (dr_select[i]) 211 continue; 212 dr_select[i] = 1; 213 ++ndrives; 214 } 215 216 (void)signal(SIGCONT, phdr); 217 218 for (hdrcnt = 1;;) { 219 if (!--hdrcnt) { 220 phdr(0); 221 hdrcnt = 20; 222 } 223 (void)kvm_read((void *)nl[X_DK_TIME].n_value, 224 cur.dk_time, dk_ndrive * sizeof(long)); 225 (void)kvm_read((void *)nl[X_DK_XFER].n_value, 226 cur.dk_xfer, dk_ndrive * sizeof(long)); 227 (void)kvm_read((void *)nl[X_DK_WDS].n_value, 228 cur.dk_wds, dk_ndrive * sizeof(long)); 229 (void)kvm_read((void *)nl[X_DK_SEEK].n_value, 230 cur.dk_seek, dk_ndrive * sizeof(long)); 231 (void)kvm_read((void *)nl[X_TK_NIN].n_value, 232 &cur.tk_nin, sizeof(cur.tk_nin)); 233 (void)kvm_read((void *)nl[X_TK_NOUT].n_value, 234 &cur.tk_nout, sizeof(cur.tk_nout)); 235 (void)kvm_read((void *)nl[X_CP_TIME].n_value, 236 cur.cp_time, sizeof(cur.cp_time)); 237 for (i = 0; i < dk_ndrive; i++) { 238 if (!dr_select[i]) 239 continue; 240 #define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp 241 X(dk_xfer); 242 X(dk_seek); 243 X(dk_wds); 244 X(dk_time); 245 } 246 tmp = cur.tk_nin; 247 cur.tk_nin -= last.tk_nin; 248 last.tk_nin = tmp; 249 tmp = cur.tk_nout; 250 cur.tk_nout -= last.tk_nout; 251 last.tk_nout = tmp; 252 etime = 0; 253 for (i = 0; i < CPUSTATES; i++) { 254 X(cp_time); 255 etime += cur.cp_time[i]; 256 } 257 if (etime == 0.0) 258 etime = 1.0; 259 etime /= (float)hz; 260 (void)printf("%4.0f%5.0f", 261 cur.tk_nin / etime, cur.tk_nout / etime); 262 dkstats(); 263 cpustats(); 264 (void)printf("\n"); 265 (void)fflush(stdout); 266 267 if (reps >= 0 && --reps <= 0) 268 break; 269 (void)sleep(interval); 270 } 271 exit(0); 272 } 273 274 /* ARGUSED */ 275 void 276 phdr(notused) 277 int notused; 278 { 279 register int i; 280 281 (void)printf(" tty"); 282 for (i = 0; i < dk_ndrive; i++) 283 if (dr_select[i]) 284 (void)printf(" %3.3s ", dr_name[i]); 285 (void)printf(" cpu\n tin tout"); 286 for (i = 0; i < dk_ndrive; i++) 287 if (dr_select[i]) 288 (void)printf(" sps tps msps "); 289 (void)printf(" us ni sy id\n"); 290 } 291 292 void 293 dkstats() 294 { 295 register int dn; 296 double atime, itime, msps, words, xtime; 297 298 for (dn = 0; dn < dk_ndrive; ++dn) { 299 if (!dr_select[dn]) 300 continue; 301 words = cur.dk_wds[dn] * 32; /* words xfer'd */ 302 (void)printf("%4.0f", /* sectors */ 303 words / (DEV_BSIZE / 2) / etime); 304 305 (void)printf("%4.0f", cur.dk_xfer[dn] / etime); 306 307 if (dk_wpms[dn] && cur.dk_xfer[dn]) { 308 atime = cur.dk_time[dn]; /* ticks disk busy */ 309 atime /= (float)hz; /* ticks to seconds */ 310 xtime = words / dk_wpms[dn]; /* transfer time */ 311 itime = atime - xtime; /* time not xfer'ing */ 312 if (itime < 0) 313 msps = 0; 314 else 315 msps = itime * 1000 / cur.dk_xfer[dn]; 316 } else 317 msps = 0; 318 (void)printf("%5.1f ", msps); 319 } 320 } 321 322 void 323 cpustats() 324 { 325 register int state; 326 double time; 327 328 time = 0; 329 for (state = 0; state < CPUSTATES; ++state) 330 time += cur.cp_time[state]; 331 for (state = 0; state < CPUSTATES; ++state) 332 (void)printf("%3.0f", 333 100. * cur.cp_time[state] / (time ? time : 1)); 334 } 335 336 void 337 usage() 338 { 339 (void)fprintf(stderr, 340 "usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n"); 341 exit(1); 342 } 343 344 #if __STDC__ 345 #include <stdarg.h> 346 #else 347 #include <varargs.h> 348 #endif 349 350 void 351 #if __STDC__ 352 err(const char *fmt, ...) 353 #else 354 err(fmt, va_alist) 355 char *fmt; 356 va_dcl 357 #endif 358 { 359 va_list ap; 360 #if __STDC__ 361 va_start(ap, fmt); 362 #else 363 va_start(ap); 364 #endif 365 (void)fprintf(stderr, "iostat: "); 366 (void)vfprintf(stderr, fmt, ap); 367 va_end(ap); 368 (void)fprintf(stderr, "\n"); 369 exit(1); 370 /* NOTREACHED */ 371 } 372