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.11 (Berkeley) 11/13/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 10 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 void cpustats __P((void)); 94 void dkstats __P((void)); 95 void err __P((const char *, ...)); 96 void phdr __P((int)); 97 void usage __P((void)); 98 99 main(argc, argv) 100 int argc; 101 char **argv; 102 { 103 register int i; 104 long tmp; 105 int ch, hdrcnt, reps, interval, phz, ndrives; 106 char **cp, *memfile, *namelist, buf[30]; 107 108 interval = reps = 0; 109 namelist = memfile = NULL; 110 while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF) 111 switch(ch) { 112 case 'c': 113 reps = atoi(optarg); 114 break; 115 case 'M': 116 memfile = optarg; 117 break; 118 case 'N': 119 namelist = optarg; 120 break; 121 case 'w': 122 interval = atoi(optarg); 123 break; 124 case '?': 125 default: 126 usage(); 127 } 128 argc -= optind; 129 argv += optind; 130 131 if (kvm_openfiles(namelist, memfile, NULL) == -1) 132 err("kvm_openfiles: %s", kvm_geterr()); 133 if (kvm_nlist(nl) == -1) 134 err("kvm_nlist: %s", kvm_geterr()); 135 if (nl[X_DK_NDRIVE].n_type == 0) 136 err("dk_ndrive not found in namelist"); 137 (void)nlread(X_DK_NDRIVE, dk_ndrive); 138 if (dk_ndrive <= 0) 139 err("invalid dk_ndrive %d\n", dk_ndrive); 140 141 cur.dk_time = calloc(dk_ndrive, sizeof(long)); 142 cur.dk_wds = calloc(dk_ndrive, sizeof(long)); 143 cur.dk_seek = calloc(dk_ndrive, sizeof(long)); 144 cur.dk_xfer = calloc(dk_ndrive, sizeof(long)); 145 last.dk_time = calloc(dk_ndrive, sizeof(long)); 146 last.dk_wds = calloc(dk_ndrive, sizeof(long)); 147 last.dk_seek = calloc(dk_ndrive, sizeof(long)); 148 last.dk_xfer = calloc(dk_ndrive, sizeof(long)); 149 dr_select = calloc(dk_ndrive, sizeof(int)); 150 dr_name = calloc(dk_ndrive, sizeof(char *)); 151 dk_wpms = calloc(dk_ndrive, sizeof(long)); 152 153 for (i = 0; i < dk_ndrive; i++) { 154 (void)sprintf(buf, "dk%d", i); 155 dr_name[i] = strdup(buf); 156 } 157 read_names(); 158 (void)nlread(X_HZ, hz); 159 (void)nlread(X_PHZ, phz); 160 if (phz) 161 hz = phz; 162 (void)kvm_read((void *)nl[X_DK_WPMS].n_value, dk_wpms, 163 dk_ndrive * sizeof(dk_wpms)); 164 165 /* 166 * Choose drives to be displayed. Priority goes to (in order) drives 167 * supplied as arguments and default drives. If everything isn't 168 * filled in and there are drives not taken care of, display the first 169 * few that fit. 170 * 171 * The backward compatibility #ifdefs permit the syntax: 172 * iostat [ drives ] [ interval [ count ] ] 173 */ 174 #define BACKWARD_COMPATIBILITY 175 for (ndrives = 0; *argv; ++argv) { 176 #ifdef BACKWARD_COMPATIBILITY 177 if (isdigit(**argv)) 178 break; 179 #endif 180 for (i = 0; i < dk_ndrive; i++) { 181 if (strcmp(dr_name[i], *argv)) 182 continue; 183 dr_select[i] = 1; 184 ++ndrives; 185 } 186 } 187 #ifdef BACKWARD_COMPATIBILITY 188 if (*argv) { 189 interval = atoi(*argv); 190 if (*++argv) 191 reps = atoi(*argv); 192 } 193 #endif 194 195 if (interval) { 196 if (!reps) 197 reps = -1; 198 } else 199 if (reps) 200 interval = 1; 201 202 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 203 if (dr_select[i] || dk_wpms[i] == 0) 204 continue; 205 for (cp = defdrives; *cp; cp++) 206 if (strcmp(dr_name[i], *cp) == 0) { 207 dr_select[i] = 1; 208 ++ndrives; 209 break; 210 } 211 } 212 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 213 if (dr_select[i]) 214 continue; 215 dr_select[i] = 1; 216 ++ndrives; 217 } 218 219 (void)signal(SIGCONT, phdr); 220 221 for (hdrcnt = 1;;) { 222 if (!--hdrcnt) { 223 phdr(0); 224 hdrcnt = 20; 225 } 226 (void)kvm_read((void *)nl[X_DK_TIME].n_value, 227 cur.dk_time, dk_ndrive * sizeof(long)); 228 (void)kvm_read((void *)nl[X_DK_XFER].n_value, 229 cur.dk_xfer, dk_ndrive * sizeof(long)); 230 (void)kvm_read((void *)nl[X_DK_WDS].n_value, 231 cur.dk_wds, dk_ndrive * sizeof(long)); 232 (void)kvm_read((void *)nl[X_DK_SEEK].n_value, 233 cur.dk_seek, dk_ndrive * sizeof(long)); 234 (void)kvm_read((void *)nl[X_TK_NIN].n_value, 235 &cur.tk_nin, sizeof(cur.tk_nin)); 236 (void)kvm_read((void *)nl[X_TK_NOUT].n_value, 237 &cur.tk_nout, sizeof(cur.tk_nout)); 238 (void)kvm_read((void *)nl[X_CP_TIME].n_value, 239 cur.cp_time, sizeof(cur.cp_time)); 240 for (i = 0; i < dk_ndrive; i++) { 241 if (!dr_select[i]) 242 continue; 243 #define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp 244 X(dk_xfer); 245 X(dk_seek); 246 X(dk_wds); 247 X(dk_time); 248 } 249 tmp = cur.tk_nin; 250 cur.tk_nin -= last.tk_nin; 251 last.tk_nin = tmp; 252 tmp = cur.tk_nout; 253 cur.tk_nout -= last.tk_nout; 254 last.tk_nout = tmp; 255 etime = 0; 256 for (i = 0; i < CPUSTATES; i++) { 257 X(cp_time); 258 etime += cur.cp_time[i]; 259 } 260 if (etime == 0.0) 261 etime = 1.0; 262 etime /= (float)hz; 263 (void)printf("%4.0f%5.0f", 264 cur.tk_nin / etime, cur.tk_nout / etime); 265 dkstats(); 266 cpustats(); 267 (void)printf("\n"); 268 (void)fflush(stdout); 269 270 if (reps >= 0 && --reps <= 0) 271 break; 272 (void)sleep(interval); 273 } 274 exit(0); 275 } 276 277 /* ARGUSED */ 278 void 279 phdr(notused) 280 int notused; 281 { 282 register int i; 283 284 (void)printf(" tty"); 285 for (i = 0; i < dk_ndrive; i++) 286 if (dr_select[i]) 287 (void)printf(" %3.3s ", dr_name[i]); 288 (void)printf(" cpu\n tin tout"); 289 for (i = 0; i < dk_ndrive; i++) 290 if (dr_select[i]) 291 (void)printf(" sps tps msps "); 292 (void)printf(" us ni sy id\n"); 293 } 294 295 void 296 dkstats() 297 { 298 register int dn; 299 double atime, itime, msps, words, xtime; 300 301 for (dn = 0; dn < dk_ndrive; ++dn) { 302 if (!dr_select[dn]) 303 continue; 304 words = cur.dk_wds[dn] * 32; /* words xfer'd */ 305 (void)printf("%4.0f", /* sectors */ 306 words / (DEV_BSIZE / 2) / etime); 307 308 (void)printf("%4.0f", cur.dk_xfer[dn] / etime); 309 310 if (dk_wpms[dn] && cur.dk_xfer[dn]) { 311 atime = cur.dk_time[dn]; /* ticks disk busy */ 312 atime /= (float)hz; /* ticks to seconds */ 313 xtime = words / dk_wpms[dn]; /* transfer time */ 314 itime = atime - xtime; /* time not xfer'ing */ 315 if (itime < 0) 316 msps = 0; 317 else 318 msps = itime * 1000 / cur.dk_xfer[dn]; 319 } else 320 msps = 0; 321 (void)printf("%5.1f ", msps); 322 } 323 } 324 325 void 326 cpustats() 327 { 328 register int state; 329 double time; 330 331 time = 0; 332 for (state = 0; state < CPUSTATES; ++state) 333 time += cur.cp_time[state]; 334 for (state = 0; state < CPUSTATES; ++state) 335 (void)printf("%3.0f", 336 100. * cur.cp_time[state] / (time ? time : 1)); 337 } 338 339 void 340 usage() 341 { 342 (void)fprintf(stderr, 343 "usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n"); 344 exit(1); 345 } 346 347 #if __STDC__ 348 #include <stdarg.h> 349 #else 350 #include <varargs.h> 351 #endif 352 353 void 354 #if __STDC__ 355 err(const char *fmt, ...) 356 #else 357 err(fmt, va_alist) 358 char *fmt; 359 va_dcl 360 #endif 361 { 362 va_list ap; 363 #if __STDC__ 364 va_start(ap, fmt); 365 #else 366 va_start(ap); 367 #endif 368 (void)fprintf(stderr, "iostat: "); 369 (void)vfprintf(stderr, fmt, ap); 370 va_end(ap); 371 (void)fprintf(stderr, "\n"); 372 exit(1); 373 /* NOTREACHED */ 374 } 375