vmstat.c revision 1.204
1/* $NetBSD: vmstat.c,v 1.204 2014/09/12 16:25:29 skrll Exp $ */ 2 3/*- 4 * Copyright (c) 1998, 2000, 2001, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation by: 8 * - Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * - Simon Burge and Luke Mewburn of Wasabi Systems, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34/* 35 * Copyright (c) 1980, 1986, 1991, 1993 36 * The Regents of the University of California. All rights reserved. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. Neither the name of the University nor the names of its contributors 47 * may be used to endorse or promote products derived from this software 48 * without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60 * SUCH DAMAGE. 61 */ 62 63#include <sys/cdefs.h> 64#ifndef lint 65__COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1991, 1993\ 66 The Regents of the University of California. All rights reserved."); 67#endif /* not lint */ 68 69#ifndef lint 70#if 0 71static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95"; 72#else 73__RCSID("$NetBSD: vmstat.c,v 1.204 2014/09/12 16:25:29 skrll Exp $"); 74#endif 75#endif /* not lint */ 76 77#define __POOL_EXPOSE 78 79#include <sys/param.h> 80#include <sys/types.h> 81#include <sys/mount.h> 82#include <sys/uio.h> 83 84#include <sys/buf.h> 85#include <sys/evcnt.h> 86#include <sys/ioctl.h> 87#include <sys/malloc.h> 88#include <sys/mallocvar.h> 89#include <sys/namei.h> 90#include <sys/pool.h> 91#include <sys/proc.h> 92#include <sys/sched.h> 93#include <sys/socket.h> 94#include <sys/sysctl.h> 95#include <sys/time.h> 96#include <sys/queue.h> 97#include <sys/kernhist.h> 98 99#include <uvm/uvm_extern.h> 100#include <uvm/uvm_stat.h> 101 102#include <net/if.h> 103#include <netinet/in.h> 104#include <netinet/in_var.h> 105 106#include <ufs/ufs/inode.h> 107 108#include <nfs/rpcv2.h> 109#include <nfs/nfsproto.h> 110#include <nfs/nfsnode.h> 111 112#include <ctype.h> 113#include <err.h> 114#include <errno.h> 115#include <fcntl.h> 116#include <kvm.h> 117#include <limits.h> 118#include <nlist.h> 119#undef n_hash 120#include <paths.h> 121#include <signal.h> 122#include <stdio.h> 123#include <stddef.h> 124#include <stdlib.h> 125#include <string.h> 126#include <time.h> 127#include <unistd.h> 128#include <util.h> 129 130#include "drvstats.h" 131 132/* 133 * All this mess will go away once everything is converted. 134 */ 135#ifdef __HAVE_CPU_DATA_FIRST 136 137# include <sys/cpu_data.h> 138struct cpu_info { 139 struct cpu_data ci_data; 140}; 141#else 142# include <sys/cpu.h> 143#endif 144 145/* 146 * General namelist 147 */ 148struct nlist namelist[] = 149{ 150#define X_BOOTTIME 0 151 { .n_name = "_boottime" }, 152#define X_HZ 1 153 { .n_name = "_hz" }, 154#define X_STATHZ 2 155 { .n_name = "_stathz" }, 156#define X_NCHSTATS 3 157 { .n_name = "_nchstats" }, 158#define X_ALLEVENTS 4 159 { .n_name = "_allevents" }, 160#define X_POOLHEAD 5 161 { .n_name = "_pool_head" }, 162#define X_UVMEXP 6 163 { .n_name = "_uvmexp" }, 164#define X_TIME_SECOND 7 165 { .n_name = "_time_second" }, 166#define X_TIME 8 167 { .n_name = "_time" }, 168#define X_CPU_INFOS 9 169 { .n_name = "_cpu_infos" }, 170#define X_NL_SIZE 10 171 { .n_name = NULL }, 172}; 173 174/* 175 * Namelist for pre-evcnt interrupt counters. 176 */ 177struct nlist intrnl[] = 178{ 179#define X_INTRNAMES 0 180 { .n_name = "_intrnames" }, 181#define X_EINTRNAMES 1 182 { .n_name = "_eintrnames" }, 183#define X_INTRCNT 2 184 { .n_name = "_intrcnt" }, 185#define X_EINTRCNT 3 186 { .n_name = "_eintrcnt" }, 187#define X_INTRNL_SIZE 4 188 { .n_name = NULL }, 189}; 190 191 192/* 193 * Namelist for hash statistics 194 */ 195struct nlist hashnl[] = 196{ 197#define X_NFSNODE 0 198 { .n_name = "_nfsnodehash" }, 199#define X_NFSNODETBL 1 200 { .n_name = "_nfsnodehashtbl" }, 201#define X_IHASH 2 202 { .n_name = "_ihash" }, 203#define X_IHASHTBL 3 204 { .n_name = "_ihashtbl" }, 205#define X_BUFHASH 4 206 { .n_name = "_bufhash" }, 207#define X_BUFHASHTBL 5 208 { .n_name = "_bufhashtbl" }, 209#define X_UIHASH 6 210 { .n_name = "_uihash" }, 211#define X_UIHASHTBL 7 212 { .n_name = "_uihashtbl" }, 213#define X_IFADDRHASH 8 214 { .n_name = "_in_ifaddrhash" }, 215#define X_IFADDRHASHTBL 9 216 { .n_name = "_in_ifaddrhashtbl" }, 217#define X_NCHASH 10 218 { .n_name = "_nchash" }, 219#define X_NCHASHTBL 11 220 { .n_name = "_nchashtbl" }, 221#define X_NCVHASH 12 222 { .n_name = "_ncvhash" }, 223#define X_NCVHASHTBL 13 224 { .n_name = "_ncvhashtbl" }, 225#define X_HASHNL_SIZE 14 /* must be last */ 226 { .n_name = NULL }, 227}; 228 229/* 230 * Namelist for kernel histories 231 */ 232struct nlist histnl[] = 233{ 234 { .n_name = "_kern_histories" }, 235#define X_KERN_HISTORIES 0 236 { .n_name = NULL }, 237}; 238 239 240#define KILO 1024 241 242struct cpu_counter { 243 uint64_t nintr; 244 uint64_t nsyscall; 245 uint64_t nswtch; 246 uint64_t nfault; 247 uint64_t ntrap; 248 uint64_t nsoft; 249} cpucounter, ocpucounter; 250 251struct uvmexp_sysctl uvmexp, ouvmexp; 252int ndrives; 253 254int winlines = 20; 255 256kvm_t *kd; 257 258 259#define FORKSTAT 0x001 260#define INTRSTAT 0x002 261#define MEMSTAT 0x004 262#define SUMSTAT 0x008 263#define EVCNTSTAT 0x010 264#define VMSTAT 0x020 265#define HISTLIST 0x040 266#define HISTDUMP 0x080 267#define HASHSTAT 0x100 268#define HASHLIST 0x200 269#define VMTOTAL 0x400 270#define POOLCACHESTAT 0x800 271 272/* 273 * Print single word. `ovflow' is number of characters didn't fit 274 * on the last word. `fmt' is a format string to print this word. 275 * It must contain asterisk for field width. `width' is a width 276 * occupied by this word. `fixed' is a number of constant chars in 277 * `fmt'. `val' is a value to be printed using format string `fmt'. 278 */ 279#define PRWORD(ovflw, fmt, width, fixed, val) do { \ 280 (ovflw) += printf((fmt), \ 281 (width) - (fixed) - (ovflw) > 0 ? \ 282 (width) - (fixed) - (ovflw) : 0, \ 283 (val)) - (width); \ 284 if ((ovflw) < 0) \ 285 (ovflw) = 0; \ 286} while (/* CONSTCOND */0) 287 288void cpustats(int *); 289void cpucounters(struct cpu_counter *); 290void deref_kptr(const void *, void *, size_t, const char *); 291void drvstats(int *); 292void doevcnt(int verbose, int type); 293void dohashstat(int, int, const char *); 294void dointr(int verbose); 295void dopool(int, int); 296void dopoolcache(int); 297void dosum(void); 298void dovmstat(struct timespec *, int); 299void print_total_hdr(void); 300void dovmtotal(struct timespec *, int); 301void kread(struct nlist *, int, void *, size_t); 302int kreadc(struct nlist *, int, void *, size_t); 303void needhdr(int); 304void getnlist(int); 305long getuptime(void); 306void printhdr(void); 307long pct(u_long, u_long); 308__dead static void usage(void); 309void doforkst(void); 310 311void hist_traverse(int, const char *); 312void hist_dodump(struct kern_history *); 313 314int main(int, char **); 315char **choosedrives(char **); 316 317/* Namelist and memory file names. */ 318char *nlistf, *memf; 319 320/* allow old usage [vmstat 1] */ 321#define BACKWARD_COMPATIBILITY 322 323static const int clockrate_mib[] = { CTL_KERN, KERN_CLOCKRATE }; 324static const int vmmeter_mib[] = { CTL_VM, VM_METER }; 325static const int uvmexp2_mib[] = { CTL_VM, VM_UVMEXP2 }; 326static const int boottime_mib[] = { CTL_KERN, KERN_BOOTTIME }; 327static char kvm_errbuf[_POSIX2_LINE_MAX]; 328 329int 330main(int argc, char *argv[]) 331{ 332 int c, todo, verbose, wide; 333 struct timespec interval; 334 int reps; 335 gid_t egid = getegid(); 336 const char *histname, *hashname; 337 338 histname = hashname = NULL; 339 (void)setegid(getgid()); 340 memf = nlistf = NULL; 341 reps = todo = verbose = wide = 0; 342 interval.tv_sec = 0; 343 interval.tv_nsec = 0; 344 while ((c = getopt(argc, argv, "Cc:efh:HilLM:mN:stu:UvWw:")) != -1) { 345 switch (c) { 346 case 'c': 347 reps = atoi(optarg); 348 break; 349 case 'C': 350 todo |= POOLCACHESTAT; 351 break; 352 case 'e': 353 todo |= EVCNTSTAT; 354 break; 355 case 'f': 356 todo |= FORKSTAT; 357 break; 358 case 'h': 359 hashname = optarg; 360 /* FALLTHROUGH */ 361 case 'H': 362 todo |= HASHSTAT; 363 break; 364 case 'i': 365 todo |= INTRSTAT; 366 break; 367 case 'l': 368 todo |= HISTLIST; 369 break; 370 case 'L': 371 todo |= HASHLIST; 372 break; 373 case 'M': 374 memf = optarg; 375 break; 376 case 'm': 377 todo |= MEMSTAT; 378 break; 379 case 'N': 380 nlistf = optarg; 381 break; 382 case 's': 383 todo |= SUMSTAT; 384 break; 385 case 't': 386 todo |= VMTOTAL; 387 break; 388 case 'u': 389 histname = optarg; 390 /* FALLTHROUGH */ 391 case 'U': 392 todo |= HISTDUMP; 393 break; 394 case 'v': 395 verbose++; 396 break; 397 case 'W': 398 wide++; 399 break; 400 case 'w': 401 interval.tv_sec = atol(optarg); 402 break; 403 case '?': 404 default: 405 usage(); 406 } 407 } 408 argc -= optind; 409 argv += optind; 410 411 if (todo == 0) 412 todo = VMSTAT; 413 414 /* 415 * Discard setgid privileges. If not the running kernel, we toss 416 * them away totally so that bad guys can't print interesting stuff 417 * from kernel memory, otherwise switch back to kmem for the 418 * duration of the kvm_openfiles() call. 419 */ 420 if (nlistf != NULL || memf != NULL) 421 (void)setgid(getgid()); 422 else 423 (void)setegid(egid); 424 425 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, kvm_errbuf); 426 if (kd == NULL) { 427 if (nlistf != NULL || memf != NULL) { 428 errx(1, "kvm_openfiles: %s", kvm_errbuf); 429 } 430 } 431 432 if (nlistf == NULL && memf == NULL) 433 (void)setgid(getgid()); 434 435 436 if (todo & VMSTAT) { 437 struct winsize winsize; 438 439 (void)drvinit(0);/* Initialize disk stats, no disks selected. */ 440 441 (void)setgid(getgid()); /* don't need privs anymore */ 442 443 argv = choosedrives(argv); /* Select disks. */ 444 winsize.ws_row = 0; 445 (void)ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize); 446 if (winsize.ws_row > 0) 447 winlines = winsize.ws_row; 448 449 } 450 451#ifdef BACKWARD_COMPATIBILITY 452 if (*argv) { 453 interval.tv_sec = atol(*argv); 454 if (*++argv) 455 reps = atoi(*argv); 456 } 457#endif 458 459 if (interval.tv_sec) { 460 if (!reps) 461 reps = -1; 462 } else if (reps) 463 interval.tv_sec = 1; 464 465 466 getnlist(todo); 467 /* 468 * Statistics dumping is incompatible with the default 469 * VMSTAT/dovmstat() output. So perform the interval/reps handling 470 * for it here. 471 */ 472 if ((todo & (VMSTAT|VMTOTAL)) == 0) { 473 for (;;) { 474 if (todo & (HISTLIST|HISTDUMP)) { 475 if ((todo & (HISTLIST|HISTDUMP)) == 476 (HISTLIST|HISTDUMP)) 477 errx(1, "you may list or dump," 478 " but not both!"); 479 hist_traverse(todo, histname); 480 (void)putchar('\n'); 481 } 482 if (todo & FORKSTAT) { 483 doforkst(); 484 (void)putchar('\n'); 485 } 486 if (todo & MEMSTAT) { 487 dopool(verbose, wide); 488 (void)putchar('\n'); 489 } 490 if (todo & POOLCACHESTAT) { 491 dopoolcache(verbose); 492 (void)putchar('\n'); 493 } 494 if (todo & SUMSTAT) { 495 dosum(); 496 (void)putchar('\n'); 497 } 498 if (todo & INTRSTAT) { 499 dointr(verbose); 500 (void)putchar('\n'); 501 } 502 if (todo & EVCNTSTAT) { 503 doevcnt(verbose, EVCNT_TYPE_ANY); 504 (void)putchar('\n'); 505 } 506 if (todo & (HASHLIST|HASHSTAT)) { 507 if ((todo & (HASHLIST|HASHSTAT)) == 508 (HASHLIST|HASHSTAT)) 509 errx(1, "you may list or display," 510 " but not both!"); 511 dohashstat(verbose, todo, hashname); 512 (void)putchar('\n'); 513 } 514 515 fflush(stdout); 516 if (reps >= 0 && --reps <=0) 517 break; 518 (void)nanosleep(&interval, NULL); 519 } 520 } else { 521 if ((todo & (VMSTAT|VMTOTAL)) == (VMSTAT|VMTOTAL)) { 522 errx(1, "you may not both do vmstat and vmtotal"); 523 } 524 if (todo & VMSTAT) 525 dovmstat(&interval, reps); 526 if (todo & VMTOTAL) 527 dovmtotal(&interval, reps); 528 } 529 return 0; 530} 531 532void 533getnlist(int todo) 534{ 535 static int namelist_done = 0; 536 static int done = 0; 537 int c; 538 size_t i; 539 540 if (kd == NULL) 541 errx(1, "kvm_openfiles: %s", kvm_errbuf); 542 543 if (!namelist_done) { 544 namelist_done = 1; 545 if ((c = kvm_nlist(kd, namelist)) != 0) { 546 int doexit = 0; 547 if (c == -1) 548 errx(1, "kvm_nlist: %s %s", 549 "namelist", kvm_geterr(kd)); 550 for (i = 0; i < __arraycount(namelist)-1; i++) 551 if (namelist[i].n_type == 0 && 552 i != X_TIME_SECOND && 553 i != X_TIME) { 554 if (doexit++ == 0) 555 (void)fprintf(stderr, 556 "%s: undefined symbols:", 557 getprogname()); 558 (void)fprintf(stderr, " %s", 559 namelist[i].n_name); 560 } 561 if (doexit) { 562 (void)fputc('\n', stderr); 563 exit(1); 564 } 565 } 566 } 567 if ((todo & (SUMSTAT|INTRSTAT)) && !(done & (SUMSTAT|INTRSTAT))) { 568 done |= SUMSTAT|INTRSTAT; 569 (void) kvm_nlist(kd, intrnl); 570 } 571 if ((todo & (HASHLIST|HASHSTAT)) && !(done & (HASHLIST|HASHSTAT))) { 572 done |= HASHLIST|HASHSTAT; 573 if ((c = kvm_nlist(kd, hashnl)) == -1 || c == X_HASHNL_SIZE) 574 errx(1, "kvm_nlist: %s %s", "hashnl", kvm_geterr(kd)); 575 } 576 if ((todo & (HISTLIST|HISTDUMP)) && !(done & (HISTLIST|HISTDUMP))) { 577 done |= HISTLIST|HISTDUMP; 578 if (kvm_nlist(kd, histnl) == -1) 579 errx(1, "kvm_nlist: %s %s", "histnl", kvm_geterr(kd)); 580 } 581} 582 583char ** 584choosedrives(char **argv) 585{ 586 size_t i; 587 588 /* 589 * Choose drives to be displayed. Priority goes to (in order) drives 590 * supplied as arguments, default drives. If everything isn't filled 591 * in and there are drives not taken care of, display the first few 592 * that fit. 593 */ 594#define BACKWARD_COMPATIBILITY 595 for (ndrives = 0; *argv; ++argv) { 596#ifdef BACKWARD_COMPATIBILITY 597 if (isdigit((unsigned char)**argv)) 598 break; 599#endif 600 for (i = 0; i < ndrive; i++) { 601 if (strcmp(dr_name[i], *argv)) 602 continue; 603 drv_select[i] = 1; 604 ++ndrives; 605 break; 606 } 607 } 608 for (i = 0; i < ndrive && ndrives < 2; i++) { 609 if (drv_select[i]) 610 continue; 611 drv_select[i] = 1; 612 ++ndrives; 613 } 614 615 return (argv); 616} 617 618long 619getuptime(void) 620{ 621 static struct timespec boottime; 622 struct timespec now; 623 time_t uptime, nowsec; 624 625 if (memf == NULL) { 626 if (boottime.tv_sec == 0) { 627 size_t buflen = sizeof(boottime); 628 if (sysctl(boottime_mib, __arraycount(boottime_mib), 629 &boottime, &buflen, NULL, 0) == -1) 630 warn("Can't get boottime"); 631 } 632 clock_gettime(CLOCK_REALTIME, &now); 633 } else { 634 if (boottime.tv_sec == 0) 635 kread(namelist, X_BOOTTIME, &boottime, 636 sizeof(boottime)); 637 if (kreadc(namelist, X_TIME_SECOND, &nowsec, sizeof(nowsec))) { 638 /* 639 * XXX this assignment dance can be removed once 640 * timeval tv_sec is SUS mandated time_t 641 */ 642 now.tv_sec = nowsec; 643 now.tv_nsec = 0; 644 } else { 645 kread(namelist, X_TIME, &now, sizeof(now)); 646 } 647 } 648 uptime = now.tv_sec - boottime.tv_sec; 649 if (uptime <= 0 || uptime > 60*60*24*365*10) 650 errx(1, "time makes no sense; namelist must be wrong."); 651 return (uptime); 652} 653 654int hz, hdrcnt; 655 656void 657print_total_hdr(void) 658{ 659 660 (void)printf("procs memory\n"); 661 (void)printf("ru dw pw sl"); 662 (void)printf(" total-v active-v active-r"); 663 (void)printf(" vm-sh avm-sh rm-sh arm-sh free\n"); 664 hdrcnt = winlines - 2; 665} 666 667void 668dovmtotal(struct timespec *interval, int reps) 669{ 670 struct vmtotal total; 671 size_t size; 672 673 (void)signal(SIGCONT, needhdr); 674 675 for (hdrcnt = 1;;) { 676 if (!--hdrcnt) 677 print_total_hdr(); 678 if (memf != NULL) { 679 warnx("Unable to get vmtotals from crash dump."); 680 (void)memset(&total, 0, sizeof(total)); 681 } else { 682 size = sizeof(total); 683 if (sysctl(vmmeter_mib, __arraycount(vmmeter_mib), 684 &total, &size, NULL, 0) == -1) { 685 warn("Can't get vmtotals"); 686 (void)memset(&total, 0, sizeof(total)); 687 } 688 } 689 (void)printf("%2d ", total.t_rq); 690 (void)printf("%2d ", total.t_dw); 691 (void)printf("%2d ", total.t_pw); 692 (void)printf("%2d ", total.t_sl); 693 694 (void)printf("%9d ", total.t_vm); 695 (void)printf("%9d ", total.t_avm); 696 (void)printf("%9d ", total.t_arm); 697 (void)printf("%5d ", total.t_vmshr); 698 (void)printf("%6d ", total.t_avmshr); 699 (void)printf("%5d ", total.t_rmshr); 700 (void)printf("%6d ", total.t_armshr); 701 (void)printf("%5d", total.t_free); 702 703 (void)putchar('\n'); 704 705 (void)fflush(stdout); 706 if (reps >= 0 && --reps <= 0) 707 break; 708 709 (void)nanosleep(interval, NULL); 710 } 711} 712 713void 714dovmstat(struct timespec *interval, int reps) 715{ 716 struct vmtotal total; 717 time_t uptime, halfuptime; 718 size_t size; 719 int pagesize = getpagesize(); 720 int ovflw; 721 722 uptime = getuptime(); 723 halfuptime = uptime / 2; 724 (void)signal(SIGCONT, needhdr); 725 726 if (memf != NULL) { 727 if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0) 728 kread(namelist, X_STATHZ, &hz, sizeof(hz)); 729 if (!hz) 730 kread(namelist, X_HZ, &hz, sizeof(hz)); 731 } else { 732 struct clockinfo clockinfo; 733 size = sizeof(clockinfo); 734 if (sysctl(clockrate_mib, 2, &clockinfo, &size, NULL, 0) == -1) 735 err(1, "sysctl kern.clockrate failed"); 736 hz = clockinfo.stathz; 737 if (!hz) 738 hz = clockinfo.hz; 739 } 740 741 for (hdrcnt = 1;;) { 742 if (!--hdrcnt) 743 printhdr(); 744 /* Read new disk statistics */ 745 cpureadstats(); 746 drvreadstats(); 747 tkreadstats(); 748 if (memf != NULL) { 749 struct uvmexp uvmexp_kernel; 750 /* 751 * XXX Can't do this if we're reading a crash 752 * XXX dump because they're lazily-calculated. 753 */ 754 warnx("Unable to get vmtotals from crash dump."); 755 (void)memset(&total, 0, sizeof(total)); 756 kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel)); 757#define COPY(field) uvmexp.field = uvmexp_kernel.field 758 COPY(pdreact); 759 COPY(pageins); 760 COPY(pgswapout); 761 COPY(pdfreed); 762 COPY(pdscans); 763#undef COPY 764 } else { 765 size = sizeof(total); 766 if (sysctl(vmmeter_mib, __arraycount(vmmeter_mib), 767 &total, &size, NULL, 0) == -1) { 768 warn("Can't get vmtotals"); 769 (void)memset(&total, 0, sizeof(total)); 770 } 771 size = sizeof(uvmexp); 772 if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp, 773 &size, NULL, 0) == -1) 774 warn("sysctl vm.uvmexp2 failed"); 775 } 776 cpucounters(&cpucounter); 777 ovflw = 0; 778 PRWORD(ovflw, " %*d", 2, 1, total.t_rq - 1); 779 PRWORD(ovflw, " %*d", 2, 1, total.t_dw + total.t_pw); 780#define pgtok(a) (long)((a) * ((uint32_t)pagesize >> 10)) 781#define rate(x) (u_long)(((x) + halfuptime) / uptime) /* round */ 782 PRWORD(ovflw, " %*ld", 9, 1, pgtok(total.t_avm)); 783 PRWORD(ovflw, " %*ld", 7, 1, pgtok(total.t_free)); 784 PRWORD(ovflw, " %*ld", 5, 1, 785 rate(cpucounter.nfault - ocpucounter.nfault)); 786 PRWORD(ovflw, " %*ld", 4, 1, 787 rate(uvmexp.pdreact - ouvmexp.pdreact)); 788 PRWORD(ovflw, " %*ld", 4, 1, 789 rate(uvmexp.pageins - ouvmexp.pageins)); 790 PRWORD(ovflw, " %*ld", 5, 1, 791 rate(uvmexp.pgswapout - ouvmexp.pgswapout)); 792 PRWORD(ovflw, " %*ld", 5, 1, 793 rate(uvmexp.pdfreed - ouvmexp.pdfreed)); 794 PRWORD(ovflw, " %*ld", 6, 2, 795 rate(uvmexp.pdscans - ouvmexp.pdscans)); 796 drvstats(&ovflw); 797 PRWORD(ovflw, " %*ld", 5, 1, 798 rate(cpucounter.nintr - ocpucounter.nintr)); 799 PRWORD(ovflw, " %*ld", 5, 1, 800 rate(cpucounter.nsyscall - ocpucounter.nsyscall)); 801 PRWORD(ovflw, " %*ld", 4, 1, 802 rate(cpucounter.nswtch - ocpucounter.nswtch)); 803 cpustats(&ovflw); 804 (void)putchar('\n'); 805 (void)fflush(stdout); 806 if (reps >= 0 && --reps <= 0) 807 break; 808 ouvmexp = uvmexp; 809 ocpucounter = cpucounter; 810 uptime = interval->tv_sec; 811 /* 812 * We round upward to avoid losing low-frequency events 813 * (i.e., >= 1 per interval but < 1 per second). 814 */ 815 halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2; 816 (void)nanosleep(interval, NULL); 817 } 818} 819 820void 821printhdr(void) 822{ 823 size_t i; 824 825 (void)printf(" procs memory page%*s", 23, ""); 826 if (ndrives > 0) 827 (void)printf("%s %*sfaults cpu\n", 828 ((ndrives > 1) ? "disks" : "disk"), 829 ((ndrives > 1) ? ndrives * 3 - 4 : 0), ""); 830 else 831 (void)printf("%*s faults cpu\n", 832 ndrives * 3, ""); 833 834 (void)printf(" r b avm fre flt re pi po fr sr "); 835 for (i = 0; i < ndrive; i++) 836 if (drv_select[i]) 837 (void)printf("%c%c ", dr_name[i][0], 838 dr_name[i][strlen(dr_name[i]) - 1]); 839 (void)printf(" in sy cs us sy id\n"); 840 hdrcnt = winlines - 2; 841} 842 843/* 844 * Force a header to be prepended to the next output. 845 */ 846void 847/*ARGSUSED*/ 848needhdr(int dummy) 849{ 850 851 hdrcnt = 1; 852} 853 854long 855pct(u_long top, u_long bot) 856{ 857 long ans; 858 859 if (bot == 0) 860 return (0); 861 ans = (long)((quad_t)top * 100 / bot); 862 return (ans); 863} 864 865#define PCT(top, bot) (int)pct((u_long)(top), (u_long)(bot)) 866 867void 868dosum(void) 869{ 870 struct nchstats_sysctl nch_stats; 871 uint64_t nchtotal; 872 size_t ssize; 873 int active_kernel; 874 struct cpu_counter cc; 875 876 /* 877 * The "active" and "inactive" variables 878 * are now estimated by the kernel and sadly 879 * can not easily be dug out of a crash dump. 880 */ 881 ssize = sizeof(uvmexp); 882 memset(&uvmexp, 0, ssize); 883 active_kernel = (memf == NULL); 884 if (active_kernel) { 885 /* only on active kernel */ 886 if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp, 887 &ssize, NULL, 0) == -1) 888 warn("sysctl vm.uvmexp2 failed"); 889 } else { 890 struct uvmexp uvmexp_kernel; 891 kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel)); 892#define COPY(field) uvmexp.field = uvmexp_kernel.field 893 COPY(pagesize); 894 COPY(ncolors); 895 COPY(npages); 896 COPY(free); 897 COPY(paging); 898 COPY(wired); 899 COPY(zeropages); 900 COPY(reserve_pagedaemon); 901 COPY(reserve_kernel); 902 COPY(anonpages); 903 COPY(filepages); 904 COPY(execpages); 905 COPY(freemin); 906 COPY(freetarg); 907 COPY(wiredmax); 908 COPY(nswapdev); 909 COPY(swpages); 910 COPY(swpginuse); 911 COPY(nswget); 912 COPY(pageins); 913 COPY(pdpageouts); 914 COPY(pgswapin); 915 COPY(pgswapout); 916 COPY(forks); 917 COPY(forks_ppwait); 918 COPY(forks_sharevm); 919 COPY(pga_zerohit); 920 COPY(pga_zeromiss); 921 COPY(zeroaborts); 922 COPY(colorhit); 923 COPY(colormiss); 924 COPY(cpuhit); 925 COPY(cpumiss); 926 COPY(fltnoram); 927 COPY(fltnoanon); 928 COPY(fltpgwait); 929 COPY(fltpgrele); 930 COPY(fltrelck); 931 COPY(fltrelckok); 932 COPY(fltanget); 933 COPY(fltanretry); 934 COPY(fltamcopy); 935 COPY(fltamcopy); 936 COPY(fltnomap); 937 COPY(fltlget); 938 COPY(fltget); 939 COPY(flt_anon); 940 COPY(flt_acow); 941 COPY(flt_obj); 942 COPY(flt_prcopy); 943 COPY(flt_przero); 944 COPY(pdwoke); 945 COPY(pdrevs); 946 COPY(pdfreed); 947 COPY(pdscans); 948 COPY(pdanscan); 949 COPY(pdobscan); 950 COPY(pdreact); 951 COPY(pdbusy); 952 COPY(pdpending); 953 COPY(pddeact); 954#undef COPY 955 } 956 957 958 (void)printf("%9" PRIu64 " bytes per page\n", uvmexp.pagesize); 959 960 (void)printf("%9" PRIu64 " page color%s\n", 961 uvmexp.ncolors, uvmexp.ncolors == 1 ? "" : "s"); 962 963 (void)printf("%9" PRIu64 " pages managed\n", uvmexp.npages); 964 (void)printf("%9" PRIu64 " pages free\n", uvmexp.free); 965 if (active_kernel) { 966 (void)printf("%9" PRIu64 " pages active\n", uvmexp.active); 967 (void)printf("%9" PRIu64 " pages inactive\n", uvmexp.inactive); 968 } 969 (void)printf("%9" PRIu64 " pages paging\n", uvmexp.paging); 970 (void)printf("%9" PRIu64 " pages wired\n", uvmexp.wired); 971 (void)printf("%9" PRIu64 " zero pages\n", uvmexp.zeropages); 972 (void)printf("%9" PRIu64 " reserve pagedaemon pages\n", 973 uvmexp.reserve_pagedaemon); 974 (void)printf("%9" PRIu64 " reserve kernel pages\n", uvmexp.reserve_kernel); 975 (void)printf("%9" PRIu64 " anonymous pages\n", uvmexp.anonpages); 976 (void)printf("%9" PRIu64 " cached file pages\n", uvmexp.filepages); 977 (void)printf("%9" PRIu64 " cached executable pages\n", uvmexp.execpages); 978 979 (void)printf("%9" PRIu64 " minimum free pages\n", uvmexp.freemin); 980 (void)printf("%9" PRIu64 " target free pages\n", uvmexp.freetarg); 981 (void)printf("%9" PRIu64 " maximum wired pages\n", uvmexp.wiredmax); 982 983 (void)printf("%9" PRIu64 " swap devices\n", uvmexp.nswapdev); 984 (void)printf("%9" PRIu64 " swap pages\n", uvmexp.swpages); 985 (void)printf("%9" PRIu64 " swap pages in use\n", uvmexp.swpginuse); 986 (void)printf("%9" PRIu64 " swap allocations\n", uvmexp.nswget); 987 988 cpucounters(&cc); 989 990 (void)printf("%9" PRIu64 " total faults taken\n", cc.nfault); 991 (void)printf("%9" PRIu64 " traps\n", cc.ntrap); 992 (void)printf("%9" PRIu64 " device interrupts\n", cc.nintr); 993 (void)printf("%9" PRIu64 " CPU context switches\n", cc.nswtch); 994 (void)printf("%9" PRIu64 " software interrupts\n", cc.nsoft); 995 (void)printf("%9" PRIu64 " system calls\n", cc.nsyscall); 996 (void)printf("%9" PRIu64 " pagein requests\n", uvmexp.pageins); 997 (void)printf("%9" PRIu64 " pageout requests\n", uvmexp.pdpageouts); 998 (void)printf("%9" PRIu64 " pages swapped in\n", uvmexp.pgswapin); 999 (void)printf("%9" PRIu64 " pages swapped out\n", uvmexp.pgswapout); 1000 (void)printf("%9" PRIu64 " forks total\n", uvmexp.forks); 1001 (void)printf("%9" PRIu64 " forks blocked parent\n", uvmexp.forks_ppwait); 1002 (void)printf("%9" PRIu64 " forks shared address space with parent\n", 1003 uvmexp.forks_sharevm); 1004 (void)printf("%9" PRIu64 " pagealloc zero wanted and avail\n", 1005 uvmexp.pga_zerohit); 1006 (void)printf("%9" PRIu64 " pagealloc zero wanted and not avail\n", 1007 uvmexp.pga_zeromiss); 1008 (void)printf("%9" PRIu64 " aborts of idle page zeroing\n", 1009 uvmexp.zeroaborts); 1010 (void)printf("%9" PRIu64 " pagealloc desired color avail\n", 1011 uvmexp.colorhit); 1012 (void)printf("%9" PRIu64 " pagealloc desired color not avail\n", 1013 uvmexp.colormiss); 1014 (void)printf("%9" PRIu64 " pagealloc local cpu avail\n", 1015 uvmexp.cpuhit); 1016 (void)printf("%9" PRIu64 " pagealloc local cpu not avail\n", 1017 uvmexp.cpumiss); 1018 1019 (void)printf("%9" PRIu64 " faults with no memory\n", uvmexp.fltnoram); 1020 (void)printf("%9" PRIu64 " faults with no anons\n", uvmexp.fltnoanon); 1021 (void)printf("%9" PRIu64 " faults had to wait on pages\n", uvmexp.fltpgwait); 1022 (void)printf("%9" PRIu64 " faults found released page\n", uvmexp.fltpgrele); 1023 (void)printf("%9" PRIu64 " faults relock (%" PRIu64 " ok)\n", uvmexp.fltrelck, 1024 uvmexp.fltrelckok); 1025 (void)printf("%9" PRIu64 " anon page faults\n", uvmexp.fltanget); 1026 (void)printf("%9" PRIu64 " anon retry faults\n", uvmexp.fltanretry); 1027 (void)printf("%9" PRIu64 " amap copy faults\n", uvmexp.fltamcopy); 1028 (void)printf("%9" PRIu64 " neighbour anon page faults\n", uvmexp.fltnamap); 1029 (void)printf("%9" PRIu64 " neighbour object page faults\n", uvmexp.fltnomap); 1030 (void)printf("%9" PRIu64 " locked pager get faults\n", uvmexp.fltlget); 1031 (void)printf("%9" PRIu64 " unlocked pager get faults\n", uvmexp.fltget); 1032 (void)printf("%9" PRIu64 " anon faults\n", uvmexp.flt_anon); 1033 (void)printf("%9" PRIu64 " anon copy on write faults\n", uvmexp.flt_acow); 1034 (void)printf("%9" PRIu64 " object faults\n", uvmexp.flt_obj); 1035 (void)printf("%9" PRIu64 " promote copy faults\n", uvmexp.flt_prcopy); 1036 (void)printf("%9" PRIu64 " promote zero fill faults\n", uvmexp.flt_przero); 1037 1038 (void)printf("%9" PRIu64 " times daemon wokeup\n",uvmexp.pdwoke); 1039 (void)printf("%9" PRIu64 " revolutions of the clock hand\n", uvmexp.pdrevs); 1040 (void)printf("%9" PRIu64 " pages freed by daemon\n", uvmexp.pdfreed); 1041 (void)printf("%9" PRIu64 " pages scanned by daemon\n", uvmexp.pdscans); 1042 (void)printf("%9" PRIu64 " anonymous pages scanned by daemon\n", 1043 uvmexp.pdanscan); 1044 (void)printf("%9" PRIu64 " object pages scanned by daemon\n", uvmexp.pdobscan); 1045 (void)printf("%9" PRIu64 " pages reactivated\n", uvmexp.pdreact); 1046 (void)printf("%9" PRIu64 " pages found busy by daemon\n", uvmexp.pdbusy); 1047 (void)printf("%9" PRIu64 " total pending pageouts\n", uvmexp.pdpending); 1048 (void)printf("%9" PRIu64 " pages deactivated\n", uvmexp.pddeact); 1049 1050 if (active_kernel) { 1051 ssize = sizeof(nch_stats); 1052 if (sysctlbyname("vfs.namecache_stats", &nch_stats, &ssize, 1053 NULL, 0)) { 1054 warn("vfs.namecache_stats failed"); 1055 memset(&nch_stats, 0, sizeof(nch_stats)); 1056 } 1057 } else { 1058 struct nchstats nch_stats_kvm; 1059 1060 kread(namelist, X_NCHSTATS, &nch_stats_kvm, 1061 sizeof(nch_stats_kvm)); 1062 nch_stats.ncs_goodhits = nch_stats_kvm.ncs_goodhits; 1063 nch_stats.ncs_neghits = nch_stats_kvm.ncs_neghits; 1064 nch_stats.ncs_badhits = nch_stats_kvm.ncs_badhits; 1065 nch_stats.ncs_falsehits = nch_stats_kvm.ncs_falsehits; 1066 nch_stats.ncs_miss = nch_stats_kvm.ncs_miss; 1067 nch_stats.ncs_long = nch_stats_kvm.ncs_long; 1068 nch_stats.ncs_pass2 = nch_stats_kvm.ncs_pass2; 1069 nch_stats.ncs_2passes = nch_stats_kvm.ncs_2passes; 1070 nch_stats.ncs_revhits = nch_stats_kvm.ncs_revhits; 1071 nch_stats.ncs_revmiss = nch_stats_kvm.ncs_revmiss; 1072 } 1073 1074 nchtotal = nch_stats.ncs_goodhits + nch_stats.ncs_neghits + 1075 nch_stats.ncs_badhits + nch_stats.ncs_falsehits + 1076 nch_stats.ncs_miss + nch_stats.ncs_long; 1077 (void)printf("%9" PRIu64 " total name lookups\n", nchtotal); 1078 (void)printf("%9" PRIu64 " good hits\n", nch_stats.ncs_goodhits); 1079 (void)printf("%9" PRIu64 " negative hits\n", nch_stats.ncs_neghits); 1080 (void)printf("%9" PRIu64 " bad hits\n", nch_stats.ncs_badhits); 1081 (void)printf("%9" PRIu64 " false hits\n", nch_stats.ncs_falsehits); 1082 (void)printf("%9" PRIu64 " miss\n", nch_stats.ncs_miss); 1083 (void)printf("%9" PRIu64 " too long\n", nch_stats.ncs_long); 1084 (void)printf("%9" PRIu64 " pass2 hits\n", nch_stats.ncs_pass2); 1085 (void)printf("%9" PRIu64 " 2passes\n", nch_stats.ncs_2passes); 1086 (void)printf( 1087 "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n", 1088 "", PCT(nch_stats.ncs_goodhits, nchtotal), 1089 PCT(nch_stats.ncs_neghits, nchtotal), 1090 PCT(nch_stats.ncs_pass2, nchtotal)); 1091 (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "", 1092 PCT(nch_stats.ncs_badhits, nchtotal), 1093 PCT(nch_stats.ncs_falsehits, nchtotal), 1094 PCT(nch_stats.ncs_long, nchtotal)); 1095} 1096 1097void 1098doforkst(void) 1099{ 1100 if (memf != NULL) { 1101 struct uvmexp uvmexp_kernel; 1102 kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel)); 1103#define COPY(field) uvmexp.field = uvmexp_kernel.field 1104 COPY(forks); 1105 COPY(forks_ppwait); 1106 COPY(forks_sharevm); 1107#undef COPY 1108 } else { 1109 size_t size = sizeof(uvmexp); 1110 if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp, 1111 &size, NULL, 0) == -1) 1112 warn("sysctl vm.uvmexp2 failed"); 1113 } 1114 1115 (void)printf("%" PRIu64 " forks total\n", uvmexp.forks); 1116 (void)printf("%" PRIu64 " forks blocked parent\n", uvmexp.forks_ppwait); 1117 (void)printf("%" PRIu64 " forks shared address space with parent\n", 1118 uvmexp.forks_sharevm); 1119} 1120 1121void 1122drvstats(int *ovflwp) 1123{ 1124 size_t dn; 1125 double etime; 1126 int ovflw = *ovflwp; 1127 1128 /* Calculate disk stat deltas. */ 1129 cpuswap(); 1130 drvswap(); 1131 tkswap(); 1132 etime = cur.cp_etime; 1133 1134 for (dn = 0; dn < ndrive; ++dn) { 1135 if (!drv_select[dn]) 1136 continue; 1137 PRWORD(ovflw, " %*.0f", 3, 1, 1138 (cur.rxfer[dn] + cur.wxfer[dn]) / etime); 1139 } 1140 *ovflwp = ovflw; 1141} 1142 1143void 1144cpucounters(struct cpu_counter *cc) 1145{ 1146 static struct cpu_info **cpu_infos; 1147 static int initialised; 1148 struct cpu_info **slot; 1149 1150 if (memf == NULL) { 1151 cc->nintr = uvmexp.intrs; 1152 cc->nsyscall = uvmexp.syscalls; 1153 cc->nswtch = uvmexp.swtch; 1154 cc->nfault = uvmexp.faults; 1155 cc->ntrap = uvmexp.traps; 1156 cc->nsoft = uvmexp.softs; 1157 return; 1158 } 1159 1160 if (!initialised) { 1161 kread(namelist, X_CPU_INFOS, &cpu_infos, sizeof(cpu_infos)); 1162 initialised = 1; 1163 } 1164 1165 slot = cpu_infos; 1166 1167 memset(cc, 0, sizeof(*cc)); 1168 1169 for (;;) { 1170 struct cpu_info tci, *ci = NULL; 1171 1172 deref_kptr(slot++, &ci, sizeof(ci), "CPU array trashed"); 1173 if (!ci) { 1174 break; 1175 } 1176 1177 if ((size_t)kvm_read(kd, (u_long)ci, &tci, sizeof(tci)) 1178 != sizeof(tci)) { 1179 warnx("Can't read cpu info from %p (%s)", 1180 ci, kvm_geterr(kd)); 1181 memset(cc, 0, sizeof(*cc)); 1182 return; 1183 } 1184 cc->nintr += tci.ci_data.cpu_nintr; 1185 cc->nsyscall += tci.ci_data.cpu_nsyscall; 1186 cc->nswtch = tci.ci_data.cpu_nswtch; 1187 cc->nfault = tci.ci_data.cpu_nfault; 1188 cc->ntrap = tci.ci_data.cpu_ntrap; 1189 cc->nsoft = tci.ci_data.cpu_nsoft; 1190 } 1191} 1192 1193void 1194cpustats(int *ovflwp) 1195{ 1196 int state; 1197 double pcnt, total; 1198 double stat_us, stat_sy, stat_id; 1199 int ovflw = *ovflwp; 1200 1201 total = 0; 1202 for (state = 0; state < CPUSTATES; ++state) 1203 total += cur.cp_time[state]; 1204 if (total) 1205 pcnt = 100 / total; 1206 else 1207 pcnt = 0; 1208 stat_us = (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * pcnt; 1209 stat_sy = (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * pcnt; 1210 stat_id = cur.cp_time[CP_IDLE] * pcnt; 1211 PRWORD(ovflw, " %*.0f", ((stat_sy >= 100) ? 2 : 3), 1, stat_us); 1212 PRWORD(ovflw, " %*.0f", ((stat_us >= 100 || stat_id >= 100) ? 2 : 3), 1, 1213 stat_sy); 1214 PRWORD(ovflw, " %*.0f", 3, 1, stat_id); 1215 *ovflwp = ovflw; 1216} 1217 1218void 1219dointr(int verbose) 1220{ 1221 unsigned long *intrcnt, *ointrcnt; 1222 unsigned long long inttotal, uptime; 1223 int nintr, inamlen; 1224 char *intrname, *ointrname; 1225 1226 inttotal = 0; 1227 uptime = getuptime(); 1228 (void)printf("%-34s %16s %8s\n", "interrupt", "total", "rate"); 1229 nintr = intrnl[X_EINTRCNT].n_value - intrnl[X_INTRCNT].n_value; 1230 inamlen = intrnl[X_EINTRNAMES].n_value - intrnl[X_INTRNAMES].n_value; 1231 if (nintr != 0 && inamlen != 0) { 1232 ointrcnt = intrcnt = malloc((size_t)nintr); 1233 ointrname = intrname = malloc((size_t)inamlen); 1234 if (intrcnt == NULL || intrname == NULL) 1235 errx(1, "%s", ""); 1236 kread(intrnl, X_INTRCNT, intrcnt, (size_t)nintr); 1237 kread(intrnl, X_INTRNAMES, intrname, (size_t)inamlen); 1238 nintr /= sizeof(long); 1239 while (--nintr >= 0) { 1240 if (*intrcnt || verbose) 1241 (void)printf("%-34s %16llu %8llu\n", intrname, 1242 (unsigned long long)*intrcnt, 1243 (unsigned long long) 1244 (*intrcnt / uptime)); 1245 intrname += strlen(intrname) + 1; 1246 inttotal += *intrcnt++; 1247 } 1248 free(ointrcnt); 1249 free(ointrname); 1250 } 1251 1252 doevcnt(verbose, EVCNT_TYPE_INTR); 1253} 1254 1255void 1256doevcnt(int verbose, int type) 1257{ 1258 static const char * const evtypes [] = { "misc", "intr", "trap" }; 1259 uint64_t counttotal, uptime; 1260 struct evcntlist allevents; 1261 struct evcnt evcnt, *evptr; 1262 char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX]; 1263 1264 counttotal = 0; 1265 uptime = getuptime(); 1266 if (type == EVCNT_TYPE_ANY) 1267 (void)printf("%-34s %16s %8s %s\n", "event", "total", "rate", 1268 "type"); 1269 1270 if (memf == NULL) do { 1271 const int mib[4] = { CTL_KERN, KERN_EVCNT, type, 1272 verbose ? KERN_EVCNT_COUNT_ANY : KERN_EVCNT_COUNT_NONZERO }; 1273 size_t buflen = 0; 1274 void *buf = NULL; 1275 const struct evcnt_sysctl *evs, *last_evs; 1276 for (;;) { 1277 size_t newlen; 1278 int error; 1279 if (buflen) 1280 buf = malloc(buflen); 1281 error = sysctl(mib, __arraycount(mib), 1282 buf, &newlen, NULL, 0); 1283 if (error) { 1284 err(1, "kern.evcnt"); 1285 if (buf) 1286 free(buf); 1287 return; 1288 } 1289 if (newlen <= buflen) { 1290 buflen = newlen; 1291 break; 1292 } 1293 if (buf) 1294 free(buf); 1295 buflen = newlen; 1296 } 1297 evs = buf; 1298 last_evs = (void *)((char *)buf + buflen); 1299 buflen /= sizeof(uint64_t); 1300 while (evs < last_evs 1301 && buflen >= sizeof(*evs)/sizeof(uint64_t) 1302 && buflen >= evs->ev_len) { 1303 (void)printf(type == EVCNT_TYPE_ANY ? 1304 "%s %s%*s %16"PRIu64" %8"PRIu64" %s\n" : 1305 "%s %s%*s %16"PRIu64" %8"PRIu64"\n", 1306 evs->ev_strings, 1307 evs->ev_strings + evs->ev_grouplen + 1, 1308 34 - (evs->ev_grouplen + 1 + evs->ev_namelen), "", 1309 evs->ev_count, 1310 evs->ev_count / uptime, 1311 (evs->ev_type < __arraycount(evtypes) ? 1312 evtypes[evs->ev_type] : "?")); 1313 buflen -= evs->ev_len; 1314 counttotal += evs->ev_count; 1315 evs = (const void *)((const uint64_t *)evs + evs->ev_len); 1316 } 1317 free(buf); 1318 if (type != EVCNT_TYPE_ANY) 1319 (void)printf("%-34s %16"PRIu64" %8"PRIu64"\n", 1320 "Total", counttotal, counttotal / uptime); 1321 return; 1322 } while (/*CONSTCOND*/ 0); 1323 1324 kread(namelist, X_ALLEVENTS, &allevents, sizeof allevents); 1325 evptr = TAILQ_FIRST(&allevents); 1326 while (evptr) { 1327 deref_kptr(evptr, &evcnt, sizeof(evcnt), "event chain trashed"); 1328 1329 evptr = TAILQ_NEXT(&evcnt, ev_list); 1330 if (evcnt.ev_count == 0 && !verbose) 1331 continue; 1332 if (type != EVCNT_TYPE_ANY && evcnt.ev_type != type) 1333 continue; 1334 1335 deref_kptr(evcnt.ev_group, evgroup, 1336 (size_t)evcnt.ev_grouplen + 1, "event chain trashed"); 1337 deref_kptr(evcnt.ev_name, evname, 1338 (size_t)evcnt.ev_namelen + 1, "event chain trashed"); 1339 1340 (void)printf(type == EVCNT_TYPE_ANY ? 1341 "%s %s%*s %16"PRIu64" %8"PRIu64" %s\n" : 1342 "%s %s%*s %16"PRIu64" %8"PRIu64"\n", 1343 evgroup, evname, 1344 34 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "", 1345 evcnt.ev_count, 1346 (evcnt.ev_count / uptime), 1347 (evcnt.ev_type < __arraycount(evtypes) ? 1348 evtypes[evcnt.ev_type] : "?")); 1349 1350 counttotal += evcnt.ev_count; 1351 } 1352 if (type != EVCNT_TYPE_ANY) 1353 (void)printf("%-34s %16"PRIu64" %8"PRIu64"\n", 1354 "Total", counttotal, counttotal / uptime); 1355} 1356 1357static void 1358dopool_sysctl(int verbose, int wide) 1359{ 1360 uint64_t total, inuse, this_total, this_inuse; 1361 struct { 1362 uint64_t pt_nget; 1363 uint64_t pt_nfail; 1364 uint64_t pt_nput; 1365 uint64_t pt_nout; 1366 uint64_t pt_nitems; 1367 uint64_t pt_npagealloc; 1368 uint64_t pt_npagefree; 1369 uint64_t pt_npages; 1370 } pool_totals; 1371 size_t i, len; 1372 int name_len, ovflw; 1373 struct pool_sysctl *pp, *data; 1374 char in_use[8], avail[8], maxp[32]; 1375 1376 data = asysctlbyname("kern.pool", &len); 1377 if (data == NULL) 1378 err(1, "failed to reead kern.pool"); 1379 1380 memset(&pool_totals, 0, sizeof pool_totals); 1381 total = inuse = 0; 1382 len /= sizeof(*data); 1383 1384 (void)printf("Memory resource pool statistics\n"); 1385 (void)printf( 1386 "%-*s%*s%*s%5s%*s%s%s%*s%*s%6s%s%6s%6s%6s%5s%s%s\n", 1387 wide ? 16 : 11, "Name", 1388 wide ? 6 : 5, "Size", 1389 wide ? 12 : 9, "Requests", 1390 "Fail", 1391 wide ? 12 : 9, "Releases", 1392 wide ? " InUse" : "", 1393 wide ? " Avail" : "", 1394 wide ? 7 : 6, "Pgreq", 1395 wide ? 7 : 6, "Pgrel", 1396 "Npage", 1397 wide ? " PageSz" : "", 1398 "Hiwat", 1399 "Minpg", 1400 "Maxpg", 1401 "Idle", 1402 wide ? " Flags" : "", 1403 wide ? " Util" : ""); 1404 1405 name_len = MIN((int)sizeof(pp->pr_wchan), wide ? 16 : 11); 1406 for (i = 0; i < len; ++i) { 1407 pp = &data[i]; 1408 if (pp->pr_nget == 0 && !verbose) 1409 continue; 1410 if (pp->pr_maxpages == UINT_MAX) 1411 (void)snprintf(maxp, sizeof(maxp), "inf"); 1412 else 1413 (void)snprintf(maxp, sizeof(maxp), "%" PRIu64, 1414 pp->pr_maxpages); 1415 ovflw = 0; 1416 PRWORD(ovflw, "%-*s", name_len, 0, pp->pr_wchan); 1417 PRWORD(ovflw, " %*" PRIu64, wide ? 6 : 5, 1, pp->pr_size); 1418 PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pp->pr_nget); 1419 pool_totals.pt_nget += pp->pr_nget; 1420 PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_nfail); 1421 pool_totals.pt_nfail += pp->pr_nfail; 1422 PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pp->pr_nput); 1423 pool_totals.pt_nput += pp->pr_nput; 1424 if (wide) { 1425 PRWORD(ovflw, " %*" PRIu64, 7, 1, pp->pr_nout); 1426 pool_totals.pt_nout += pp->pr_nout; 1427 } 1428 if (wide) { 1429 PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_nitems); 1430 pool_totals.pt_nitems += pp->pr_nitems; 1431 } 1432 PRWORD(ovflw, " %*" PRIu64, wide ? 7 : 6, 1, pp->pr_npagealloc); 1433 pool_totals.pt_npagealloc += pp->pr_npagealloc; 1434 PRWORD(ovflw, " %*" PRIu64, wide ? 7 : 6, 1, pp->pr_npagefree); 1435 pool_totals.pt_npagefree += pp->pr_npagefree; 1436 PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_npages); 1437 pool_totals.pt_npages += pp->pr_npages; 1438 if (wide) 1439 PRWORD(ovflw, " %*" PRIu64, 7, 1, pp->pr_pagesize); 1440 PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_hiwat); 1441 PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_minpages); 1442 PRWORD(ovflw, " %*s", 6, 1, maxp); 1443 PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_nidle); 1444 if (wide) 1445 PRWORD(ovflw, " 0x%0*" PRIx64, 4, 1, 1446 pp->pr_flags); 1447 1448 this_inuse = pp->pr_nout * pp->pr_size; 1449 this_total = pp->pr_npages * pp->pr_pagesize; 1450 if (pp->pr_flags & PR_RECURSIVE) { 1451 /* 1452 * Don't count in-use memory, since it's part 1453 * of another pool and will be accounted for 1454 * there. 1455 */ 1456 total += (this_total - this_inuse); 1457 } else { 1458 inuse += this_inuse; 1459 total += this_total; 1460 } 1461 if (wide) { 1462 if (this_total == 0) 1463 (void)printf(" ---"); 1464 else 1465 (void)printf(" %5.1f%%", 1466 (100.0 * this_inuse) / this_total); 1467 } 1468 (void)printf("\n"); 1469 } 1470 if (wide) { 1471 snprintf(in_use, sizeof in_use, "%7"PRId64, pool_totals.pt_nout); 1472 snprintf(avail, sizeof avail, "%6"PRId64, pool_totals.pt_nitems); 1473 } else { 1474 in_use[0] = '\0'; 1475 avail[0] = '\0'; 1476 } 1477 (void)printf( 1478 "%-*s%*s%*"PRId64"%5"PRId64"%*"PRId64"%s%s%*"PRId64"%*"PRId64"%6"PRId64"\n", 1479 wide ? 16 : 11, "Totals", 1480 wide ? 6 : 5, "", 1481 wide ? 12 : 9, pool_totals.pt_nget, 1482 pool_totals.pt_nfail, 1483 wide ? 12 : 9, pool_totals.pt_nput, 1484 in_use, 1485 avail, 1486 wide ? 7 : 6, pool_totals.pt_npagealloc, 1487 wide ? 7 : 6, pool_totals.pt_npagefree, 1488 pool_totals.pt_npages); 1489 1490 inuse /= KILO; 1491 total /= KILO; 1492 (void)printf( 1493 "\nIn use %" PRIu64 "K, " 1494 "total allocated %" PRIu64 "K; utilization %.1f%%\n", 1495 inuse, total, (100.0 * inuse) / total); 1496 1497 free(data); 1498} 1499 1500void 1501dopool(int verbose, int wide) 1502{ 1503 int first, ovflw; 1504 void *addr; 1505 long total, inuse, this_total, this_inuse; 1506 struct { 1507 uint64_t pt_nget; 1508 uint64_t pt_nfail; 1509 uint64_t pt_nput; 1510 uint64_t pt_nout; 1511 uint64_t pt_nitems; 1512 uint64_t pt_npagealloc; 1513 uint64_t pt_npagefree; 1514 uint64_t pt_npages; 1515 } pool_totals; 1516 char in_use[8]; 1517 char avail[8]; 1518 TAILQ_HEAD(,pool) pool_head; 1519 struct pool pool, *pp = &pool; 1520 struct pool_allocator pa; 1521 char name[32], maxp[32]; 1522 1523 if (memf == NULL) 1524 return dopool_sysctl(verbose, wide); 1525 1526 memset(&pool_totals, 0, sizeof pool_totals); 1527 kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head)); 1528 addr = TAILQ_FIRST(&pool_head); 1529 1530 total = inuse = 0; 1531 1532 for (first = 1; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist) ) { 1533 deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed"); 1534 deref_kptr(pp->pr_alloc, &pa, sizeof(pa), 1535 "pool allocator trashed"); 1536 deref_kptr(pp->pr_wchan, name, sizeof(name), 1537 "pool wait channel trashed"); 1538 name[sizeof(name)-1] = '\0'; 1539 1540 if (first) { 1541 (void)printf("Memory resource pool statistics\n"); 1542 (void)printf( 1543 "%-*s%*s%*s%5s%*s%s%s%*s%*s%6s%s%6s%6s%6s%5s%s%s\n", 1544 wide ? 16 : 11, "Name", 1545 wide ? 6 : 5, "Size", 1546 wide ? 12 : 9, "Requests", 1547 "Fail", 1548 wide ? 12 : 9, "Releases", 1549 wide ? " InUse" : "", 1550 wide ? " Avail" : "", 1551 wide ? 7 : 6, "Pgreq", 1552 wide ? 7 : 6, "Pgrel", 1553 "Npage", 1554 wide ? " PageSz" : "", 1555 "Hiwat", 1556 "Minpg", 1557 "Maxpg", 1558 "Idle", 1559 wide ? " Flags" : "", 1560 wide ? " Util" : ""); 1561 first = 0; 1562 } 1563 if (pp->pr_nget == 0 && !verbose) 1564 continue; 1565 if (pp->pr_maxpages == UINT_MAX) 1566 (void)snprintf(maxp, sizeof(maxp), "inf"); 1567 else 1568 (void)snprintf(maxp, sizeof(maxp), "%u", 1569 pp->pr_maxpages); 1570 ovflw = 0; 1571 PRWORD(ovflw, "%-*s", wide ? 16 : 11, 0, name); 1572 PRWORD(ovflw, " %*u", wide ? 6 : 5, 1, pp->pr_size); 1573 PRWORD(ovflw, " %*lu", wide ? 12 : 9, 1, pp->pr_nget); 1574 pool_totals.pt_nget += pp->pr_nget; 1575 PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nfail); 1576 pool_totals.pt_nfail += pp->pr_nfail; 1577 PRWORD(ovflw, " %*lu", wide ? 12 : 9, 1, pp->pr_nput); 1578 pool_totals.pt_nput += pp->pr_nput; 1579 if (wide) { 1580 PRWORD(ovflw, " %*u", 7, 1, pp->pr_nout); 1581 pool_totals.pt_nout += pp->pr_nout; 1582 } 1583 if (wide) { 1584 PRWORD(ovflw, " %*u", 6, 1, pp->pr_nitems); 1585 pool_totals.pt_nitems += pp->pr_nitems; 1586 } 1587 PRWORD(ovflw, " %*lu", wide ? 7 : 6, 1, pp->pr_npagealloc); 1588 pool_totals.pt_npagealloc += pp->pr_npagealloc; 1589 PRWORD(ovflw, " %*lu", wide ? 7 : 6, 1, pp->pr_npagefree); 1590 pool_totals.pt_npagefree += pp->pr_npagefree; 1591 PRWORD(ovflw, " %*u", 6, 1, pp->pr_npages); 1592 pool_totals.pt_npages += pp->pr_npages; 1593 if (wide) 1594 PRWORD(ovflw, " %*u", 7, 1, pa.pa_pagesz); 1595 PRWORD(ovflw, " %*u", 6, 1, pp->pr_hiwat); 1596 PRWORD(ovflw, " %*u", 6, 1, pp->pr_minpages); 1597 PRWORD(ovflw, " %*s", 6, 1, maxp); 1598 PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nidle); 1599 if (wide) 1600 PRWORD(ovflw, " 0x%0*x", 4, 1, 1601 pp->pr_flags | pp->pr_roflags); 1602 1603 this_inuse = pp->pr_nout * pp->pr_size; 1604 this_total = pp->pr_npages * pa.pa_pagesz; 1605 if (pp->pr_roflags & PR_RECURSIVE) { 1606 /* 1607 * Don't count in-use memory, since it's part 1608 * of another pool and will be accounted for 1609 * there. 1610 */ 1611 total += (this_total - this_inuse); 1612 } else { 1613 inuse += this_inuse; 1614 total += this_total; 1615 } 1616 if (wide) { 1617 if (this_total == 0) 1618 (void)printf(" ---"); 1619 else 1620 (void)printf(" %5.1f%%", 1621 (100.0 * this_inuse) / this_total); 1622 } 1623 (void)printf("\n"); 1624 } 1625 if (wide) { 1626 snprintf(in_use, sizeof in_use, "%7"PRId64, pool_totals.pt_nout); 1627 snprintf(avail, sizeof avail, "%6"PRId64, pool_totals.pt_nitems); 1628 } else { 1629 in_use[0] = '\0'; 1630 avail[0] = '\0'; 1631 } 1632 (void)printf( 1633 "%-*s%*s%*"PRId64"%5"PRId64"%*"PRId64"%s%s%*"PRId64"%*"PRId64"%6"PRId64"\n", 1634 wide ? 16 : 11, "Totals", 1635 wide ? 6 : 5, "", 1636 wide ? 12 : 9, pool_totals.pt_nget, 1637 pool_totals.pt_nfail, 1638 wide ? 12 : 9, pool_totals.pt_nput, 1639 in_use, 1640 avail, 1641 wide ? 7 : 6, pool_totals.pt_npagealloc, 1642 wide ? 7 : 6, pool_totals.pt_npagefree, 1643 pool_totals.pt_npages); 1644 1645 inuse /= KILO; 1646 total /= KILO; 1647 (void)printf( 1648 "\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n", 1649 inuse, total, (100.0 * inuse) / total); 1650} 1651 1652static void 1653dopoolcache_sysctl(int verbose) 1654{ 1655 struct pool_sysctl *data, *pp; 1656 size_t i, len; 1657 bool first = true; 1658 int ovflw; 1659 uint64_t tot; 1660 float p; 1661 1662 data = asysctlbyname("kern.pool", &len); 1663 if (data == NULL) 1664 err(1, "failed to reead kern.pool"); 1665 len /= sizeof(*data); 1666 1667 for (i = 0; i < len; ++i) { 1668 pp = &data[i]; 1669 if (pp->pr_cache_meta_size == 0) 1670 continue; 1671 1672 if (pp->pr_cache_nmiss_global == 0 && !verbose) 1673 continue; 1674 1675 if (first) { 1676 (void)printf("Pool cache statistics.\n"); 1677 (void)printf("%-*s%*s%*s%*s%*s%*s%*s%*s%*s%*s\n", 1678 12, "Name", 1679 6, "Spin", 1680 6, "GrpSz", 1681 5, "Full", 1682 5, "Emty", 1683 10, "PoolLayer", 1684 11, "CacheLayer", 1685 6, "Hit%", 1686 12, "CpuLayer", 1687 6, "Hit%" 1688 ); 1689 first = false; 1690 } 1691 1692 ovflw = 0; 1693 PRWORD(ovflw, "%-*s", MIN((int)sizeof(pp->pr_wchan), 13), 1, 1694 pp->pr_wchan); 1695 PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_cache_ncontended); 1696 PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_cache_meta_size); 1697 PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_cache_nfull); 1698 PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_cache_nempty); 1699 PRWORD(ovflw, " %*" PRIu64, 10, 1, pp->pr_cache_nmiss_global); 1700 1701 tot = pp->pr_cache_nhit_global + pp->pr_cache_nmiss_global; 1702 p = pp->pr_cache_nhit_global * 100.0 / tot; 1703 PRWORD(ovflw, " %*" PRIu64, 11, 1, tot); 1704 PRWORD(ovflw, " %*.1f", 6, 1, p); 1705 1706 tot = pp->pr_cache_nhit_pcpu + pp->pr_cache_nmiss_pcpu; 1707 p = pp->pr_cache_nhit_pcpu * 100.0 / tot; 1708 PRWORD(ovflw, " %*" PRIu64, 12, 1, tot); 1709 PRWORD(ovflw, " %*.1f", 6, 1, p); 1710 printf("\n"); 1711 } 1712} 1713 1714void 1715dopoolcache(int verbose) 1716{ 1717 struct pool_cache pool_cache, *pc = &pool_cache; 1718 pool_cache_cpu_t cache_cpu, *cc = &cache_cpu; 1719 TAILQ_HEAD(,pool) pool_head; 1720 struct pool pool, *pp = &pool; 1721 char name[32]; 1722 uint64_t cpuhit, cpumiss, tot; 1723 void *addr; 1724 int first, ovflw; 1725 size_t i; 1726 double p; 1727 1728 if (memf == NULL) 1729 return dopoolcache_sysctl(verbose); 1730 1731 kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head)); 1732 addr = TAILQ_FIRST(&pool_head); 1733 1734 for (first = 1; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist) ) { 1735 deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed"); 1736 if (pp->pr_cache == NULL) 1737 continue; 1738 deref_kptr(pp->pr_wchan, name, sizeof(name), 1739 "pool wait channel trashed"); 1740 deref_kptr(pp->pr_cache, pc, sizeof(*pc), "pool cache trashed"); 1741 if (pc->pc_misses == 0 && !verbose) 1742 continue; 1743 name[sizeof(name)-1] = '\0'; 1744 1745 cpuhit = 0; 1746 cpumiss = 0; 1747 for (i = 0; i < __arraycount(pc->pc_cpus); i++) { 1748 if ((addr = pc->pc_cpus[i]) == NULL) 1749 continue; 1750 deref_kptr(addr, cc, sizeof(*cc), 1751 "pool cache cpu trashed"); 1752 cpuhit += cc->cc_hits; 1753 cpumiss += cc->cc_misses; 1754 } 1755 1756 if (first) { 1757 (void)printf("Pool cache statistics.\n"); 1758 (void)printf("%-*s%*s%*s%*s%*s%*s%*s%*s%*s%*s\n", 1759 12, "Name", 1760 6, "Spin", 1761 6, "GrpSz", 1762 5, "Full", 1763 5, "Emty", 1764 10, "PoolLayer", 1765 11, "CacheLayer", 1766 6, "Hit%", 1767 12, "CpuLayer", 1768 6, "Hit%" 1769 ); 1770 first = 0; 1771 } 1772 1773 ovflw = 0; 1774 PRWORD(ovflw, "%-*s", 13, 1, name); 1775 PRWORD(ovflw, " %*llu", 6, 1, (long long)pc->pc_contended); 1776 PRWORD(ovflw, " %*u", 6, 1, pc->pc_pcgsize); 1777 PRWORD(ovflw, " %*u", 5, 1, pc->pc_nfull); 1778 PRWORD(ovflw, " %*u", 5, 1, pc->pc_nempty); 1779 PRWORD(ovflw, " %*llu", 10, 1, (long long)pc->pc_misses); 1780 1781 tot = pc->pc_hits + pc->pc_misses; 1782 p = pc->pc_hits * 100.0 / (tot); 1783 PRWORD(ovflw, " %*llu", 11, 1, (long long)tot); 1784 PRWORD(ovflw, " %*.1f", 6, 1, p); 1785 1786 tot = cpuhit + cpumiss; 1787 p = cpuhit * 100.0 / (tot); 1788 PRWORD(ovflw, " %*llu", 12, 1, (long long)tot); 1789 PRWORD(ovflw, " %*.1f", 6, 1, p); 1790 printf("\n"); 1791 } 1792} 1793 1794enum hashtype { /* from <sys/systm.h> */ 1795 HASH_LIST, 1796 HASH_TAILQ 1797}; 1798 1799struct uidinfo { /* XXX: no kernel header file */ 1800 LIST_ENTRY(uidinfo) ui_hash; 1801 uid_t ui_uid; 1802 long ui_proccnt; 1803}; 1804 1805struct kernel_hash { 1806 const char * description; /* description */ 1807 int hashsize; /* nlist index for hash size */ 1808 int hashtbl; /* nlist index for hash table */ 1809 enum hashtype type; /* type of hash table */ 1810 size_t offset; /* offset of {LIST,TAILQ}_NEXT */ 1811} khashes[] = 1812{ 1813 { 1814 "buffer hash", 1815 X_BUFHASH, X_BUFHASHTBL, 1816 HASH_LIST, offsetof(struct buf, b_hash) 1817 }, { 1818 "ipv4 address -> interface hash", 1819 X_IFADDRHASH, X_IFADDRHASHTBL, 1820 HASH_LIST, offsetof(struct in_ifaddr, ia_hash), 1821 }, { 1822 "name cache hash", 1823 X_NCHASH, X_NCHASHTBL, 1824 HASH_LIST, offsetof(struct namecache, nc_hash), 1825 }, { 1826 "name cache directory hash", 1827 X_NCVHASH, X_NCVHASHTBL, 1828 HASH_LIST, offsetof(struct namecache, nc_vhash), 1829 }, { 1830 "user info (uid -> used processes) hash", 1831 X_UIHASH, X_UIHASHTBL, 1832 HASH_LIST, offsetof(struct uidinfo, ui_hash), 1833 }, { 1834 NULL, -1, -1, 0, 0, 1835 } 1836}; 1837 1838void 1839dohashstat(int verbose, int todo, const char *hashname) 1840{ 1841 LIST_HEAD(, generic) *hashtbl_list; 1842 TAILQ_HEAD(, generic) *hashtbl_tailq; 1843 struct kernel_hash *curhash; 1844 void *hashaddr, *hashbuf, *nhashbuf, *nextaddr; 1845 size_t elemsize, hashbufsize, thissize; 1846 u_long hashsize, i; 1847 int used, items, chain, maxchain; 1848 1849 hashbuf = NULL; 1850 hashbufsize = 0; 1851 1852 if (todo & HASHLIST) { 1853 (void)printf("Supported hashes:\n"); 1854 for (curhash = khashes; curhash->description; curhash++) { 1855 if (hashnl[curhash->hashsize].n_value == 0 || 1856 hashnl[curhash->hashtbl].n_value == 0) 1857 continue; 1858 (void)printf("\t%-16s%s\n", 1859 hashnl[curhash->hashsize].n_name + 1, 1860 curhash->description); 1861 } 1862 return; 1863 } 1864 1865 if (hashname != NULL) { 1866 for (curhash = khashes; curhash->description; curhash++) { 1867 if (strcmp(hashnl[curhash->hashsize].n_name + 1, 1868 hashname) == 0 && 1869 hashnl[curhash->hashsize].n_value != 0 && 1870 hashnl[curhash->hashtbl].n_value != 0) 1871 break; 1872 } 1873 if (curhash->description == NULL) { 1874 warnx("%s: no such hash", hashname); 1875 return; 1876 } 1877 } 1878 1879 (void)printf( 1880 "%-16s %8s %8s %8s %8s %8s %8s\n" 1881 "%-16s %8s %8s %8s %8s %8s %8s\n", 1882 "", "total", "used", "util", "num", "average", "maximum", 1883 "hash table", "buckets", "buckets", "%", "items", "chain", 1884 "chain"); 1885 1886 for (curhash = khashes; curhash->description; curhash++) { 1887 if (hashnl[curhash->hashsize].n_value == 0 || 1888 hashnl[curhash->hashtbl].n_value == 0) 1889 continue; 1890 if (hashname != NULL && 1891 strcmp(hashnl[curhash->hashsize].n_name + 1, hashname)) 1892 continue; 1893 elemsize = curhash->type == HASH_LIST ? 1894 sizeof(*hashtbl_list) : sizeof(*hashtbl_tailq); 1895 deref_kptr((void *)hashnl[curhash->hashsize].n_value, 1896 &hashsize, sizeof(hashsize), 1897 hashnl[curhash->hashsize].n_name); 1898 hashsize++; 1899 deref_kptr((void *)hashnl[curhash->hashtbl].n_value, 1900 &hashaddr, sizeof(hashaddr), 1901 hashnl[curhash->hashtbl].n_name); 1902 if (verbose) 1903 (void)printf( 1904 "%s %lu, %s %p, offset %ld, elemsize %llu\n", 1905 hashnl[curhash->hashsize].n_name + 1, hashsize, 1906 hashnl[curhash->hashtbl].n_name + 1, hashaddr, 1907 (long)curhash->offset, 1908 (unsigned long long)elemsize); 1909 thissize = hashsize * elemsize; 1910 if (hashbuf == NULL || thissize > hashbufsize) { 1911 if ((nhashbuf = realloc(hashbuf, thissize)) == NULL) 1912 errx(1, "malloc hashbuf %llu", 1913 (unsigned long long)hashbufsize); 1914 hashbuf = nhashbuf; 1915 hashbufsize = thissize; 1916 } 1917 deref_kptr(hashaddr, hashbuf, thissize, 1918 hashnl[curhash->hashtbl].n_name); 1919 used = 0; 1920 items = maxchain = 0; 1921 if (curhash->type == HASH_LIST) { 1922 hashtbl_list = hashbuf; 1923 hashtbl_tailq = NULL; 1924 } else { 1925 hashtbl_list = NULL; 1926 hashtbl_tailq = hashbuf; 1927 } 1928 for (i = 0; i < hashsize; i++) { 1929 if (curhash->type == HASH_LIST) 1930 nextaddr = LIST_FIRST(&hashtbl_list[i]); 1931 else 1932 nextaddr = TAILQ_FIRST(&hashtbl_tailq[i]); 1933 if (nextaddr == NULL) 1934 continue; 1935 if (verbose) 1936 (void)printf("%5lu: %p\n", i, nextaddr); 1937 used++; 1938 chain = 0; 1939 do { 1940 chain++; 1941 deref_kptr((char *)nextaddr + curhash->offset, 1942 &nextaddr, sizeof(void *), 1943 "hash chain corrupted"); 1944 if (verbose > 1) 1945 (void)printf("got nextaddr as %p\n", 1946 nextaddr); 1947 } while (nextaddr != NULL); 1948 items += chain; 1949 if (verbose && chain > 1) 1950 (void)printf("\tchain = %d\n", chain); 1951 if (chain > maxchain) 1952 maxchain = chain; 1953 } 1954 (void)printf("%-16s %8ld %8d %8.2f %8d %8.2f %8d\n", 1955 hashnl[curhash->hashsize].n_name + 1, 1956 hashsize, used, used * 100.0 / hashsize, 1957 items, used ? (double)items / used : 0.0, maxchain); 1958 } 1959} 1960 1961/* 1962 * kreadc like kread but returns 1 if sucessful, 0 otherwise 1963 */ 1964int 1965kreadc(struct nlist *nl, int nlx, void *addr, size_t size) 1966{ 1967 const char *sym; 1968 1969 sym = nl[nlx].n_name; 1970 if (*sym == '_') 1971 ++sym; 1972 if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) 1973 return 0; 1974 deref_kptr((void *)nl[nlx].n_value, addr, size, sym); 1975 return 1; 1976} 1977 1978/* 1979 * kread reads something from the kernel, given its nlist index in namelist[]. 1980 */ 1981void 1982kread(struct nlist *nl, int nlx, void *addr, size_t size) 1983{ 1984 const char *sym; 1985 1986 sym = nl[nlx].n_name; 1987 if (*sym == '_') 1988 ++sym; 1989 if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) 1990 errx(1, "symbol %s not defined", sym); 1991 deref_kptr((void *)nl[nlx].n_value, addr, size, sym); 1992} 1993 1994/* 1995 * Dereference the kernel pointer `kptr' and fill in the local copy 1996 * pointed to by `ptr'. The storage space must be pre-allocated, 1997 * and the size of the copy passed in `len'. 1998 */ 1999void 2000deref_kptr(const void *kptr, void *ptr, size_t len, const char *msg) 2001{ 2002 2003 if (*msg == '_') 2004 msg++; 2005 if ((size_t)kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len) 2006 errx(1, "kptr %lx: %s: %s", (u_long)kptr, msg, kvm_geterr(kd)); 2007} 2008 2009/* 2010 * Traverse the kernel history buffers, performing the requested action. 2011 * 2012 * Note, we assume that if we're not listing, we're dumping. 2013 */ 2014void 2015hist_traverse(int todo, const char *histname) 2016{ 2017 struct kern_history_head histhead; 2018 struct kern_history hist, *histkva; 2019 char *name = NULL; 2020 size_t namelen = 0; 2021 2022 if (histnl[0].n_value == 0) { 2023 warnx("kernel history is not compiled into the kernel."); 2024 return; 2025 } 2026 2027 deref_kptr((void *)histnl[X_KERN_HISTORIES].n_value, &histhead, 2028 sizeof(histhead), histnl[X_KERN_HISTORIES].n_name); 2029 2030 if (histhead.lh_first == NULL) { 2031 warnx("No active kernel history logs."); 2032 return; 2033 } 2034 2035 if (todo & HISTLIST) 2036 (void)printf("Active kernel histories:"); 2037 2038 for (histkva = LIST_FIRST(&histhead); histkva != NULL; 2039 histkva = LIST_NEXT(&hist, list)) { 2040 deref_kptr(histkva, &hist, sizeof(hist), "histkva"); 2041 if (name == NULL || hist.namelen > namelen) { 2042 if (name != NULL) 2043 free(name); 2044 namelen = hist.namelen; 2045 if ((name = malloc(namelen + 1)) == NULL) 2046 err(1, "malloc history name"); 2047 } 2048 2049 deref_kptr(hist.name, name, namelen, "history name"); 2050 name[namelen] = '\0'; 2051 if (todo & HISTLIST) 2052 (void)printf(" %s", name); 2053 else { 2054 /* 2055 * If we're dumping all histories, do it, else 2056 * check to see if this is the one we want. 2057 */ 2058 if (histname == NULL || strcmp(histname, name) == 0) { 2059 if (histname == NULL) 2060 (void)printf( 2061 "\nkernel history `%s':\n", name); 2062 hist_dodump(&hist); 2063 } 2064 } 2065 } 2066 2067 if (todo & HISTLIST) 2068 (void)putchar('\n'); 2069 2070 if (name != NULL) 2071 free(name); 2072} 2073 2074/* 2075 * Actually dump the history buffer at the specified KVA. 2076 */ 2077void 2078hist_dodump(struct kern_history *histp) 2079{ 2080 struct kern_history_ent *histents, *e; 2081 size_t histsize; 2082 char *fmt = NULL, *fn = NULL; 2083 size_t fmtlen = 0, fnlen = 0; 2084 unsigned i; 2085 2086 histsize = sizeof(struct kern_history_ent) * histp->n; 2087 2088 if ((histents = malloc(histsize)) == NULL) 2089 err(1, "malloc history entries"); 2090 2091 (void)memset(histents, 0, histsize); 2092 2093 deref_kptr(histp->e, histents, histsize, "history entries"); 2094 i = histp->f; 2095 do { 2096 e = &histents[i]; 2097 if (e->fmt != NULL) { 2098 if (fmt == NULL || e->fmtlen > fmtlen) { 2099 if (fmt != NULL) 2100 free(fmt); 2101 fmtlen = e->fmtlen; 2102 if ((fmt = malloc(fmtlen + 1)) == NULL) 2103 err(1, "malloc printf format"); 2104 } 2105 if (fn == NULL || e->fnlen > fnlen) { 2106 if (fn != NULL) 2107 free(fn); 2108 fnlen = e->fnlen; 2109 if ((fn = malloc(fnlen + 1)) == NULL) 2110 err(1, "malloc function name"); 2111 } 2112 2113 deref_kptr(e->fmt, fmt, fmtlen, "printf format"); 2114 fmt[fmtlen] = '\0'; 2115 2116 deref_kptr(e->fn, fn, fnlen, "function name"); 2117 fn[fnlen] = '\0'; 2118 2119 (void)printf("%06ld.%06ld ", (long int)e->tv.tv_sec, 2120 (long int)e->tv.tv_usec); 2121 (void)printf("%s#%ld@%d: ", fn, e->call, e->cpunum); 2122 (void)printf(fmt, e->v[0], e->v[1], e->v[2], e->v[3]); 2123 (void)putchar('\n'); 2124 } 2125 i = (i + 1) % histp->n; 2126 } while (i != histp->f); 2127 2128 free(histents); 2129 if (fmt != NULL) 2130 free(fmt); 2131 if (fn != NULL) 2132 free(fn); 2133} 2134 2135static void 2136usage(void) 2137{ 2138 2139 (void)fprintf(stderr, 2140 "usage: %s [-CefHiLlmstUvW] [-c count] [-h hashname] [-M core] [-N system]\n" 2141 "\t\t[-u histname] [-w wait] [disks]\n", getprogname()); 2142 exit(1); 2143} 2144