1 #ifndef lint 2 static char *sccsid = "@(#)iostat.c 4.17 (Berkeley) 89/05/29"; 3 #endif 4 5 /* 6 * iostat 7 */ 8 #include <sys/types.h> 9 #include <sys/file.h> 10 #include <sys/buf.h> 11 #include <sys/dkstat.h> 12 #include <sys/signal.h> 13 #include <stdio.h> 14 #include <ctype.h> 15 #include <nlist.h> 16 #include <paths.h> 17 18 struct nlist nl[] = { 19 { "_dk_busy" }, 20 #define X_DK_BUSY 0 21 { "_dk_time" }, 22 #define X_DK_TIME 1 23 { "_dk_xfer" }, 24 #define X_DK_XFER 2 25 { "_dk_wds" }, 26 #define X_DK_WDS 3 27 { "_tk_nin" }, 28 #define X_TK_NIN 4 29 { "_tk_nout" }, 30 #define X_TK_NOUT 5 31 { "_dk_seek" }, 32 #define X_DK_SEEK 6 33 { "_cp_time" }, 34 #define X_CP_TIME 7 35 { "_dk_wpms" }, 36 #define X_DK_WPMS 8 37 { "_hz" }, 38 #define X_HZ 9 39 { "_phz" }, 40 #define X_PHZ 10 41 { "_dk_ndrive" }, 42 #define X_DK_NDRIVE 11 43 #ifdef vax 44 { "_mbdinit" }, 45 #define X_MBDINIT (X_DK_NDRIVE+1) 46 { "_ubdinit" }, 47 #define X_UBDINIT (X_DK_NDRIVE+2) 48 #endif 49 #ifdef tahoe 50 #define X_VBDINIT (X_DK_NDRIVE+1) 51 { "_vbdinit" }, 52 #endif 53 { 0 }, 54 }; 55 56 char **dr_name; 57 int *dr_select; 58 long *dk_wpms; 59 int dk_ndrive; 60 int ndrives = 0; 61 #ifdef vax 62 char *defdrives[] = { "hp0", "hp1", "hp2", 0 }; 63 #else 64 char *defdrives[] = { 0 }; 65 #endif 66 67 struct { 68 int dk_busy; 69 long cp_time[CPUSTATES]; 70 long *dk_time; 71 long *dk_wds; 72 long *dk_seek; 73 long *dk_xfer; 74 long tk_nin; 75 long tk_nout; 76 } s, s1; 77 78 int mf; 79 int hz; 80 int phz; 81 double etime; 82 int tohdr = 1; 83 int printhdr(); 84 85 main(argc, argv) 86 char *argv[]; 87 { 88 extern char *ctime(); 89 register i; 90 int iter, ndrives; 91 double f1, f2; 92 long t; 93 char *arg, **cp, name[6], buf[BUFSIZ]; 94 95 nlist(_PATH_UNIX, nl); 96 if(nl[X_DK_BUSY].n_type == 0) { 97 fprintf(stderr, "iostat: dk_busy not found in %s namelist\n", 98 _PATH_UNIX); 99 exit(1); 100 } 101 mf = open(_PATH_KMEM, 0); 102 if(mf < 0) { 103 fprintf(stderr, "iostat: cannot open %s\n", _PATH_KMEM); 104 exit(1); 105 } 106 iter = 0; 107 for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) 108 ; 109 if (nl[X_DK_NDRIVE].n_value == 0) { 110 printf("dk_ndrive undefined in system\n"); 111 exit(1); 112 } 113 lseek(mf, nl[X_DK_NDRIVE].n_value, L_SET); 114 read(mf, &dk_ndrive, sizeof (dk_ndrive)); 115 if (dk_ndrive <= 0) { 116 printf("dk_ndrive %d\n", dk_ndrive); 117 exit(1); 118 } 119 dr_select = (int *)calloc(dk_ndrive, sizeof (int)); 120 dr_name = (char **)calloc(dk_ndrive, sizeof (char *)); 121 dk_wpms = (long *)calloc(dk_ndrive, sizeof (long)); 122 #define allocate(e, t) \ 123 s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \ 124 s1./**/e = (t *)calloc(dk_ndrive, sizeof (t)); 125 allocate(dk_time, long); 126 allocate(dk_wds, long); 127 allocate(dk_seek, long); 128 allocate(dk_xfer, long); 129 for (arg = buf, i = 0; i < dk_ndrive; i++) { 130 dr_name[i] = arg; 131 sprintf(dr_name[i], "dk%d", i); 132 arg += strlen(dr_name[i]) + 1; 133 } 134 read_names(); 135 lseek(mf, (long)nl[X_HZ].n_value, L_SET); 136 read(mf, &hz, sizeof hz); 137 lseek(mf, (long)nl[X_PHZ].n_value, L_SET); 138 read(mf, &phz, sizeof phz); 139 if (phz) 140 hz = phz; 141 lseek(mf, (long)nl[X_DK_WPMS].n_value, L_SET); 142 read(mf, dk_wpms, dk_ndrive*sizeof (dk_wpms)); 143 /* 144 * Choose drives to be displayed. Priority 145 * goes to (in order) drives supplied as arguments, 146 * default drives. If everything isn't filled 147 * in and there are drives not taken care of, 148 * display the first few that fit. 149 */ 150 ndrives = 0; 151 while (argc > 0 && !isdigit(argv[0][0])) { 152 for (i = 0; i < dk_ndrive; i++) { 153 if (strcmp(dr_name[i], argv[0])) 154 continue; 155 dr_select[i] = 1; 156 ndrives++; 157 } 158 argc--, argv++; 159 } 160 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 161 if (dr_select[i] || dk_wpms[i] == 0) 162 continue; 163 for (cp = defdrives; *cp; cp++) 164 if (strcmp(dr_name[i], *cp) == 0) { 165 dr_select[i] = 1; 166 ndrives++; 167 break; 168 } 169 } 170 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 171 if (dr_select[i]) 172 continue; 173 dr_select[i] = 1; 174 ndrives++; 175 } 176 if (argc > 1) 177 iter = atoi(argv[1]); 178 signal(SIGCONT, printhdr); 179 loop: 180 if (--tohdr == 0) 181 printhdr(); 182 lseek(mf, (long)nl[X_DK_BUSY].n_value, L_SET); 183 read(mf, &s.dk_busy, sizeof s.dk_busy); 184 lseek(mf, (long)nl[X_DK_TIME].n_value, L_SET); 185 read(mf, s.dk_time, dk_ndrive*sizeof (long)); 186 lseek(mf, (long)nl[X_DK_XFER].n_value, L_SET); 187 read(mf, s.dk_xfer, dk_ndrive*sizeof (long)); 188 lseek(mf, (long)nl[X_DK_WDS].n_value, L_SET); 189 read(mf, s.dk_wds, dk_ndrive*sizeof (long)); 190 lseek(mf, (long)nl[X_DK_SEEK].n_value, L_SET); 191 read(mf, s.dk_seek, dk_ndrive*sizeof (long)); 192 lseek(mf, (long)nl[X_TK_NIN].n_value, L_SET); 193 read(mf, &s.tk_nin, sizeof s.tk_nin); 194 lseek(mf, (long)nl[X_TK_NOUT].n_value, L_SET); 195 read(mf, &s.tk_nout, sizeof s.tk_nout); 196 lseek(mf, (long)nl[X_CP_TIME].n_value, L_SET); 197 read(mf, s.cp_time, sizeof s.cp_time); 198 for (i = 0; i < dk_ndrive; i++) { 199 if (!dr_select[i]) 200 continue; 201 #define X(fld) t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t 202 X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time); 203 } 204 t = s.tk_nin; s.tk_nin -= s1.tk_nin; s1.tk_nin = t; 205 t = s.tk_nout; s.tk_nout -= s1.tk_nout; s1.tk_nout = t; 206 etime = 0; 207 for(i=0; i<CPUSTATES; i++) { 208 X(cp_time); 209 etime += s.cp_time[i]; 210 } 211 if (etime == 0.0) 212 etime = 1.0; 213 etime /= (float) hz; 214 printf("%4.0f%5.0f", s.tk_nin/etime, s.tk_nout/etime); 215 for (i=0; i<dk_ndrive; i++) 216 if (dr_select[i]) 217 stats(i); 218 for (i=0; i<CPUSTATES; i++) 219 stat1(i); 220 printf("\n"); 221 fflush(stdout); 222 contin: 223 if (--iter && argc > 0) { 224 sleep(atoi(argv[0])); 225 goto loop; 226 } 227 } 228 229 printhdr() 230 { 231 register int i; 232 233 printf(" tty"); 234 for (i = 0; i < dk_ndrive; i++) 235 if (dr_select[i]) 236 printf(" %3.3s ", dr_name[i]); 237 printf(" cpu\n"); 238 printf(" tin tout"); 239 for (i = 0; i < dk_ndrive; i++) 240 if (dr_select[i]) 241 printf(" bps tps msps "); 242 printf(" us ni sy id\n"); 243 tohdr = 19; 244 } 245 246 stats(dn) 247 { 248 register i; 249 double atime, words, xtime, itime; 250 251 if (dk_wpms[dn] == 0) { 252 printf("%4.0f%4.0f%5.1f ", 0.0, 0.0, 0.0); 253 return; 254 } 255 atime = s.dk_time[dn]; 256 atime /= (float) hz; 257 words = s.dk_wds[dn]*32.0; /* number of words transferred */ 258 xtime = words/dk_wpms[dn]; /* transfer time */ 259 itime = atime - xtime; /* time not transferring */ 260 if (xtime < 0) 261 itime += xtime, xtime = 0; 262 if (itime < 0) 263 xtime += itime, itime = 0; 264 printf("%4.0f", words/512/etime); 265 printf("%4.0f", s.dk_xfer[dn]/etime); 266 printf("%5.1f ", 267 s.dk_seek[dn] ? itime*1000./s.dk_seek[dn] : 0.0); 268 } 269 270 stat1(o) 271 { 272 register i; 273 double time; 274 275 time = 0; 276 for(i=0; i<CPUSTATES; i++) 277 time += s.cp_time[i]; 278 if (time == 0.0) 279 time = 1.0; 280 printf("%3.0f", 100.*s.cp_time[o]/time); 281 } 282 283 #define steal(where, var) \ 284 lseek(mf, where, L_SET); read(mf, &var, sizeof var); 285 286 #ifdef vax 287 #include <vaxuba/ubavar.h> 288 #include <vaxmba/mbavar.h> 289 290 read_names() 291 { 292 struct mba_device mdev; 293 register struct mba_device *mp; 294 struct mba_driver mdrv; 295 short two_char; 296 char *cp = (char *) &two_char; 297 struct uba_device udev, *up; 298 struct uba_driver udrv; 299 300 mp = (struct mba_device *) nl[X_MBDINIT].n_value; 301 up = (struct uba_device *) nl[X_UBDINIT].n_value; 302 if (up == 0) { 303 fprintf(stderr, "iostat: Disk init info not in namelist\n"); 304 exit(1); 305 } 306 if (mp) for (;;) { 307 steal(mp++, mdev); 308 if (mdev.mi_driver == 0) 309 break; 310 if (mdev.mi_dk < 0 || mdev.mi_alive == 0) 311 continue; 312 steal(mdev.mi_driver, mdrv); 313 steal(mdrv.md_dname, two_char); 314 sprintf(dr_name[mdev.mi_dk], "%c%c%d", 315 cp[0], cp[1], mdev.mi_unit); 316 } 317 if (up) for (;;) { 318 steal(up++, udev); 319 if (udev.ui_driver == 0) 320 break; 321 if (udev.ui_dk < 0 || udev.ui_alive == 0) 322 continue; 323 steal(udev.ui_driver, udrv); 324 steal(udrv.ud_dname, two_char); 325 sprintf(dr_name[udev.ui_dk], "%c%c%d", 326 cp[0], cp[1], udev.ui_unit); 327 } 328 } 329 #endif 330 331 #ifdef tahoe 332 #include <tahoevba/vbavar.h> 333 334 /* 335 * Read the drive names out of kmem. 336 */ 337 read_names() 338 { 339 struct vba_device udev, *up; 340 struct vba_driver udrv; 341 short two_char; 342 char *cp = (char *)&two_char; 343 344 up = (struct vba_device *) nl[X_VBDINIT].n_value; 345 if (up == 0) { 346 fprintf(stderr, "vmstat: Disk init info not in namelist\n"); 347 exit(1); 348 } 349 for (;;) { 350 steal(up++, udev); 351 if (udev.ui_driver == 0) 352 break; 353 if (udev.ui_dk < 0 || udev.ui_alive == 0) 354 continue; 355 steal(udev.ui_driver, udrv); 356 steal(udrv.ud_dname, two_char); 357 sprintf(dr_name[udev.ui_dk], "%c%c%d", 358 cp[0], cp[1], udev.ui_unit); 359 } 360 } 361 #endif 362