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