1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 char copyright[] = 9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif not lint 12 13 #ifndef lint 14 static char sccsid[] = "@(#)vmstat.c 5.1 (Berkeley) 05/31/85"; 15 #endif not lint 16 17 #include <stdio.h> 18 #include <ctype.h> 19 #include <nlist.h> 20 21 #include <sys/param.h> 22 #include <sys/file.h> 23 #include <sys/vm.h> 24 #include <sys/dk.h> 25 #include <sys/buf.h> 26 #include <sys/dir.h> 27 #include <sys/inode.h> 28 #include <sys/namei.h> 29 30 struct nlist nl[] = { 31 #define X_CPTIME 0 32 { "_cp_time" }, 33 #define X_RATE 1 34 { "_rate" }, 35 #define X_TOTAL 2 36 { "_total" }, 37 #define X_DEFICIT 3 38 { "_deficit" }, 39 #define X_FORKSTAT 4 40 { "_forkstat" }, 41 #define X_SUM 5 42 { "_sum" }, 43 #define X_FIRSTFREE 6 44 { "_firstfree" }, 45 #define X_MAXFREE 7 46 { "_maxfree" }, 47 #define X_BOOTTIME 8 48 { "_boottime" }, 49 #define X_DKXFER 9 50 { "_dk_xfer" }, 51 #define X_REC 10 52 { "_rectime" }, 53 #define X_PGIN 11 54 { "_pgintime" }, 55 #define X_HZ 12 56 { "_hz" }, 57 #define X_PHZ 13 58 { "_phz" }, 59 #define X_NCHSTATS 14 60 { "_nchstats" }, 61 #define X_INTRNAMES 15 62 { "_intrnames" }, 63 #define X_EINTRNAMES 16 64 { "_eintrnames" }, 65 #define X_INTRCNT 17 66 { "_intrcnt" }, 67 #define X_EINTRCNT 18 68 { "_eintrcnt" }, 69 #define X_DK_NDRIVE 19 70 { "_dk_ndrive" }, 71 #ifdef vax 72 #define X_MBDINIT 20 73 { "_mbdinit" }, 74 #define X_UBDINIT 21 75 { "_ubdinit" }, 76 #endif 77 { "" }, 78 }; 79 80 char **dr_name; 81 int *dr_select; 82 int dk_ndrive; 83 int ndrives = 0; 84 #ifdef vax 85 char *defdrives[] = { "hp0", "hp1", "hp2", 0 }; 86 #else 87 char *defdrives[] = { 0 }; 88 #endif 89 double stat1(); 90 int firstfree, maxfree; 91 int hz; 92 int phz; 93 int HZ; 94 95 #ifdef vax 96 #define INTS(x) ((x) - (hz + phz)) 97 #endif 98 99 struct { 100 int busy; 101 long time[CPUSTATES]; 102 long *xfer; 103 struct vmmeter Rate; 104 struct vmtotal Total; 105 struct vmmeter Sum; 106 struct forkstat Forkstat; 107 unsigned rectime; 108 unsigned pgintime; 109 } s, s1, z; 110 #define rate s.Rate 111 #define total s.Total 112 #define sum s.Sum 113 #define forkstat s.Forkstat 114 115 struct vmmeter osum; 116 int zero; 117 int deficit; 118 double etime; 119 int mf; 120 time_t now, boottime; 121 int printhdr(); 122 int lines = 1; 123 124 main(argc, argv) 125 int argc; 126 char **argv; 127 { 128 extern char *ctime(); 129 register i,j; 130 int iter, nintv, iflag = 0; 131 double f1, f2; 132 long t; 133 char *arg, **cp, name[6], buf[BUFSIZ]; 134 135 nlist("/vmunix", nl); 136 if(nl[0].n_type == 0) { 137 printf("no /vmunix namelist\n"); 138 exit(1); 139 } 140 mf = open("/dev/kmem", 0); 141 if(mf < 0) { 142 printf("cannot open /dev/kmem\n"); 143 exit(1); 144 } 145 iter = 0; 146 argc--, argv++; 147 while (argc>0 && argv[0][0]=='-') { 148 char *cp = *argv++; 149 argc--; 150 while (*++cp) switch (*cp) { 151 152 case 't': 153 dotimes(); 154 exit(0); 155 156 case 'z': 157 close(mf); 158 mf = open("/dev/kmem", 2); 159 lseek(mf, (long)nl[X_SUM].n_value, L_SET); 160 write(mf, &z.Sum, sizeof z.Sum); 161 exit(0); 162 163 case 'f': 164 doforkst(); 165 exit(0); 166 167 case 's': 168 dosum(); 169 exit(0); 170 171 case 'i': 172 iflag++; 173 break; 174 175 default: 176 fprintf(stderr, 177 "usage: vmstat [ -fsi ] [ interval ] [ count]\n"); 178 exit(1); 179 } 180 } 181 lseek(mf, (long)nl[X_FIRSTFREE].n_value, L_SET); 182 read(mf, &firstfree, sizeof firstfree); 183 lseek(mf, (long)nl[X_MAXFREE].n_value, L_SET); 184 read(mf, &maxfree, sizeof maxfree); 185 lseek(mf, (long)nl[X_BOOTTIME].n_value, L_SET); 186 read(mf, &boottime, sizeof boottime); 187 lseek(mf, (long)nl[X_HZ].n_value, L_SET); 188 read(mf, &hz, sizeof hz); 189 if (nl[X_PHZ].n_value != 0) { 190 lseek(mf, (long)nl[X_PHZ].n_value, L_SET); 191 read(mf, &phz, sizeof phz); 192 } 193 HZ = phz ? phz : hz; 194 if (nl[DK_NDRIVE].n_value == 0) { 195 printf("dk_ndrive undefined in system\n"); 196 exit(1); 197 } 198 lseek(mf, nl[X_DK_NDRIVE].n_value, L_SET); 199 read(mf, &dk_ndrive, sizeof (dk_ndrive)); 200 if (dk_ndrive <= 0) { 201 printf("dk_ndrive %d\n", dk_ndrive); 202 exit(1); 203 } 204 dr_select = (int *)calloc(dk_ndrive, sizeof (int)); 205 dr_name = (char **)calloc(dk_ndrive, sizeof (char *)); 206 #define allocate(e, t) \ 207 s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \ 208 s1./**/e = (t *)calloc(dk_ndrive, sizeof (t)); 209 allocate(xfer, long); 210 for (arg = buf, i = 0; i < dk_ndrive; i++) { 211 dr_name[i] = arg; 212 sprintf(dr_name[i], "dk%d", i); 213 arg += strlen(dr_name[i]) + 1; 214 } 215 read_names(); 216 time(&now); 217 nintv = now - boottime; 218 if (nintv <= 0 || nintv > 60*60*24*365*10) { 219 printf("Time makes no sense... namelist must be wrong.\n"); 220 exit(1); 221 } 222 if (iflag) { 223 dointr(nintv); 224 exit(0); 225 } 226 /* 227 * Choose drives to be displayed. Priority 228 * goes to (in order) drives supplied as arguments, 229 * default drives. If everything isn't filled 230 * in and there are drives not taken care of, 231 * display the first few that fit. 232 */ 233 ndrives = 0; 234 while (argc > 0 && !isdigit(argv[0][0])) { 235 for (i = 0; i < dk_ndrive; i++) { 236 if (strcmp(dr_name[i], argv[0])) 237 continue; 238 dr_select[i] = 1; 239 ndrives++; 240 } 241 argc--, argv++; 242 } 243 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 244 if (dr_select[i]) 245 continue; 246 for (cp = defdrives; *cp; cp++) 247 if (strcmp(dr_name[i], *cp) == 0) { 248 dr_select[i] = 1; 249 ndrives++; 250 break; 251 } 252 } 253 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 254 if (dr_select[i]) 255 continue; 256 dr_select[i] = 1; 257 ndrives++; 258 } 259 if (argc > 1) 260 iter = atoi(argv[1]); 261 signal(SIGCONT, printhdr); 262 loop: 263 if (--lines == 0) 264 printhdr(); 265 lseek(mf, (long)nl[X_CPTIME].n_value, L_SET); 266 read(mf, s.time, sizeof s.time); 267 lseek(mf, (long)nl[X_DKXFER].n_value, L_SET); 268 read(mf, s.xfer, dk_ndrive * sizeof (long)); 269 if (nintv != 1) 270 lseek(mf, (long)nl[X_SUM].n_value, L_SET); 271 else 272 lseek(mf, (long)nl[X_RATE].n_value, L_SET); 273 read(mf, &rate, sizeof rate); 274 lseek(mf, (long)nl[X_TOTAL].n_value, L_SET); 275 read(mf, &total, sizeof total); 276 osum = sum; 277 lseek(mf, (long)nl[X_SUM].n_value, L_SET); 278 read(mf, &sum, sizeof sum); 279 lseek(mf, (long)nl[X_DEFICIT].n_value, L_SET); 280 read(mf, &deficit, sizeof deficit); 281 etime = 0; 282 for (i=0; i < dk_ndrive; i++) { 283 t = s.xfer[i]; 284 s.xfer[i] -= s1.xfer[i]; 285 s1.xfer[i] = t; 286 } 287 for (i=0; i < CPUSTATES; i++) { 288 t = s.time[i]; 289 s.time[i] -= s1.time[i]; 290 s1.time[i] = t; 291 etime += s.time[i]; 292 } 293 if(etime == 0.) 294 etime = 1.; 295 printf("%2d%2d%2d", total.t_rq, total.t_dw+total.t_pw, total.t_sw); 296 #define pgtok(a) ((a)*NBPG/1024) 297 printf("%6d%5d", pgtok(total.t_avm), pgtok(total.t_free)); 298 printf("%4d%3d", (rate.v_pgrec - (rate.v_xsfrec+rate.v_xifrec))/nintv, 299 (rate.v_xsfrec+rate.v_xifrec)/nintv); 300 printf("%4d", pgtok(rate.v_pgpgin)/nintv); 301 printf("%4d%4d%4d%4d", pgtok(rate.v_pgpgout)/nintv, 302 pgtok(rate.v_dfree)/nintv, pgtok(deficit), rate.v_scan/nintv); 303 etime /= (float)HZ; 304 for (i = 0; i < dk_ndrive; i++) 305 if (dr_select[i]) 306 stats(i); 307 printf("%4d%4d%4d", INTS(rate.v_intr/nintv), rate.v_syscall/nintv, 308 rate.v_swtch/nintv); 309 for(i=0; i<CPUSTATES; i++) { 310 float f = stat1(i); 311 if (i == 0) { /* US+NI */ 312 i++; 313 f += stat1(i); 314 } 315 printf("%3.0f", f); 316 } 317 printf("\n"); 318 fflush(stdout); 319 contin: 320 nintv = 1; 321 if (--iter &&argc > 0) { 322 sleep(atoi(argv[0])); 323 goto loop; 324 } 325 } 326 327 printhdr() 328 { 329 register int i, j; 330 331 printf(" procs memory page "); 332 i = (ndrives * 3 - 6) / 2; 333 if (i < 0) 334 i = 0; 335 for (j = 0; j < i; j++) 336 putchar(' '); 337 printf("faults"); 338 i = ndrives * 3 - 6 - i; 339 for (j = 0; j < i; j++) 340 putchar(' '); 341 printf(" cpu\n"); 342 printf(" r b w avm fre re at pi po fr de sr "); 343 for (i = 0; i < dk_ndrive; i++) 344 if (dr_select[i]) 345 printf("%c%c ", dr_name[i][0], dr_name[i][2]); 346 printf(" in sy cs us sy id\n"); 347 lines = 19; 348 } 349 350 dotimes() 351 { 352 353 lseek(mf, (long)nl[X_REC].n_value, L_SET); 354 read(mf, &s.rectime, sizeof s.rectime); 355 lseek(mf, (long)nl[X_PGIN].n_value, L_SET); 356 read(mf, &s.pgintime, sizeof s.pgintime); 357 lseek(mf, (long)nl[X_SUM].n_value, L_SET); 358 read(mf, &sum, sizeof sum); 359 printf("%d reclaims, %d total time (usec)\n", sum.v_pgrec, s.rectime); 360 printf("average: %d usec / reclaim\n", s.rectime/sum.v_pgrec); 361 printf("\n"); 362 printf("%d page ins, %d total time (msec)\n",sum.v_pgin, s.pgintime/10); 363 printf("average: %8.1f msec / page in\n", s.pgintime/(sum.v_pgin*10.0)); 364 } 365 366 dosum() 367 { 368 struct nchstats nchstats; 369 long nchtotal; 370 371 lseek(mf, (long)nl[X_SUM].n_value, L_SET); 372 read(mf, &sum, sizeof sum); 373 printf("%9d swap ins\n", sum.v_swpin); 374 printf("%9d swap outs\n", sum.v_swpout); 375 printf("%9d pages swapped in\n", sum.v_pswpin / CLSIZE); 376 printf("%9d pages swapped out\n", sum.v_pswpout / CLSIZE); 377 printf("%9d total address trans. faults taken\n", sum.v_faults); 378 printf("%9d page ins\n", sum.v_pgin); 379 printf("%9d page outs\n", sum.v_pgout); 380 printf("%9d pages paged in\n", sum.v_pgpgin); 381 printf("%9d pages paged out\n", sum.v_pgpgout); 382 printf("%9d sequential process pages freed\n", sum.v_seqfree); 383 printf("%9d total reclaims (%d%% fast)\n", sum.v_pgrec, 384 (sum.v_fastpgrec * 100) / (sum.v_pgrec == 0 ? 1 : sum.v_pgrec)); 385 printf("%9d reclaims from free list\n", sum.v_pgfrec); 386 printf("%9d intransit blocking page faults\n", sum.v_intrans); 387 printf("%9d zero fill pages created\n", sum.v_nzfod / CLSIZE); 388 printf("%9d zero fill page faults\n", sum.v_zfod / CLSIZE); 389 printf("%9d executable fill pages created\n", sum.v_nexfod / CLSIZE); 390 printf("%9d executable fill page faults\n", sum.v_exfod / CLSIZE); 391 printf("%9d swap text pages found in free list\n", sum.v_xsfrec); 392 printf("%9d inode text pages found in free list\n", sum.v_xifrec); 393 printf("%9d file fill pages created\n", sum.v_nvrfod / CLSIZE); 394 printf("%9d file fill page faults\n", sum.v_vrfod / CLSIZE); 395 printf("%9d pages examined by the clock daemon\n", sum.v_scan); 396 printf("%9d revolutions of the clock hand\n", sum.v_rev); 397 printf("%9d pages freed by the clock daemon\n", sum.v_dfree / CLSIZE); 398 printf("%9d cpu context switches\n", sum.v_swtch); 399 printf("%9d device interrupts\n", sum.v_intr); 400 printf("%9d software interrupts\n", sum.v_soft); 401 #ifdef vax 402 printf("%9d pseduo-dma dz interrupts\n", sum.v_pdma); 403 #endif 404 printf("%9d traps\n", sum.v_trap); 405 printf("%9d system calls\n", sum.v_syscall); 406 lseek(mf, (long)nl[X_NCHSTATS].n_value, 0); 407 read(mf, &nchstats, sizeof nchstats); 408 nchtotal = nchstats.ncs_goodhits + nchstats.ncs_badhits + 409 nchstats.ncs_falsehits + nchstats.ncs_miss + nchstats.ncs_long; 410 printf("%9d total name lookups", nchtotal); 411 #define nz(x) ((x) ? (x) : 1) 412 printf(" (cache hits %d%% system %d%% per-process)\n", 413 nchstats.ncs_goodhits * 100 / nz(nchtotal), 414 nchstats.ncs_pass2 * 100 / nz(nchtotal)); 415 printf("%9s badhits %d, falsehits %d, toolong %d\n", "", 416 nchstats.ncs_badhits, nchstats.ncs_falsehits, nchstats.ncs_long); 417 } 418 419 doforkst() 420 { 421 422 lseek(mf, (long)nl[X_FORKSTAT].n_value, L_SET); 423 read(mf, &forkstat, sizeof forkstat); 424 printf("%d forks, %d pages, average=%.2f\n", 425 forkstat.cntfork, forkstat.sizfork, 426 (float) forkstat.sizfork / forkstat.cntfork); 427 printf("%d vforks, %d pages, average=%.2f\n", 428 forkstat.cntvfork, forkstat.sizvfork, 429 (float)forkstat.sizvfork / forkstat.cntvfork); 430 } 431 432 stats(dn) 433 { 434 435 if (dn >= dk_ndrive) { 436 printf(" 0"); 437 return; 438 } 439 printf("%3.0f", s.xfer[dn]/etime); 440 } 441 442 double 443 stat1(row) 444 { 445 double t; 446 register i; 447 448 t = 0; 449 for(i=0; i<CPUSTATES; i++) 450 t += s.time[i]; 451 if(t == 0.) 452 t = 1.; 453 return(s.time[row]*100./t); 454 } 455 456 pct(top, bot) 457 { 458 459 if (bot == 0) 460 return (0); 461 return ((top * 100) / bot); 462 } 463 464 dointr(nintv) 465 { 466 int nintr, inttotal; 467 long *intrcnt; 468 char *intrname, *malloc(); 469 470 nintr = (nl[X_EINTRCNT].n_value - nl[X_INTRCNT].n_value) / sizeof(long); 471 intrcnt = (long *) malloc(nl[X_EINTRCNT].n_value - 472 nl[X_INTRCNT].n_value); 473 intrname = malloc(nl[X_EINTRNAMES].n_value - nl[X_INTRNAMES].n_value); 474 if (intrcnt == NULL || intrname == NULL) { 475 fprintf(stderr, "vmstat: out of memory\n"); 476 exit(9); 477 } 478 lseek(mf, (long)nl[X_INTRCNT].n_value, L_SET); 479 read(mf, intrcnt, nintr * sizeof (long)); 480 lseek(mf, (long)nl[X_INTRNAMES].n_value, L_SET); 481 read(mf, intrname, nl[X_EINTRNAMES].n_value - nl[X_INTRNAMES].n_value); 482 printf("interrupt total rate\n"); 483 inttotal = 0; 484 while (nintr--) { 485 if (*intrcnt) 486 printf("%-12s %8ld %8ld\n", intrname, 487 *intrcnt, *intrcnt / nintv); 488 intrname += strlen(intrname) + 1; 489 inttotal += *intrcnt++; 490 } 491 printf("Total %8ld %8ld\n", inttotal, inttotal / nintv); 492 } 493 494 #define steal(where, var) \ 495 lseek(mf, where, L_SET); read(mf, &var, sizeof var); 496 /* 497 * Read the drive names out of kmem. 498 */ 499 #ifdef vax 500 #include <vaxuba/ubavar.h> 501 #include <vaxmba/mbavar.h> 502 503 read_names() 504 { 505 struct mba_device mdev; 506 register struct mba_device *mp; 507 struct mba_driver mdrv; 508 short two_char; 509 char *cp = (char *) &two_char; 510 struct uba_device udev, *up; 511 struct uba_driver udrv; 512 513 mp = (struct mba_device *) nl[X_MBDINIT].n_value; 514 up = (struct uba_device *) nl[X_UBDINIT].n_value; 515 if (up == 0) { 516 fprintf(stderr, "vmstat: Disk init info not in namelist\n"); 517 exit(1); 518 } 519 if (mp) for (;;) { 520 steal(mp++, mdev); 521 if (mdev.mi_driver == 0) 522 break; 523 if (mdev.mi_dk < 0 || mdev.mi_alive == 0) 524 continue; 525 steal(mdev.mi_driver, mdrv); 526 steal(mdrv.md_dname, two_char); 527 sprintf(dr_name[mdev.mi_dk], "%c%c%d", 528 cp[0], cp[1], mdev.mi_unit); 529 } 530 for (;;) { 531 steal(up++, udev); 532 if (udev.ui_driver == 0) 533 break; 534 if (udev.ui_dk < 0 || udev.ui_alive == 0) 535 continue; 536 steal(udev.ui_driver, udrv); 537 steal(udrv.ud_dname, two_char); 538 sprintf(dr_name[udev.ui_dk], "%c%c%d", 539 cp[0], cp[1], udev.ui_unit); 540 } 541 } 542 #endif 543