1 /* 2 * Copyright (c) 1980, 1986, 1991, 1993 3 * The Regents of the University of California. 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 static char copyright[] = 36 "@(#) Copyright (c) 1980, 1986, 1991, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93"; 42 #endif /* not lint */ 43 44 #include <sys/param.h> 45 #include <sys/time.h> 46 #include <sys/proc.h> 47 #include <sys/user.h> 48 #include <sys/dkstat.h> 49 #include <sys/buf.h> 50 #include <sys/namei.h> 51 #include <sys/malloc.h> 52 #include <sys/signal.h> 53 #include <sys/fcntl.h> 54 #include <sys/ioctl.h> 55 #include <sys/sysctl.h> 56 #include <vm/vm.h> 57 #include <time.h> 58 #include <nlist.h> 59 #include <kvm.h> 60 #include <errno.h> 61 #include <unistd.h> 62 #include <stdio.h> 63 #include <ctype.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <paths.h> 67 #include <limits.h> 68 69 #define NEWVM /* XXX till old has been updated or purged */ 70 struct nlist namelist[] = { 71 #define X_CPTIME 0 72 { "_cp_time" }, 73 #define X_DK_NDRIVE 1 74 { "_dk_ndrive" }, 75 #define X_SUM 2 76 { "_cnt" }, 77 #define X_BOOTTIME 3 78 { "_boottime" }, 79 #define X_DKXFER 4 80 { "_dk_xfer" }, 81 #define X_HZ 5 82 { "_hz" }, 83 #define X_STATHZ 6 84 { "_stathz" }, 85 #define X_NCHSTATS 7 86 { "_nchstats" }, 87 #define X_INTRNAMES 8 88 { "_intrnames" }, 89 #define X_EINTRNAMES 9 90 { "_eintrnames" }, 91 #define X_INTRCNT 10 92 { "_intrcnt" }, 93 #define X_EINTRCNT 11 94 { "_eintrcnt" }, 95 #define X_KMEMSTAT 12 96 { "_kmemstats" }, 97 #define X_KMEMBUCKETS 13 98 { "_bucket" }, 99 #ifdef notdef 100 #define X_DEFICIT 14 101 { "_deficit" }, 102 #define X_FORKSTAT 15 103 { "_forkstat" }, 104 #define X_REC 16 105 { "_rectime" }, 106 #define X_PGIN 17 107 { "_pgintime" }, 108 #define X_XSTATS 18 109 { "_xstats" }, 110 #define X_END 19 111 #else 112 #define X_END 14 113 #endif 114 #if defined(hp300) || defined(luna68k) 115 #define X_HPDINIT (X_END) 116 { "_hp_dinit" }, 117 #endif 118 #if defined(i386) 119 #define X_ISA_BIO (X_END) 120 { "_isa_devtab_bio" }, 121 #endif 122 #ifdef mips 123 #define X_SCSI_DINIT (X_END) 124 { "_scsi_dinit" }, 125 #endif 126 #ifdef tahoe 127 #define X_VBDINIT (X_END) 128 { "_vbdinit" }, 129 #define X_CKEYSTATS (X_END+1) 130 { "_ckeystats" }, 131 #define X_DKEYSTATS (X_END+2) 132 { "_dkeystats" }, 133 #endif 134 #ifdef vax 135 #define X_MBDINIT (X_END) 136 { "_mbdinit" }, 137 #define X_UBDINIT (X_END+1) 138 { "_ubdinit" }, 139 #endif 140 { "" }, 141 }; 142 143 struct _disk { 144 long time[CPUSTATES]; 145 long *xfer; 146 } cur, last; 147 148 struct vmmeter sum, osum; 149 char **dr_name; 150 int *dr_select, dk_ndrive, ndrives; 151 152 int winlines = 20; 153 154 kvm_t *kd; 155 156 #define FORKSTAT 0x01 157 #define INTRSTAT 0x02 158 #define MEMSTAT 0x04 159 #define SUMSTAT 0x08 160 #define TIMESTAT 0x10 161 #define VMSTAT 0x20 162 163 #include "names.c" /* disk names -- machine dependent */ 164 165 void cpustats(), dkstats(), dointr(), domem(), dosum(); 166 void dovmstat(), kread(), usage(); 167 #ifdef notdef 168 void dotimes(), doforkst(); 169 #endif 170 171 main(argc, argv) 172 register int argc; 173 register char **argv; 174 { 175 extern int optind; 176 extern char *optarg; 177 register int c, todo; 178 u_int interval; 179 int reps; 180 char *memf, *nlistf; 181 char errbuf[_POSIX2_LINE_MAX]; 182 183 memf = nlistf = NULL; 184 interval = reps = todo = 0; 185 while ((c = getopt(argc, argv, "c:fiM:mN:stw:")) != EOF) { 186 switch (c) { 187 case 'c': 188 reps = atoi(optarg); 189 break; 190 #ifndef notdef 191 case 'f': 192 todo |= FORKSTAT; 193 break; 194 #endif 195 case 'i': 196 todo |= INTRSTAT; 197 break; 198 case 'M': 199 memf = optarg; 200 break; 201 case 'm': 202 todo |= MEMSTAT; 203 break; 204 case 'N': 205 nlistf = optarg; 206 break; 207 case 's': 208 todo |= SUMSTAT; 209 break; 210 #ifndef notdef 211 case 't': 212 todo |= TIMESTAT; 213 break; 214 #endif 215 case 'w': 216 interval = atoi(optarg); 217 break; 218 case '?': 219 default: 220 usage(); 221 } 222 } 223 argc -= optind; 224 argv += optind; 225 226 if (todo == 0) 227 todo = VMSTAT; 228 229 /* 230 * Discard setgid privileges if not the running kernel so that bad 231 * guys can't print interesting stuff from kernel memory. 232 */ 233 if (nlistf != NULL || memf != NULL) 234 setgid(getgid()); 235 236 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 237 if (kd == 0) { 238 (void)fprintf(stderr, 239 "vmstat: kvm_openfiles: %s\n", errbuf); 240 exit(1); 241 } 242 243 if ((c = kvm_nlist(kd, namelist)) != 0) { 244 if (c > 0) { 245 (void)fprintf(stderr, 246 "vmstat: undefined symbols:"); 247 for (c = 0; 248 c < sizeof(namelist)/sizeof(namelist[0]); c++) 249 if (namelist[c].n_type == 0) 250 fprintf(stderr, " %s", 251 namelist[c].n_name); 252 (void)fputc('\n', stderr); 253 } else 254 (void)fprintf(stderr, "vmstat: kvm_nlist: %s\n", 255 kvm_geterr(kd)); 256 exit(1); 257 } 258 259 if (todo & VMSTAT) { 260 char **getdrivedata(); 261 struct winsize winsize; 262 263 argv = getdrivedata(argv); 264 winsize.ws_row = 0; 265 (void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize); 266 if (winsize.ws_row > 0) 267 winlines = winsize.ws_row; 268 269 } 270 271 #define BACKWARD_COMPATIBILITY 272 #ifdef BACKWARD_COMPATIBILITY 273 if (*argv) { 274 interval = atoi(*argv); 275 if (*++argv) 276 reps = atoi(*argv); 277 } 278 #endif 279 280 if (interval) { 281 if (!reps) 282 reps = -1; 283 } else if (reps) 284 interval = 1; 285 286 #ifdef notdef 287 if (todo & FORKSTAT) 288 doforkst(); 289 #endif 290 if (todo & MEMSTAT) 291 domem(); 292 if (todo & SUMSTAT) 293 dosum(); 294 #ifdef notdef 295 if (todo & TIMESTAT) 296 dotimes(); 297 #endif 298 if (todo & INTRSTAT) 299 dointr(); 300 if (todo & VMSTAT) 301 dovmstat(interval, reps); 302 exit(0); 303 } 304 305 char ** 306 getdrivedata(argv) 307 char **argv; 308 { 309 register int i; 310 register char **cp; 311 char buf[30]; 312 313 kread(X_DK_NDRIVE, &dk_ndrive, sizeof(dk_ndrive)); 314 if (dk_ndrive <= 0) { 315 (void)fprintf(stderr, "vmstat: dk_ndrive %d\n", dk_ndrive); 316 exit(1); 317 } 318 dr_select = calloc((size_t)dk_ndrive, sizeof(int)); 319 dr_name = calloc((size_t)dk_ndrive, sizeof(char *)); 320 for (i = 0; i < dk_ndrive; i++) 321 dr_name[i] = NULL; 322 cur.xfer = calloc((size_t)dk_ndrive, sizeof(long)); 323 last.xfer = calloc((size_t)dk_ndrive, sizeof(long)); 324 if (!read_names()) 325 exit (1); 326 for (i = 0; i < dk_ndrive; i++) 327 if (dr_name[i] == NULL) { 328 (void)sprintf(buf, "??%d", i); 329 dr_name[i] = strdup(buf); 330 } 331 332 /* 333 * Choose drives to be displayed. Priority goes to (in order) drives 334 * supplied as arguments, default drives. If everything isn't filled 335 * in and there are drives not taken care of, display the first few 336 * that fit. 337 */ 338 #define BACKWARD_COMPATIBILITY 339 for (ndrives = 0; *argv; ++argv) { 340 #ifdef BACKWARD_COMPATIBILITY 341 if (isdigit(**argv)) 342 break; 343 #endif 344 for (i = 0; i < dk_ndrive; i++) { 345 if (strcmp(dr_name[i], *argv)) 346 continue; 347 dr_select[i] = 1; 348 ++ndrives; 349 break; 350 } 351 } 352 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 353 if (dr_select[i]) 354 continue; 355 for (cp = defdrives; *cp; cp++) 356 if (strcmp(dr_name[i], *cp) == 0) { 357 dr_select[i] = 1; 358 ++ndrives; 359 break; 360 } 361 } 362 for (i = 0; i < dk_ndrive && ndrives < 4; i++) { 363 if (dr_select[i]) 364 continue; 365 dr_select[i] = 1; 366 ++ndrives; 367 } 368 return(argv); 369 } 370 371 long 372 getuptime() 373 { 374 static time_t now, boottime; 375 time_t uptime; 376 377 if (boottime == 0) 378 kread(X_BOOTTIME, &boottime, sizeof(boottime)); 379 (void)time(&now); 380 uptime = now - boottime; 381 if (uptime <= 0 || uptime > 60*60*24*365*10) { 382 (void)fprintf(stderr, 383 "vmstat: time makes no sense; namelist must be wrong.\n"); 384 exit(1); 385 } 386 return(uptime); 387 } 388 389 int hz, hdrcnt; 390 391 void 392 dovmstat(interval, reps) 393 u_int interval; 394 int reps; 395 { 396 struct vmtotal total; 397 time_t uptime, halfuptime; 398 void needhdr(); 399 int mib[2], size; 400 401 uptime = getuptime(); 402 halfuptime = uptime / 2; 403 (void)signal(SIGCONT, needhdr); 404 405 if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0) 406 kread(X_STATHZ, &hz, sizeof(hz)); 407 if (!hz) 408 kread(X_HZ, &hz, sizeof(hz)); 409 410 for (hdrcnt = 1;;) { 411 if (!--hdrcnt) 412 printhdr(); 413 kread(X_CPTIME, cur.time, sizeof(cur.time)); 414 kread(X_DKXFER, cur.xfer, sizeof(*cur.xfer) * dk_ndrive); 415 kread(X_SUM, &sum, sizeof(sum)); 416 size = sizeof(total); 417 mib[0] = CTL_VM; 418 mib[1] = VM_METER; 419 if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) { 420 printf("Can't get kerninfo: %s\n", strerror(errno)); 421 bzero(&total, sizeof(total)); 422 } 423 (void)printf("%2d%2d%2d", 424 total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); 425 #define pgtok(a) ((a) * sum.v_page_size >> 10) 426 #define rate(x) (((x) + halfuptime) / uptime) /* round */ 427 (void)printf("%6ld%6ld ", 428 pgtok(total.t_avm), pgtok(total.t_free)); 429 #ifdef NEWVM 430 (void)printf("%4lu ", rate(sum.v_faults - osum.v_faults)); 431 (void)printf("%3lu ", 432 rate(sum.v_reactivated - osum.v_reactivated)); 433 (void)printf("%3lu ", rate(sum.v_pageins - osum.v_pageins)); 434 (void)printf("%3lu %3lu ", 435 rate(sum.v_pageouts - osum.v_pageouts), 0); 436 #else 437 (void)printf("%3lu %2lu ", 438 rate(sum.v_pgrec - (sum.v_xsfrec+sum.v_xifrec) - 439 (osum.v_pgrec - (osum.v_xsfrec+osum.v_xifrec))), 440 rate(sum.v_xsfrec + sum.v_xifrec - 441 osum.v_xsfrec - osum.v_xifrec)); 442 (void)printf("%3lu ", 443 rate(pgtok(sum.v_pgpgin - osum.v_pgpgin))); 444 (void)printf("%3lu %3lu ", 445 rate(pgtok(sum.v_pgpgout - osum.v_pgpgout)), 446 rate(pgtok(sum.v_dfree - osum.v_dfree))); 447 (void)printf("%3d ", pgtok(deficit)); 448 #endif 449 (void)printf("%3lu ", rate(sum.v_scan - osum.v_scan)); 450 dkstats(); 451 (void)printf("%4lu %4lu %3lu ", 452 rate(sum.v_intr - osum.v_intr), 453 rate(sum.v_syscall - osum.v_syscall), 454 rate(sum.v_swtch - osum.v_swtch)); 455 cpustats(); 456 (void)printf("\n"); 457 (void)fflush(stdout); 458 if (reps >= 0 && --reps <= 0) 459 break; 460 osum = sum; 461 uptime = interval; 462 /* 463 * We round upward to avoid losing low-frequency events 464 * (i.e., >= 1 per interval but < 1 per second). 465 */ 466 halfuptime = (uptime + 1) / 2; 467 (void)sleep(interval); 468 } 469 } 470 471 printhdr() 472 { 473 register int i; 474 475 (void)printf(" procs memory page%*s", 20, ""); 476 if (ndrives > 1) 477 (void)printf("disks %*s faults cpu\n", 478 ndrives * 3 - 6, ""); 479 else 480 (void)printf("%*s faults cpu\n", ndrives * 3, ""); 481 #ifndef NEWVM 482 (void)printf(" r b w avm fre re at pi po fr de sr "); 483 #else 484 (void)printf(" r b w avm fre flt re pi po fr sr "); 485 #endif 486 for (i = 0; i < dk_ndrive; i++) 487 if (dr_select[i]) 488 (void)printf("%c%c ", dr_name[i][0], 489 dr_name[i][strlen(dr_name[i]) - 1]); 490 (void)printf(" in sy cs us sy id\n"); 491 hdrcnt = winlines - 2; 492 } 493 494 /* 495 * Force a header to be prepended to the next output. 496 */ 497 void 498 needhdr() 499 { 500 501 hdrcnt = 1; 502 } 503 504 #ifdef notdef 505 void 506 dotimes() 507 { 508 u_int pgintime, rectime; 509 510 kread(X_REC, &rectime, sizeof(rectime)); 511 kread(X_PGIN, &pgintime, sizeof(pgintime)); 512 kread(X_SUM, &sum, sizeof(sum)); 513 (void)printf("%u reclaims, %u total time (usec)\n", 514 sum.v_pgrec, rectime); 515 (void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec); 516 (void)printf("\n"); 517 (void)printf("%u page ins, %u total time (msec)\n", 518 sum.v_pgin, pgintime / 10); 519 (void)printf("average: %8.1f msec / page in\n", 520 pgintime / (sum.v_pgin * 10.0)); 521 } 522 #endif 523 524 pct(top, bot) 525 long top, bot; 526 { 527 long ans; 528 529 if (bot == 0) 530 return(0); 531 ans = (quad_t)top * 100 / bot; 532 return (ans); 533 } 534 535 #define PCT(top, bot) pct((long)(top), (long)(bot)) 536 537 #if defined(tahoe) 538 #include <machine/cpu.h> 539 #endif 540 541 void 542 dosum() 543 { 544 struct nchstats nchstats; 545 #ifndef NEWVM 546 struct xstats xstats; 547 #endif 548 long nchtotal; 549 #if defined(tahoe) 550 struct keystats keystats; 551 #endif 552 553 kread(X_SUM, &sum, sizeof(sum)); 554 (void)printf("%9u cpu context switches\n", sum.v_swtch); 555 (void)printf("%9u device interrupts\n", sum.v_intr); 556 (void)printf("%9u software interrupts\n", sum.v_soft); 557 #ifdef vax 558 (void)printf("%9u pseudo-dma dz interrupts\n", sum.v_pdma); 559 #endif 560 (void)printf("%9u traps\n", sum.v_trap); 561 (void)printf("%9u system calls\n", sum.v_syscall); 562 (void)printf("%9u total faults taken\n", sum.v_faults); 563 (void)printf("%9u swap ins\n", sum.v_swpin); 564 (void)printf("%9u swap outs\n", sum.v_swpout); 565 (void)printf("%9u pages swapped in\n", sum.v_pswpin / CLSIZE); 566 (void)printf("%9u pages swapped out\n", sum.v_pswpout / CLSIZE); 567 (void)printf("%9u page ins\n", sum.v_pageins); 568 (void)printf("%9u page outs\n", sum.v_pageouts); 569 (void)printf("%9u pages paged in\n", sum.v_pgpgin); 570 (void)printf("%9u pages paged out\n", sum.v_pgpgout); 571 (void)printf("%9u pages reactivated\n", sum.v_reactivated); 572 (void)printf("%9u intransit blocking page faults\n", sum.v_intrans); 573 (void)printf("%9u zero fill pages created\n", sum.v_nzfod / CLSIZE); 574 (void)printf("%9u zero fill page faults\n", sum.v_zfod / CLSIZE); 575 (void)printf("%9u pages examined by the clock daemon\n", sum.v_scan); 576 (void)printf("%9u revolutions of the clock hand\n", sum.v_rev); 577 #ifdef NEWVM 578 (void)printf("%9u VM object cache lookups\n", sum.v_lookups); 579 (void)printf("%9u VM object hits\n", sum.v_hits); 580 (void)printf("%9u total VM faults taken\n", sum.v_vm_faults); 581 (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults); 582 (void)printf("%9u pages freed by daemon\n", sum.v_dfree); 583 (void)printf("%9u pages freed by exiting processes\n", sum.v_pfree); 584 (void)printf("%9u pages free\n", sum.v_free_count); 585 (void)printf("%9u pages wired down\n", sum.v_wire_count); 586 (void)printf("%9u pages active\n", sum.v_active_count); 587 (void)printf("%9u pages inactive\n", sum.v_inactive_count); 588 (void)printf("%9u bytes per page\n", sum.v_page_size); 589 #else 590 (void)printf("%9u sequential process pages freed\n", sum.v_seqfree); 591 (void)printf("%9u total reclaims (%d%% fast)\n", sum.v_pgrec, 592 PCT(sum.v_fastpgrec, sum.v_pgrec)); 593 (void)printf("%9u reclaims from free list\n", sum.v_pgfrec); 594 (void)printf("%9u executable fill pages created\n", 595 sum.v_nexfod / CLSIZE); 596 (void)printf("%9u executable fill page faults\n", 597 sum.v_exfod / CLSIZE); 598 (void)printf("%9u swap text pages found in free list\n", 599 sum.v_xsfrec); 600 (void)printf("%9u inode text pages found in free list\n", 601 sum.v_xifrec); 602 (void)printf("%9u file fill pages created\n", sum.v_nvrfod / CLSIZE); 603 (void)printf("%9u file fill page faults\n", sum.v_vrfod / CLSIZE); 604 (void)printf("%9u pages freed by the clock daemon\n", 605 sum.v_dfree / CLSIZE); 606 #endif 607 kread(X_NCHSTATS, &nchstats, sizeof(nchstats)); 608 nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits + 609 nchstats.ncs_badhits + nchstats.ncs_falsehits + 610 nchstats.ncs_miss + nchstats.ncs_long; 611 (void)printf("%9ld total name lookups\n", nchtotal); 612 (void)printf( 613 "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n", 614 "", PCT(nchstats.ncs_goodhits, nchtotal), 615 PCT(nchstats.ncs_neghits, nchtotal), 616 PCT(nchstats.ncs_pass2, nchtotal)); 617 (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "", 618 PCT(nchstats.ncs_badhits, nchtotal), 619 PCT(nchstats.ncs_falsehits, nchtotal), 620 PCT(nchstats.ncs_long, nchtotal)); 621 #ifndef NEWVM 622 kread(X_XSTATS, &xstats, sizeof(xstats)); 623 (void)printf("%9lu total calls to xalloc (cache hits %d%%)\n", 624 xstats.alloc, PCT(xstats.alloc_cachehit, xstats.alloc)); 625 (void)printf("%9s sticky %lu flushed %lu unused %lu\n", "", 626 xstats.alloc_inuse, xstats.alloc_cacheflush, xstats.alloc_unused); 627 (void)printf("%9lu total calls to xfree", xstats.free); 628 (void)printf(" (sticky %lu cached %lu swapped %lu)\n", 629 xstats.free_inuse, xstats.free_cache, xstats.free_cacheswap); 630 #endif 631 #if defined(tahoe) 632 kread(X_CKEYSTATS, &keystats, sizeof(keystats)); 633 (void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n", 634 keystats.ks_allocs, "code cache keys allocated", 635 PCT(keystats.ks_allocfree, keystats.ks_allocs), 636 PCT(keystats.ks_norefs, keystats.ks_allocs), 637 PCT(keystats.ks_taken, keystats.ks_allocs), 638 PCT(keystats.ks_shared, keystats.ks_allocs)); 639 kread(X_DKEYSTATS, &keystats, sizeof(keystats)); 640 (void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n", 641 keystats.ks_allocs, "data cache keys allocated", 642 PCT(keystats.ks_allocfree, keystats.ks_allocs), 643 PCT(keystats.ks_norefs, keystats.ks_allocs), 644 PCT(keystats.ks_taken, keystats.ks_allocs), 645 PCT(keystats.ks_shared, keystats.ks_allocs)); 646 #endif 647 } 648 649 #ifdef notdef 650 void 651 doforkst() 652 { 653 struct forkstat fks; 654 655 kread(X_FORKSTAT, &fks, sizeof(struct forkstat)); 656 (void)printf("%d forks, %d pages, average %.2f\n", 657 fks.cntfork, fks.sizfork, (double)fks.sizfork / fks.cntfork); 658 (void)printf("%d vforks, %d pages, average %.2f\n", 659 fks.cntvfork, fks.sizvfork, (double)fks.sizvfork / fks.cntvfork); 660 } 661 #endif 662 663 void 664 dkstats() 665 { 666 register int dn, state; 667 double etime; 668 long tmp; 669 670 for (dn = 0; dn < dk_ndrive; ++dn) { 671 tmp = cur.xfer[dn]; 672 cur.xfer[dn] -= last.xfer[dn]; 673 last.xfer[dn] = tmp; 674 } 675 etime = 0; 676 for (state = 0; state < CPUSTATES; ++state) { 677 tmp = cur.time[state]; 678 cur.time[state] -= last.time[state]; 679 last.time[state] = tmp; 680 etime += cur.time[state]; 681 } 682 if (etime == 0) 683 etime = 1; 684 etime /= hz; 685 for (dn = 0; dn < dk_ndrive; ++dn) { 686 if (!dr_select[dn]) 687 continue; 688 (void)printf("%2.0f ", cur.xfer[dn] / etime); 689 } 690 } 691 692 void 693 cpustats() 694 { 695 register int state; 696 double pct, total; 697 698 total = 0; 699 for (state = 0; state < CPUSTATES; ++state) 700 total += cur.time[state]; 701 if (total) 702 pct = 100 / total; 703 else 704 pct = 0; 705 (void)printf("%2.0f ", (cur.time[CP_USER] + cur.time[CP_NICE]) * pct); 706 (void)printf("%2.0f ", (cur.time[CP_SYS] + cur.time[CP_INTR]) * pct); 707 (void)printf("%2.0f", cur.time[CP_IDLE] * pct); 708 } 709 710 void 711 dointr() 712 { 713 register long *intrcnt, inttotal, uptime; 714 register int nintr, inamlen; 715 register char *intrname; 716 717 uptime = getuptime(); 718 nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value; 719 inamlen = 720 namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value; 721 intrcnt = malloc((size_t)nintr); 722 intrname = malloc((size_t)inamlen); 723 if (intrcnt == NULL || intrname == NULL) { 724 (void)fprintf(stderr, "vmstat: %s.\n", strerror(errno)); 725 exit(1); 726 } 727 kread(X_INTRCNT, intrcnt, (size_t)nintr); 728 kread(X_INTRNAMES, intrname, (size_t)inamlen); 729 (void)printf("interrupt total rate\n"); 730 inttotal = 0; 731 nintr /= sizeof(long); 732 while (--nintr >= 0) { 733 if (*intrcnt) 734 (void)printf("%-12s %8ld %8ld\n", intrname, 735 *intrcnt, *intrcnt / uptime); 736 intrname += strlen(intrname) + 1; 737 inttotal += *intrcnt++; 738 } 739 (void)printf("Total %8ld %8ld\n", inttotal, inttotal / uptime); 740 } 741 742 /* 743 * These names are defined in <sys/malloc.h>. 744 */ 745 char *kmemnames[] = INITKMEMNAMES; 746 747 void 748 domem() 749 { 750 register struct kmembuckets *kp; 751 register struct kmemstats *ks; 752 register int i, j; 753 int len, size, first; 754 long totuse = 0, totfree = 0, totreq = 0; 755 char *name; 756 struct kmemstats kmemstats[M_LAST]; 757 struct kmembuckets buckets[MINBUCKET + 16]; 758 759 kread(X_KMEMBUCKETS, buckets, sizeof(buckets)); 760 (void)printf("Memory statistics by bucket size\n"); 761 (void)printf( 762 " Size In Use Free Requests HighWater Couldfree\n"); 763 for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) { 764 if (kp->kb_calls == 0) 765 continue; 766 size = 1 << i; 767 (void)printf("%8d %8ld %6ld %10ld %7ld %10ld\n", size, 768 kp->kb_total - kp->kb_totalfree, 769 kp->kb_totalfree, kp->kb_calls, 770 kp->kb_highwat, kp->kb_couldfree); 771 totfree += size * kp->kb_totalfree; 772 } 773 774 kread(X_KMEMSTAT, kmemstats, sizeof(kmemstats)); 775 (void)printf("\nMemory usage type by bucket size\n"); 776 (void)printf(" Size Type(s)\n"); 777 kp = &buckets[MINBUCKET]; 778 for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) { 779 if (kp->kb_calls == 0) 780 continue; 781 first = 1; 782 len = 8; 783 for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) { 784 if (ks->ks_calls == 0) 785 continue; 786 if ((ks->ks_size & j) == 0) 787 continue; 788 name = kmemnames[i] ? kmemnames[i] : "undefined"; 789 len += 2 + strlen(name); 790 if (first) 791 printf("%8d %s", j, name); 792 else 793 printf(","); 794 if (len >= 80) { 795 printf("\n\t "); 796 len = 10 + strlen(name); 797 } 798 if (!first) 799 printf(" %s", name); 800 first = 0; 801 } 802 printf("\n"); 803 } 804 805 (void)printf( 806 "\nMemory statistics by type Type Kern\n"); 807 (void)printf( 808 " Type InUse MemUse HighUse Limit Requests Limit Limit Size(s)\n"); 809 for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) { 810 if (ks->ks_calls == 0) 811 continue; 812 (void)printf("%11s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u", 813 kmemnames[i] ? kmemnames[i] : "undefined", 814 ks->ks_inuse, (ks->ks_memuse + 1023) / 1024, 815 (ks->ks_maxused + 1023) / 1024, 816 (ks->ks_limit + 1023) / 1024, ks->ks_calls, 817 ks->ks_limblocks, ks->ks_mapblocks); 818 first = 1; 819 for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) { 820 if ((ks->ks_size & j) == 0) 821 continue; 822 if (first) 823 printf(" %d", j); 824 else 825 printf(",%d", j); 826 first = 0; 827 } 828 printf("\n"); 829 totuse += ks->ks_memuse; 830 totreq += ks->ks_calls; 831 } 832 (void)printf("\nMemory Totals: In Use Free Requests\n"); 833 (void)printf(" %7ldK %6ldK %8ld\n", 834 (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq); 835 } 836 837 /* 838 * kread reads something from the kernel, given its nlist index. 839 */ 840 void 841 kread(nlx, addr, size) 842 int nlx; 843 void *addr; 844 size_t size; 845 { 846 char *sym; 847 848 if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) { 849 sym = namelist[nlx].n_name; 850 if (*sym == '_') 851 ++sym; 852 (void)fprintf(stderr, 853 "vmstat: symbol %s not defined\n", sym); 854 exit(1); 855 } 856 if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) { 857 sym = namelist[nlx].n_name; 858 if (*sym == '_') 859 ++sym; 860 (void)fprintf(stderr, "vmstat: %s: %s\n", sym, kvm_geterr(kd)); 861 exit(1); 862 } 863 } 864 865 void 866 usage() 867 { 868 (void)fprintf(stderr, 869 #ifndef NEWVM 870 "usage: vmstat [-fimst] [-c count] [-M core] \ 871 [-N system] [-w wait] [disks]\n"); 872 #else 873 "usage: vmstat [-ims] [-c count] [-M core] \ 874 [-N system] [-w wait] [disks]\n"); 875 #endif 876 exit(1); 877 } 878