[BACK]Return to vmstat.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.bin / vmstat

Annotation of src/usr.bin/vmstat/vmstat.c, Revision 1.138.2.1

1.138.2.1! simonb      1: /* $NetBSD: vmstat.c,v 1.138 2005/10/22 15:32:48 nonaka Exp $ */
1.45      thorpej     2:
                      3: /*-
1.87      lukem       4:  * Copyright (c) 1998, 2000, 2001 The NetBSD Foundation, Inc.
1.45      thorpej     5:  * All rights reserved.
                      6:  *
1.87      lukem       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.
1.45      thorpej    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:  * 3. All advertising materials mentioning features or use of this software
                     21:  *    must display the following acknowledgement:
                     22:  *     This product includes software developed by the NetBSD
                     23:  *     Foundation, Inc. and its contributors.
                     24:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     25:  *    contributors may be used to endorse or promote products derived
                     26:  *    from this software without specific prior written permission.
                     27:  *
                     28:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     29:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     30:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     31:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     32:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     33:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     34:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     35:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     36:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     37:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     38:  * POSSIBILITY OF SUCH DAMAGE.
                     39:  */
1.21      cgd        40:
1.1       cgd        41: /*
1.13      cgd        42:  * Copyright (c) 1980, 1986, 1991, 1993
                     43:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd        44:  *
                     45:  * Redistribution and use in source and binary forms, with or without
                     46:  * modification, are permitted provided that the following conditions
                     47:  * are met:
                     48:  * 1. Redistributions of source code must retain the above copyright
                     49:  *    notice, this list of conditions and the following disclaimer.
                     50:  * 2. Redistributions in binary form must reproduce the above copyright
                     51:  *    notice, this list of conditions and the following disclaimer in the
                     52:  *    documentation and/or other materials provided with the distribution.
1.117     agc        53:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        54:  *    may be used to endorse or promote products derived from this software
                     55:  *    without specific prior written permission.
                     56:  *
                     57:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     58:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     59:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     60:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     61:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     62:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     63:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     64:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     65:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     66:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     67:  * SUCH DAMAGE.
                     68:  */
                     69:
1.38      mrg        70: #include <sys/cdefs.h>
1.1       cgd        71: #ifndef lint
1.38      mrg        72: __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1991, 1993\n\
                     73:        The Regents of the University of California.  All rights reserved.\n");
1.1       cgd        74: #endif /* not lint */
                     75:
                     76: #ifndef lint
1.21      cgd        77: #if 0
1.37      mrg        78: static char sccsid[] = "@(#)vmstat.c   8.2 (Berkeley) 3/1/95";
1.21      cgd        79: #else
1.138.2.1! simonb     80: __RCSID("$NetBSD: vmstat.c,v 1.138 2005/10/22 15:32:48 nonaka Exp $");
1.21      cgd        81: #endif
1.1       cgd        82: #endif /* not lint */
1.57      thorpej    83:
                     84: #define        __POOL_EXPOSE
1.1       cgd        85:
                     86: #include <sys/param.h>
1.87      lukem      87: #include <sys/mount.h>
                     88: #include <sys/uio.h>
                     89:
                     90: #include <sys/buf.h>
                     91: #include <sys/device.h>
                     92: #include <sys/ioctl.h>
                     93: #include <sys/malloc.h>
1.109     thorpej    94: #include <sys/mallocvar.h>
1.1       cgd        95: #include <sys/namei.h>
1.87      lukem      96: #include <sys/pool.h>
                     97: #include <sys/proc.h>
1.64      perry      98: #include <sys/sched.h>
1.87      lukem      99: #include <sys/socket.h>
1.13      cgd       100: #include <sys/sysctl.h>
1.87      lukem     101: #include <sys/time.h>
                    102: #include <sys/user.h>
1.67      mrg       103:
                    104: #include <uvm/uvm_extern.h>
                    105: #include <uvm/uvm_stat.h>
                    106:
1.87      lukem     107: #include <net/if.h>
                    108: #include <netinet/in.h>
                    109: #include <netinet/in_var.h>
                    110:
                    111: #include <ufs/ufs/inode.h>
                    112:
                    113: #include <nfs/rpcv2.h>
                    114: #include <nfs/nfsproto.h>
                    115: #include <nfs/nfsnode.h>
                    116:
                    117: #include <ctype.h>
1.45      thorpej   118: #include <err.h>
1.87      lukem     119: #include <errno.h>
1.55      kleink    120: #include <fcntl.h>
1.87      lukem     121: #include <kvm.h>
                    122: #include <limits.h>
1.1       cgd       123: #include <nlist.h>
1.87      lukem     124: #undef n_hash
                    125: #include <paths.h>
1.22      jtc       126: #include <signal.h>
1.1       cgd       127: #include <stdio.h>
1.87      lukem     128: #include <stddef.h>
1.1       cgd       129: #include <stdlib.h>
                    130: #include <string.h>
1.87      lukem     131: #include <time.h>
                    132: #include <unistd.h>
1.104     mrg       133: #include <util.h>
1.87      lukem     134:
1.29      thorpej   135: #include "dkstats.h"
1.136     blymn     136: #include "tpstats.h"
1.45      thorpej   137:
1.90      lukem     138: /*
                    139:  * General namelist
                    140:  */
1.87      lukem     141: struct nlist namelist[] =
                    142: {
1.65      itojun    143: #define        X_BOOTTIME      0
1.1       cgd       144:        { "_boottime" },
1.75      enami     145: #define        X_HZ            1
1.1       cgd       146:        { "_hz" },
1.75      enami     147: #define        X_STATHZ        2
1.13      cgd       148:        { "_stathz" },
1.75      enami     149: #define        X_NCHSTATS      3
1.1       cgd       150:        { "_nchstats" },
1.133     chs       151: #define        X_KMEMSTAT      4
1.109     thorpej   152:        { "_kmemstatistics" },
1.133     chs       153: #define        X_KMEMBUCKETS   5
1.134     chs       154:        { "_kmembuckets" },
1.133     chs       155: #define        X_ALLEVENTS     6
1.18      pk        156:        { "_allevents" },
1.133     chs       157: #define        X_POOLHEAD      7
1.51      pk        158:        { "_pool_head" },
1.133     chs       159: #define        X_UVMEXP        8
1.58      thorpej   160:        { "_uvmexp" },
1.138.2.1! simonb    161: #define        X_TIME_SECOND   9
        !           162: #ifdef __HAVE_TIMECOUNTER
        !           163:        { "_time_second" },
        !           164: #else
        !           165:        { "_time" },    /* XXX uses same array slot as "X_TIME_SECOND" */
        !           166: #endif
1.133     chs       167: #define        X_NL_SIZE       10
1.90      lukem     168:        { NULL },
                    169: };
                    170:
                    171: /*
1.133     chs       172:  * Namelist for pre-evcnt interrupt counters.
                    173:  */
                    174: struct nlist intrnl[] =
                    175: {
                    176: #define        X_INTRNAMES     0
                    177:        { "_intrnames" },
                    178: #define        X_EINTRNAMES    1
                    179:        { "_eintrnames" },
                    180: #define        X_INTRCNT       2
                    181:        { "_intrcnt" },
                    182: #define        X_EINTRCNT      3
                    183:        { "_eintrcnt" },
                    184: #define        X_INTRNL_SIZE   4
                    185:        { NULL },
                    186: };
                    187:
                    188:
                    189: /*
1.90      lukem     190:  * Namelist for hash statistics
                    191:  */
                    192: struct nlist hashnl[] =
                    193: {
                    194: #define        X_NFSNODE       0
1.87      lukem     195:        { "_nfsnodehash" },
1.90      lukem     196: #define        X_NFSNODETBL    1
1.87      lukem     197:        { "_nfsnodehashtbl" },
1.90      lukem     198: #define        X_IHASH         2
1.87      lukem     199:        { "_ihash" },
1.90      lukem     200: #define        X_IHASHTBL      3
1.87      lukem     201:        { "_ihashtbl" },
1.90      lukem     202: #define        X_BUFHASH       4
1.87      lukem     203:        { "_bufhash" },
1.90      lukem     204: #define        X_BUFHASHTBL    5
1.87      lukem     205:        { "_bufhashtbl" },
1.122     junyoung  206: #define        X_UIHASH        6
1.87      lukem     207:        { "_uihash" },
1.122     junyoung  208: #define        X_UIHASHTBL     7
1.87      lukem     209:        { "_uihashtbl" },
1.122     junyoung  210: #define        X_IFADDRHASH    8
1.87      lukem     211:        { "_in_ifaddrhash" },
1.122     junyoung  212: #define        X_IFADDRHASHTBL 9
1.87      lukem     213:        { "_in_ifaddrhashtbl" },
1.122     junyoung  214: #define        X_NCHASH        10
1.89      lukem     215:        { "_nchash" },
1.122     junyoung  216: #define        X_NCHASHTBL     11
1.89      lukem     217:        { "_nchashtbl" },
1.122     junyoung  218: #define        X_NCVHASH       12
1.89      lukem     219:        { "_ncvhash" },
1.122     junyoung  220: #define        X_NCVHASHTBL    13
1.89      lukem     221:        { "_ncvhashtbl" },
1.122     junyoung  222: #define X_HASHNL_SIZE  14      /* must be last */
1.90      lukem     223:        { NULL },
                    224: };
1.87      lukem     225:
1.90      lukem     226: /*
                    227:  * Namelist for UVM histories
                    228:  */
                    229: struct nlist histnl[] =
                    230: {
                    231:        { "_uvm_histories" },
                    232: #define        X_UVM_HISTORIES         0
                    233:        { NULL },
1.1       cgd       234: };
                    235:
1.87      lukem     236:
1.90      lukem     237:
1.41      mrg       238: struct uvmexp uvmexp, ouvmexp;
1.73      simonb    239: int    ndrives;
1.1       cgd       240:
                    241: int    winlines = 20;
                    242:
1.13      cgd       243: kvm_t *kd;
                    244:
1.87      lukem     245: #define        FORKSTAT        1<<0
                    246: #define        INTRSTAT        1<<1
                    247: #define        MEMSTAT         1<<2
                    248: #define        SUMSTAT         1<<3
                    249: #define        EVCNTSTAT       1<<4
                    250: #define        VMSTAT          1<<5
                    251: #define        HISTLIST        1<<6
                    252: #define        HISTDUMP        1<<7
                    253: #define        HASHSTAT        1<<8
1.88      lukem     254: #define        HASHLIST        1<<9
1.130     he        255: #define        VMTOTAL         1<<10
1.1       cgd       256:
1.73      simonb    257: void   cpustats(void);
1.87      lukem     258: void   deref_kptr(const void *, void *, size_t, const char *);
1.73      simonb    259: void   dkstats(void);
1.136     blymn     260: void   tpstats(void);
1.73      simonb    261: void   doevcnt(int verbose);
1.88      lukem     262: void   dohashstat(int, int, const char *);
1.73      simonb    263: void   dointr(int verbose);
                    264: void   domem(void);
1.126     simonb    265: void   dopool(int, int);
1.96      enami     266: void   dopoolcache(struct pool *, int);
1.73      simonb    267: void   dosum(void);
1.103     mycroft   268: void   dovmstat(struct timespec *, int);
1.130     he        269: void   print_total_hdr(void);
                    270: void   dovmtotal(struct timespec *, int);
1.133     chs       271: void   kread(struct nlist *, int, void *, size_t);
1.73      simonb    272: void   needhdr(int);
                    273: long   getuptime(void);
                    274: void   printhdr(void);
                    275: long   pct(long, long);
                    276: void   usage(void);
                    277: void   doforkst(void);
                    278:
                    279: void   hist_traverse(int, const char *);
                    280: void   hist_dodump(struct uvm_history *);
                    281:
                    282: int    main(int, char **);
                    283: char   **choosedrives(char **);
1.38      mrg       284:
1.29      thorpej   285: /* Namelist and memory file names. */
                    286: char   *nlistf, *memf;
                    287:
1.47      mrg       288: /* allow old usage [vmstat 1] */
                    289: #define        BACKWARD_COMPATIBILITY
                    290:
1.38      mrg       291: int
1.75      enami     292: main(int argc, char *argv[])
1.1       cgd       293: {
1.126     simonb    294:        int c, todo, verbose, wide;
1.103     mycroft   295:        struct timespec interval;
1.1       cgd       296:        int reps;
1.75      enami     297:        char errbuf[_POSIX2_LINE_MAX];
                    298:        gid_t egid = getegid();
1.88      lukem     299:        const char *histname, *hashname;
1.1       cgd       300:
1.88      lukem     301:        histname = hashname = NULL;
1.48      mrg       302:        (void)setegid(getgid());
1.13      cgd       303:        memf = nlistf = NULL;
1.126     simonb    304:        reps = todo = verbose = wide = 0;
1.103     mycroft   305:        interval.tv_sec = 0;
                    306:        interval.tv_nsec = 0;
1.130     he        307:        while ((c = getopt(argc, argv, "c:efh:HilLM:mN:stu:UvWw:")) != -1) {
1.1       cgd       308:                switch (c) {
                    309:                case 'c':
                    310:                        reps = atoi(optarg);
                    311:                        break;
1.66      cgd       312:                case 'e':
                    313:                        todo |= EVCNTSTAT;
                    314:                        break;
1.1       cgd       315:                case 'f':
                    316:                        todo |= FORKSTAT;
                    317:                        break;
1.45      thorpej   318:                case 'h':
1.88      lukem     319:                        hashname = optarg;
                    320:                        /* FALLTHROUGH */
                    321:                case 'H':
1.87      lukem     322:                        todo |= HASHSTAT;
1.45      thorpej   323:                        break;
1.1       cgd       324:                case 'i':
                    325:                        todo |= INTRSTAT;
                    326:                        break;
1.45      thorpej   327:                case 'l':
                    328:                        todo |= HISTLIST;
                    329:                        break;
1.88      lukem     330:                case 'L':
                    331:                        todo |= HASHLIST;
                    332:                        break;
1.1       cgd       333:                case 'M':
1.13      cgd       334:                        memf = optarg;
1.1       cgd       335:                        break;
                    336:                case 'm':
                    337:                        todo |= MEMSTAT;
                    338:                        break;
                    339:                case 'N':
1.13      cgd       340:                        nlistf = optarg;
1.1       cgd       341:                        break;
                    342:                case 's':
                    343:                        todo |= SUMSTAT;
                    344:                        break;
1.130     he        345:                case 't':
                    346:                        todo |= VMTOTAL;
                    347:                        break;
1.87      lukem     348:                case 'u':
                    349:                        histname = optarg;
                    350:                        /* FALLTHROUGH */
                    351:                case 'U':
                    352:                        todo |= HISTDUMP;
                    353:                        break;
1.66      cgd       354:                case 'v':
1.87      lukem     355:                        verbose++;
1.66      cgd       356:                        break;
1.126     simonb    357:                case 'W':
                    358:                        wide++;
                    359:                        break;
1.1       cgd       360:                case 'w':
1.103     mycroft   361:                        interval.tv_sec = atol(optarg);
1.1       cgd       362:                        break;
                    363:                case '?':
                    364:                default:
                    365:                        usage();
                    366:                }
                    367:        }
                    368:        argc -= optind;
                    369:        argv += optind;
                    370:
                    371:        if (todo == 0)
                    372:                todo = VMSTAT;
                    373:
1.13      cgd       374:        /*
1.48      mrg       375:         * Discard setgid privileges.  If not the running kernel, we toss
                    376:         * them away totally so that bad guys can't print interesting stuff
                    377:         * from kernel memory, otherwise switch back to kmem for the
                    378:         * duration of the kvm_openfiles() call.
1.13      cgd       379:         */
                    380:        if (nlistf != NULL || memf != NULL)
1.48      mrg       381:                (void)setgid(getgid());
                    382:        else
                    383:                (void)setegid(egid);
1.13      cgd       384:
1.75      enami     385:        kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
                    386:        if (kd == NULL)
1.87      lukem     387:                errx(1, "kvm_openfiles: %s", errbuf);
1.48      mrg       388:
1.95      simonb    389:        if (nlistf == NULL && memf == NULL)
                    390:                (void)setgid(getgid());
1.1       cgd       391:
1.13      cgd       392:        if ((c = kvm_nlist(kd, namelist)) != 0) {
1.90      lukem     393:                if (c == -1)
                    394:                        errx(1, "kvm_nlist: %s %s", "namelist", kvm_geterr(kd));
                    395:                (void)fprintf(stderr, "vmstat: undefined symbols:");
1.110     matt      396:                for (c = 0; c < sizeof(namelist) / sizeof(namelist[0])-1; c++)
1.90      lukem     397:                        if (namelist[c].n_type == 0)
                    398:                                fprintf(stderr, " %s", namelist[c].n_name);
                    399:                (void)fputc('\n', stderr);
1.1       cgd       400:                exit(1);
                    401:        }
1.133     chs       402:        if (todo & INTRSTAT)
                    403:                (void) kvm_nlist(kd, intrnl);
1.90      lukem     404:        if ((c = kvm_nlist(kd, hashnl)) == -1 || c == X_HASHNL_SIZE)
                    405:                errx(1, "kvm_nlist: %s %s", "hashnl", kvm_geterr(kd));
                    406:        if (kvm_nlist(kd, histnl) == -1)
                    407:                errx(1, "kvm_nlist: %s %s", "histnl", kvm_geterr(kd));
1.1       cgd       408:
                    409:        if (todo & VMSTAT) {
                    410:                struct winsize winsize;
                    411:
1.95      simonb    412:                dkinit(0);      /* Initialize disk stats, no disks selected. */
1.136     blymn     413:                tpinit(0);
1.49      drochner  414:
                    415:                (void)setgid(getgid()); /* don't need privs anymore */
                    416:
1.29      thorpej   417:                argv = choosedrives(argv);      /* Select disks. */
1.1       cgd       418:                winsize.ws_row = 0;
1.115     simonb    419:                (void)ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize);
1.1       cgd       420:                if (winsize.ws_row > 0)
                    421:                        winlines = winsize.ws_row;
                    422:
                    423:        }
                    424:
                    425: #ifdef BACKWARD_COMPATIBILITY
                    426:        if (*argv) {
1.103     mycroft   427:                interval.tv_sec = atol(*argv);
1.1       cgd       428:                if (*++argv)
                    429:                        reps = atoi(*argv);
                    430:        }
                    431: #endif
                    432:
1.103     mycroft   433:        if (interval.tv_sec) {
1.1       cgd       434:                if (!reps)
                    435:                        reps = -1;
                    436:        } else if (reps)
1.103     mycroft   437:                interval.tv_sec = 1;
1.1       cgd       438:
1.78      jhawk     439:
                    440:        /*
                    441:         * Statistics dumping is incompatible with the default
                    442:         * VMSTAT/dovmstat() output. So perform the interval/reps handling
                    443:         * for it here.
                    444:         */
1.130     he        445:        if ((todo & (VMSTAT|VMTOTAL)) == 0) {
1.99      enami     446:                for (;;) {
                    447:                        if (todo & (HISTLIST|HISTDUMP)) {
                    448:                                if ((todo & (HISTLIST|HISTDUMP)) ==
                    449:                                    (HISTLIST|HISTDUMP))
                    450:                                        errx(1, "you may list or dump,"
                    451:                                            " but not both!");
                    452:                                hist_traverse(todo, histname);
                    453:                                putchar('\n');
                    454:                        }
                    455:                        if (todo & FORKSTAT) {
                    456:                                doforkst();
                    457:                                putchar('\n');
                    458:                        }
                    459:                        if (todo & MEMSTAT) {
                    460:                                domem();
1.126     simonb    461:                                dopool(verbose, wide);
1.99      enami     462:                                putchar('\n');
                    463:                        }
                    464:                        if (todo & SUMSTAT) {
                    465:                                dosum();
                    466:                                putchar('\n');
                    467:                        }
                    468:                        if (todo & INTRSTAT) {
                    469:                                dointr(verbose);
                    470:                                putchar('\n');
                    471:                        }
                    472:                        if (todo & EVCNTSTAT) {
                    473:                                doevcnt(verbose);
                    474:                                putchar('\n');
                    475:                        }
                    476:                        if (todo & (HASHLIST|HASHSTAT)) {
                    477:                                if ((todo & (HASHLIST|HASHSTAT)) ==
                    478:                                    (HASHLIST|HASHSTAT))
                    479:                                        errx(1, "you may list or display,"
                    480:                                            " but not both!");
                    481:                                dohashstat(verbose, todo, hashname);
                    482:                                putchar('\n');
                    483:                        }
1.101     sommerfe  484:
                    485:                        if (reps >= 0 && --reps <=0)
1.99      enami     486:                                break;
1.103     mycroft   487:                        nanosleep(&interval, NULL);
1.87      lukem     488:                }
1.130     he        489:        } else {
                    490:                if ((todo & (VMSTAT|VMTOTAL)) == (VMSTAT|VMTOTAL)) {
                    491:                        errx(1, "you may not both do vmstat and vmtotal");
                    492:                }
                    493:                if (todo & VMSTAT)
                    494:                        dovmstat(&interval, reps);
                    495:                if (todo & VMTOTAL)
                    496:                        dovmtotal(&interval, reps);
                    497:        }
1.1       cgd       498:        exit(0);
                    499: }
                    500:
                    501: char **
1.73      simonb    502: choosedrives(char **argv)
1.1       cgd       503: {
1.38      mrg       504:        int i;
1.1       cgd       505:
                    506:        /*
                    507:         * Choose drives to be displayed.  Priority goes to (in order) drives
                    508:         * supplied as arguments, default drives.  If everything isn't filled
                    509:         * in and there are drives not taken care of, display the first few
                    510:         * that fit.
                    511:         */
1.75      enami     512: #define        BACKWARD_COMPATIBILITY
1.1       cgd       513:        for (ndrives = 0; *argv; ++argv) {
                    514: #ifdef BACKWARD_COMPATIBILITY
1.124     dsl       515:                if (isdigit((unsigned char)**argv))
1.1       cgd       516:                        break;
                    517: #endif
                    518:                for (i = 0; i < dk_ndrive; i++) {
                    519:                        if (strcmp(dr_name[i], *argv))
                    520:                                continue;
1.29      thorpej   521:                        dk_select[i] = 1;
1.1       cgd       522:                        ++ndrives;
                    523:                        break;
                    524:                }
1.136     blymn     525:                for (i = 0; i < tp_ndrive; i++) {
                    526:                        if (strcmp(tp_name[i], *argv))
                    527:                                continue;
                    528:                        tp_select[i] = 1;
                    529:                        ++ndrives;
                    530:                        break;
                    531:                }
1.1       cgd       532:        }
1.120     dbj       533:        for (i = 0; i < dk_ndrive && ndrives < 3; i++) {
1.29      thorpej   534:                if (dk_select[i])
1.1       cgd       535:                        continue;
1.29      thorpej   536:                dk_select[i] = 1;
1.1       cgd       537:                ++ndrives;
                    538:        }
1.136     blymn     539:
                    540:        for (i = 0; i < tp_ndrive && ndrives < 3; i++) {
                    541:                if (tp_select[i])
                    542:                        continue;
                    543:                tp_select[i] = 1;
                    544:                ++ndrives;
                    545:        }
                    546:
1.75      enami     547:        return (argv);
1.1       cgd       548: }
                    549:
                    550: long
1.73      simonb    551: getuptime(void)
1.1       cgd       552: {
1.30      cgd       553:        static struct timeval boottime;
1.105     nathanw   554:        struct timeval now, diff;
1.1       cgd       555:        time_t uptime;
                    556:
1.30      cgd       557:        if (boottime.tv_sec == 0)
1.133     chs       558:                kread(namelist, X_BOOTTIME, &boottime, sizeof(boottime));
1.138.2.1! simonb    559: #ifdef __HAVE_TIMECOUNTER
        !           560:        kread(namelist, X_TIME_SECOND, &now.tv_sec, sizeof(now));
        !           561:        now.tv_usec = 0;
        !           562: #else
        !           563:        kread(namelist, X_TIME_SECOND, &now, sizeof(now));
        !           564: #endif
        !           565:        uptime = now - boottime.tv_sec;
1.87      lukem     566:        if (uptime <= 0 || uptime > 60*60*24*365*10)
                    567:                errx(1, "time makes no sense; namelist must be wrong.");
1.75      enami     568:        return (uptime);
1.1       cgd       569: }
                    570:
                    571: int    hz, hdrcnt;
                    572:
                    573: void
1.130     he        574: print_total_hdr()
                    575: {
                    576:
                    577:        (void)printf("procs            memory\n");
                    578:        (void)printf("ru dw pw sl sw");
                    579:        (void)printf("   total-v  active-v  active-r");
                    580:        (void)printf(" vm-sh avm-sh rm-sh arm-sh free\n");
                    581:        hdrcnt = winlines - 2;
                    582: }
                    583:
                    584: void
                    585: dovmtotal(struct timespec *interval, int reps)
                    586: {
                    587:        struct vmtotal total;
                    588:        int mib[2];
                    589:        size_t size;
                    590:
                    591:        (void)signal(SIGCONT, needhdr);
                    592:
                    593:        for (hdrcnt = 1;;) {
                    594:                if (!--hdrcnt)
                    595:                        print_total_hdr();
                    596:                if (memf != NULL) {
                    597:                        printf("Unable to get vmtotals from crash dump.\n");
                    598:                        memset(&total, 0, sizeof(total));
                    599:                } else {
                    600:                        size = sizeof(total);
                    601:                        mib[0] = CTL_VM;
                    602:                        mib[1] = VM_METER;
                    603:                        if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
                    604:                                printf("Can't get vmtotals: %s\n",
                    605:                                    strerror(errno));
                    606:                                memset(&total, 0, sizeof(total));
                    607:                        }
                    608:                }
                    609:                printf("%2d ", total.t_rq);
                    610:                printf("%2d ", total.t_dw);
                    611:                printf("%2d ", total.t_pw);
                    612:                printf("%2d ", total.t_sl);
                    613:                printf("%2d ", total.t_sw);
                    614:
                    615:                printf("%9d ", total.t_vm);
                    616:                printf("%9d ", total.t_avm);
                    617:                printf("%9d ", total.t_arm);
                    618:                printf("%5d ", total.t_vmshr);
                    619:                printf("%6d ", total.t_avmshr);
                    620:                printf("%5d ", total.t_rmshr);
                    621:                printf("%6d ", total.t_armshr);
                    622:                printf("%5d",  total.t_free);
                    623:
                    624:                putchar('\n');
                    625:
                    626:                (void)fflush(stdout);
                    627:                if (reps >= 0 && --reps <= 0)
                    628:                        break;
                    629:
                    630:                nanosleep(interval, NULL);
                    631:        }
                    632: }
                    633:
                    634: void
1.103     mycroft   635: dovmstat(struct timespec *interval, int reps)
1.1       cgd       636: {
                    637:        struct vmtotal total;
                    638:        time_t uptime, halfuptime;
1.17      cgd       639:        int mib[2];
                    640:        size_t size;
1.41      mrg       641:        int pagesize = getpagesize();
1.1       cgd       642:
                    643:        uptime = getuptime();
                    644:        halfuptime = uptime / 2;
                    645:        (void)signal(SIGCONT, needhdr);
                    646:
1.13      cgd       647:        if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0)
1.133     chs       648:                kread(namelist, X_STATHZ, &hz, sizeof(hz));
1.1       cgd       649:        if (!hz)
1.133     chs       650:                kread(namelist, X_HZ, &hz, sizeof(hz));
1.1       cgd       651:
                    652:        for (hdrcnt = 1;;) {
                    653:                if (!--hdrcnt)
                    654:                        printhdr();
1.29      thorpej   655:                /* Read new disk statistics */
                    656:                dkreadstats();
1.133     chs       657:                kread(namelist, X_UVMEXP, &uvmexp, sizeof(uvmexp));
1.58      thorpej   658:                if (memf != NULL) {
                    659:                        /*
                    660:                         * XXX Can't do this if we're reading a crash
                    661:                         * XXX dump because they're lazily-calculated.
                    662:                         */
                    663:                        printf("Unable to get vmtotals from crash dump.\n");
1.53      perry     664:                        memset(&total, 0, sizeof(total));
1.58      thorpej   665:                } else {
                    666:                        size = sizeof(total);
                    667:                        mib[0] = CTL_VM;
                    668:                        mib[1] = VM_METER;
                    669:                        if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
                    670:                                printf("Can't get vmtotals: %s\n",
                    671:                                    strerror(errno));
                    672:                                memset(&total, 0, sizeof(total));
                    673:                        }
1.13      cgd       674:                }
1.120     dbj       675:                (void)printf("%2d %d %d",
1.13      cgd       676:                    total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
1.75      enami     677: #define        pgtok(a) (long)((a) * (pagesize >> 10))
1.38      mrg       678: #define        rate(x) (u_long)(((x) + halfuptime) / uptime)   /* round */
1.104     mrg       679:                (void)printf(" %6ld %6ld ",
1.1       cgd       680:                    pgtok(total.t_avm), pgtok(total.t_free));
1.42      mrg       681:                (void)printf("%4lu ", rate(uvmexp.faults - ouvmexp.faults));
                    682:                (void)printf("%3lu ", rate(uvmexp.pdreact - ouvmexp.pdreact));
1.46      mrg       683:                (void)printf("%3lu ", rate(uvmexp.pageins - ouvmexp.pageins));
1.44      mrg       684:                (void)printf("%4lu ",
                    685:                    rate(uvmexp.pgswapout - ouvmexp.pgswapout));
                    686:                (void)printf("%4lu ", rate(uvmexp.pdfreed - ouvmexp.pdfreed));
                    687:                (void)printf("%4lu ", rate(uvmexp.pdscans - ouvmexp.pdscans));
1.42      mrg       688:                dkstats();
1.136     blymn     689:                tpstats();
1.42      mrg       690:                (void)printf("%4lu %4lu %3lu ",
                    691:                    rate(uvmexp.intrs - ouvmexp.intrs),
                    692:                    rate(uvmexp.syscalls - ouvmexp.syscalls),
                    693:                    rate(uvmexp.swtch - ouvmexp.swtch));
                    694:                cpustats();
1.87      lukem     695:                putchar('\n');
1.42      mrg       696:                (void)fflush(stdout);
                    697:                if (reps >= 0 && --reps <= 0)
                    698:                        break;
                    699:                ouvmexp = uvmexp;
1.103     mycroft   700:                uptime = interval->tv_sec;
1.1       cgd       701:                /*
                    702:                 * We round upward to avoid losing low-frequency events
                    703:                 * (i.e., >= 1 per interval but < 1 per second).
                    704:                 */
1.33      thorpej   705:                halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2;
1.103     mycroft   706:                nanosleep(interval, NULL);
1.1       cgd       707:        }
                    708: }
                    709:
1.38      mrg       710: void
1.73      simonb    711: printhdr(void)
1.1       cgd       712: {
1.38      mrg       713:        int i;
1.1       cgd       714:
1.104     mrg       715:        (void)printf(" procs    memory      page%*s", 23, "");
1.29      thorpej   716:        if (ndrives > 0)
1.70      sommerfe  717:                (void)printf("%s %*sfaults      cpu\n",
1.75      enami     718:                    ((ndrives > 1) ? "disks" : "disk"),
                    719:                    ((ndrives > 1) ? ndrives * 3 - 4 : 0), "");
1.1       cgd       720:        else
1.29      thorpej   721:                (void)printf("%*s  faults   cpu\n",
1.75      enami     722:                    ndrives * 3, "");
1.29      thorpej   723:
1.104     mrg       724:        (void)printf(" r b w    avm    fre  flt  re  pi   po   fr   sr ");
1.1       cgd       725:        for (i = 0; i < dk_ndrive; i++)
1.29      thorpej   726:                if (dk_select[i])
1.1       cgd       727:                        (void)printf("%c%c ", dr_name[i][0],
                    728:                            dr_name[i][strlen(dr_name[i]) - 1]);
                    729:        (void)printf("  in   sy  cs us sy id\n");
                    730:        hdrcnt = winlines - 2;
                    731: }
                    732:
                    733: /*
                    734:  * Force a header to be prepended to the next output.
                    735:  */
                    736: void
1.73      simonb    737: needhdr(int dummy)
1.1       cgd       738: {
                    739:
                    740:        hdrcnt = 1;
                    741: }
                    742:
1.38      mrg       743: long
1.73      simonb    744: pct(long top, long bot)
1.1       cgd       745: {
1.13      cgd       746:        long ans;
                    747:
1.1       cgd       748:        if (bot == 0)
1.75      enami     749:                return (0);
1.13      cgd       750:        ans = (quad_t)top * 100 / bot;
                    751:        return (ans);
1.1       cgd       752: }
                    753:
1.38      mrg       754: #define        PCT(top, bot) (int)pct((long)(top), (long)(bot))
1.1       cgd       755:
                    756: void
1.73      simonb    757: dosum(void)
1.1       cgd       758: {
                    759:        struct nchstats nchstats;
1.123     enami     760:        u_long nchtotal;
1.1       cgd       761:
1.133     chs       762:        kread(namelist, X_UVMEXP, &uvmexp, sizeof(uvmexp));
1.41      mrg       763:
1.44      mrg       764:        (void)printf("%9u bytes per page\n", uvmexp.pagesize);
                    765:
1.81      thorpej   766:        (void)printf("%9u page color%s\n",
                    767:            uvmexp.ncolors, uvmexp.ncolors == 1 ? "" : "s");
                    768:
1.44      mrg       769:        (void)printf("%9u pages managed\n", uvmexp.npages);
                    770:        (void)printf("%9u pages free\n", uvmexp.free);
                    771:        (void)printf("%9u pages active\n", uvmexp.active);
                    772:        (void)printf("%9u pages inactive\n", uvmexp.inactive);
                    773:        (void)printf("%9u pages paging\n", uvmexp.paging);
                    774:        (void)printf("%9u pages wired\n", uvmexp.wired);
1.63      thorpej   775:        (void)printf("%9u zero pages\n", uvmexp.zeropages);
1.44      mrg       776:        (void)printf("%9u reserve pagedaemon pages\n",
                    777:            uvmexp.reserve_pagedaemon);
                    778:        (void)printf("%9u reserve kernel pages\n", uvmexp.reserve_kernel);
1.94      chs       779:        (void)printf("%9u anonymous pages\n", uvmexp.anonpages);
                    780:        (void)printf("%9u cached file pages\n", uvmexp.filepages);
                    781:        (void)printf("%9u cached executable pages\n", uvmexp.execpages);
1.44      mrg       782:
                    783:        (void)printf("%9u minimum free pages\n", uvmexp.freemin);
                    784:        (void)printf("%9u target free pages\n", uvmexp.freetarg);
                    785:        (void)printf("%9u target inactive pages\n", uvmexp.inactarg);
                    786:        (void)printf("%9u maximum wired pages\n", uvmexp.wiredmax);
                    787:
                    788:        (void)printf("%9u swap devices\n", uvmexp.nswapdev);
                    789:        (void)printf("%9u swap pages\n", uvmexp.swpages);
                    790:        (void)printf("%9u swap pages in use\n", uvmexp.swpginuse);
                    791:        (void)printf("%9u swap allocations\n", uvmexp.nswget);
                    792:
1.43      mrg       793:        (void)printf("%9u total faults taken\n", uvmexp.faults);
                    794:        (void)printf("%9u traps\n", uvmexp.traps);
                    795:        (void)printf("%9u device interrupts\n", uvmexp.intrs);
1.121     wiz       796:        (void)printf("%9u CPU context switches\n", uvmexp.swtch);
1.43      mrg       797:        (void)printf("%9u software interrupts\n", uvmexp.softs);
                    798:        (void)printf("%9u system calls\n", uvmexp.syscalls);
1.60      fredb     799:        (void)printf("%9u pagein requests\n", uvmexp.pageins);
                    800:        (void)printf("%9u pageout requests\n", uvmexp.pdpageouts);
1.43      mrg       801:        (void)printf("%9u swap ins\n", uvmexp.swapins);
                    802:        (void)printf("%9u swap outs\n", uvmexp.swapouts);
1.60      fredb     803:        (void)printf("%9u pages swapped in\n", uvmexp.pgswapin);
                    804:        (void)printf("%9u pages swapped out\n", uvmexp.pgswapout);
1.43      mrg       805:        (void)printf("%9u forks total\n", uvmexp.forks);
                    806:        (void)printf("%9u forks blocked parent\n", uvmexp.forks_ppwait);
                    807:        (void)printf("%9u forks shared address space with parent\n",
                    808:            uvmexp.forks_sharevm);
1.63      thorpej   809:        (void)printf("%9u pagealloc zero wanted and avail\n",
                    810:            uvmexp.pga_zerohit);
                    811:        (void)printf("%9u pagealloc zero wanted and not avail\n",
                    812:            uvmexp.pga_zeromiss);
1.68      thorpej   813:        (void)printf("%9u aborts of idle page zeroing\n",
                    814:            uvmexp.zeroaborts);
1.79      thorpej   815:        (void)printf("%9u pagealloc desired color avail\n",
                    816:            uvmexp.colorhit);
                    817:        (void)printf("%9u pagealloc desired color not avail\n",
                    818:            uvmexp.colormiss);
1.44      mrg       819:
                    820:        (void)printf("%9u faults with no memory\n", uvmexp.fltnoram);
                    821:        (void)printf("%9u faults with no anons\n", uvmexp.fltnoanon);
1.43      mrg       822:        (void)printf("%9u faults had to wait on pages\n", uvmexp.fltpgwait);
                    823:        (void)printf("%9u faults found released page\n", uvmexp.fltpgrele);
                    824:        (void)printf("%9u faults relock (%u ok)\n", uvmexp.fltrelck,
                    825:            uvmexp.fltrelckok);
                    826:        (void)printf("%9u anon page faults\n", uvmexp.fltanget);
                    827:        (void)printf("%9u anon retry faults\n", uvmexp.fltanretry);
                    828:        (void)printf("%9u amap copy faults\n", uvmexp.fltamcopy);
                    829:        (void)printf("%9u neighbour anon page faults\n", uvmexp.fltnamap);
                    830:        (void)printf("%9u neighbour object page faults\n", uvmexp.fltnomap);
                    831:        (void)printf("%9u locked pager get faults\n", uvmexp.fltlget);
                    832:        (void)printf("%9u unlocked pager get faults\n", uvmexp.fltget);
                    833:        (void)printf("%9u anon faults\n", uvmexp.flt_anon);
                    834:        (void)printf("%9u anon copy on write faults\n", uvmexp.flt_acow);
                    835:        (void)printf("%9u object faults\n", uvmexp.flt_obj);
                    836:        (void)printf("%9u promote copy faults\n", uvmexp.flt_prcopy);
                    837:        (void)printf("%9u promote zero fill faults\n", uvmexp.flt_przero);
1.44      mrg       838:
                    839:        (void)printf("%9u times daemon wokeup\n",uvmexp.pdwoke);
                    840:        (void)printf("%9u revolutions of the clock hand\n", uvmexp.pdrevs);
                    841:        (void)printf("%9u times daemon attempted swapout\n", uvmexp.pdswout);
                    842:        (void)printf("%9u pages freed by daemon\n", uvmexp.pdfreed);
                    843:        (void)printf("%9u pages scanned by daemon\n", uvmexp.pdscans);
1.75      enami     844:        (void)printf("%9u anonymous pages scanned by daemon\n",
                    845:            uvmexp.pdanscan);
1.44      mrg       846:        (void)printf("%9u object pages scanned by daemon\n", uvmexp.pdobscan);
                    847:        (void)printf("%9u pages reactivated\n", uvmexp.pdreact);
1.123     enami     848:        (void)printf("%9u anonymous pages reactivated\n", uvmexp.pdreanon);
                    849:        (void)printf("%9u cached file pages reactivated\n", uvmexp.pdrefile);
                    850:        (void)printf("%9u cached executable pages reactivated\n",
                    851:            uvmexp.pdreexec);
1.44      mrg       852:        (void)printf("%9u pages found busy by daemon\n", uvmexp.pdbusy);
                    853:        (void)printf("%9u total pending pageouts\n", uvmexp.pdpending);
                    854:        (void)printf("%9u pages deactivated\n", uvmexp.pddeact);
1.123     enami     855:
1.133     chs       856:        kread(namelist, X_NCHSTATS, &nchstats, sizeof(nchstats));
1.1       cgd       857:        nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
                    858:            nchstats.ncs_badhits + nchstats.ncs_falsehits +
                    859:            nchstats.ncs_miss + nchstats.ncs_long;
1.123     enami     860:        (void)printf("%9lu total name lookups\n", nchtotal);
                    861:        (void)printf("%9lu good hits\n", nchstats.ncs_goodhits);
                    862:        (void)printf("%9lu negative hits\n", nchstats.ncs_neghits);
                    863:        (void)printf("%9lu bad hits\n", nchstats.ncs_badhits);
                    864:        (void)printf("%9lu false hits\n", nchstats.ncs_falsehits);
                    865:        (void)printf("%9lu miss\n", nchstats.ncs_miss);
                    866:        (void)printf("%9lu too long\n", nchstats.ncs_long);
                    867:        (void)printf("%9lu pass2 hits\n", nchstats.ncs_pass2);
                    868:        (void)printf("%9lu 2passes\n", nchstats.ncs_2passes);
1.1       cgd       869:        (void)printf(
                    870:            "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
                    871:            "", PCT(nchstats.ncs_goodhits, nchtotal),
                    872:            PCT(nchstats.ncs_neghits, nchtotal),
                    873:            PCT(nchstats.ncs_pass2, nchtotal));
                    874:        (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
                    875:            PCT(nchstats.ncs_badhits, nchtotal),
                    876:            PCT(nchstats.ncs_falsehits, nchtotal),
                    877:            PCT(nchstats.ncs_long, nchtotal));
                    878: }
                    879:
                    880: void
1.73      simonb    881: doforkst(void)
1.1       cgd       882: {
1.41      mrg       883:
1.133     chs       884:        kread(namelist, X_UVMEXP, &uvmexp, sizeof(uvmexp));
1.58      thorpej   885:
1.41      mrg       886:        (void)printf("%u forks total\n", uvmexp.forks);
                    887:        (void)printf("%u forks blocked parent\n", uvmexp.forks_ppwait);
                    888:        (void)printf("%u forks shared address space with parent\n",
                    889:            uvmexp.forks_sharevm);
1.1       cgd       890: }
                    891:
                    892: void
1.73      simonb    893: dkstats(void)
1.1       cgd       894: {
1.101     sommerfe  895:        int dn;
1.1       cgd       896:        double etime;
                    897:
1.29      thorpej   898:        /* Calculate disk stat deltas. */
                    899:        dkswap();
1.101     sommerfe  900:        etime = cur.cp_etime;
                    901:
1.1       cgd       902:        for (dn = 0; dn < dk_ndrive; ++dn) {
1.29      thorpej   903:                if (!dk_select[dn])
1.1       cgd       904:                        continue;
1.104     mrg       905:                (void)printf("%2.0f ",
                    906:                    (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime);
1.1       cgd       907:        }
                    908: }
                    909:
                    910: void
1.136     blymn     911: tpstats(void)
                    912: {
                    913:        int dn;
                    914:        double etime;
                    915:
                    916:        /* Calculate tape stat deltas. */
                    917:        tpswap();
                    918:        etime = cur.cp_etime;
                    919:
                    920:        for (dn = 0; dn < tp_ndrive; ++dn) {
                    921:                if (!tp_select[dn])
                    922:                        continue;
                    923:                (void)printf("%2.0f ",
                    924:                    (cur_tape.rxfer[dn] + cur_tape.wxfer[dn]) / etime);
                    925:        }
                    926: }
                    927:
                    928: void
1.73      simonb    929: cpustats(void)
1.1       cgd       930: {
1.38      mrg       931:        int state;
1.129     dsl       932:        double pcnt, total;
1.120     dbj       933:        double stat_us, stat_sy, stat_id;
1.1       cgd       934:
                    935:        total = 0;
                    936:        for (state = 0; state < CPUSTATES; ++state)
1.29      thorpej   937:                total += cur.cp_time[state];
1.1       cgd       938:        if (total)
1.129     dsl       939:                pcnt = 100 / total;
1.1       cgd       940:        else
1.129     dsl       941:                pcnt = 0;
                    942:        stat_us = (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * pcnt;
                    943:        stat_sy = (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * pcnt;
                    944:        stat_id = cur.cp_time[CP_IDLE] * pcnt;
1.120     dbj       945:        (void)printf("%*.0f ", ((stat_sy >= 100) ? 1 : 2), stat_us);
1.133     chs       946:        (void)printf("%*.0f ", ((stat_us >= 100 || stat_id >= 100) ? 1 : 2),
                    947:                     stat_sy);
1.120     dbj       948:        (void)printf("%2.0f", stat_id);
1.1       cgd       949: }
                    950:
                    951: void
1.66      cgd       952: dointr(int verbose)
1.1       cgd       953: {
1.138     nonaka    954:        unsigned long *intrcnt, *ointrcnt;
1.85      enami     955:        unsigned long long inttotal, uptime;
1.38      mrg       956:        int nintr, inamlen;
1.138     nonaka    957:        char *intrname, *ointrname;
1.28      cgd       958:        struct evcntlist allevents;
                    959:        struct evcnt evcnt, *evptr;
1.66      cgd       960:        char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX];
1.1       cgd       961:
1.133     chs       962:        inttotal = 0;
1.1       cgd       963:        uptime = getuptime();
1.83      matt      964:        (void)printf("%-34s %16s %8s\n", "interrupt", "total", "rate");
1.133     chs       965:        nintr = intrnl[X_EINTRCNT].n_value - intrnl[X_INTRCNT].n_value;
                    966:        inamlen = intrnl[X_EINTRNAMES].n_value - intrnl[X_INTRNAMES].n_value;
                    967:        if (nintr != 0 && inamlen != 0) {
1.138     nonaka    968:                ointrcnt = intrcnt = malloc((size_t)nintr);
                    969:                ointrname = intrname = malloc((size_t)inamlen);
1.133     chs       970:                if (intrcnt == NULL || intrname == NULL)
                    971:                        errx(1, "%s", "");
                    972:                kread(intrnl, X_INTRCNT, intrcnt, (size_t)nintr);
                    973:                kread(intrnl, X_INTRNAMES, intrname, (size_t)inamlen);
                    974:                nintr /= sizeof(long);
                    975:                while (--nintr >= 0) {
                    976:                        if (*intrcnt || verbose)
                    977:                                (void)printf("%-34s %16llu %8llu\n", intrname,
                    978:                                             (unsigned long long)*intrcnt,
                    979:                                             (unsigned long long)
                    980:                                             (*intrcnt / uptime));
                    981:                        intrname += strlen(intrname) + 1;
                    982:                        inttotal += *intrcnt++;
                    983:                }
1.138     nonaka    984:                free(ointrcnt);
                    985:                free(ointrname);
1.1       cgd       986:        }
1.133     chs       987:
                    988:        kread(namelist, X_ALLEVENTS, &allevents, sizeof allevents);
                    989:        evptr = TAILQ_FIRST(&allevents);
1.28      cgd       990:        while (evptr) {
1.87      lukem     991:                deref_kptr(evptr, &evcnt, sizeof(evcnt), "event chain trashed");
1.133     chs       992:                evptr = TAILQ_NEXT(&evcnt, ev_list);
1.66      cgd       993:                if (evcnt.ev_type != EVCNT_TYPE_INTR)
                    994:                        continue;
                    995:
                    996:                if (evcnt.ev_count == 0 && !verbose)
                    997:                        continue;
                    998:
1.87      lukem     999:                deref_kptr(evcnt.ev_group, evgroup, evcnt.ev_grouplen + 1,
                   1000:                    "event chain trashed");
                   1001:                deref_kptr(evcnt.ev_name, evname, evcnt.ev_namelen + 1,
                   1002:                    "event chain trashed");
1.66      cgd      1003:
1.85      enami    1004:                (void)printf("%s %s%*s %16llu %8llu\n", evgroup, evname,
1.83      matt     1005:                    34 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "",
1.85      enami    1006:                    (unsigned long long)evcnt.ev_count,
                   1007:                    (unsigned long long)(evcnt.ev_count / uptime));
1.66      cgd      1008:
                   1009:                inttotal += evcnt.ev_count++;
                   1010:        }
1.85      enami    1011:        (void)printf("%-34s %16llu %8llu\n", "Total", inttotal,
                   1012:            (unsigned long long)(inttotal / uptime));
1.66      cgd      1013: }
                   1014:
                   1015: void
                   1016: doevcnt(int verbose)
                   1017: {
1.83      matt     1018:        static const char * evtypes [] = { "misc", "intr", "trap" };
1.85      enami    1019:        unsigned long long uptime;
1.66      cgd      1020:        struct evcntlist allevents;
                   1021:        struct evcnt evcnt, *evptr;
                   1022:        char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX];
                   1023:
                   1024:        /* XXX should print type! */
                   1025:
                   1026:        uptime = getuptime();
1.83      matt     1027:        (void)printf("%-34s %16s %8s %s\n", "event", "total", "rate", "type");
1.133     chs      1028:        kread(namelist, X_ALLEVENTS, &allevents, sizeof allevents);
                   1029:        evptr = TAILQ_FIRST(&allevents);
1.66      cgd      1030:        while (evptr) {
1.87      lukem    1031:                deref_kptr(evptr, &evcnt, sizeof(evcnt), "event chain trashed");
1.32      cgd      1032:
1.133     chs      1033:                evptr = TAILQ_NEXT(&evcnt, ev_list);
1.66      cgd      1034:                if (evcnt.ev_count == 0 && !verbose)
                   1035:                        continue;
                   1036:
1.87      lukem    1037:                deref_kptr(evcnt.ev_group, evgroup, evcnt.ev_grouplen + 1,
                   1038:                    "event chain trashed");
                   1039:                deref_kptr(evcnt.ev_name, evname, evcnt.ev_namelen + 1,
                   1040:                    "event chain trashed");
1.66      cgd      1041:
1.85      enami    1042:                (void)printf("%s %s%*s %16llu %8llu %s\n", evgroup, evname,
1.83      matt     1043:                    34 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "",
1.85      enami    1044:                    (unsigned long long)evcnt.ev_count,
                   1045:                    (unsigned long long)(evcnt.ev_count / uptime),
1.86      enami    1046:                    (evcnt.ev_type < sizeof(evtypes)/sizeof(evtypes[0]) ?
                   1047:                        evtypes[evcnt.ev_type] : "?"));
1.18      pk       1048:        }
1.1       cgd      1049: }
                   1050:
1.109     thorpej  1051: static char memname[64];
1.1       cgd      1052:
                   1053: void
1.73      simonb   1054: domem(void)
1.1       cgd      1055: {
1.38      mrg      1056:        struct kmembuckets *kp;
1.109     thorpej  1057:        struct malloc_type ks, *ksp;
1.38      mrg      1058:        int i, j;
1.13      cgd      1059:        int len, size, first;
                   1060:        long totuse = 0, totfree = 0, totreq = 0;
1.1       cgd      1061:        struct kmembuckets buckets[MINBUCKET + 16];
                   1062:
1.133     chs      1063:        kread(namelist, X_KMEMBUCKETS, buckets, sizeof(buckets));
1.34      thorpej  1064:        for (first = 1, i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16;
                   1065:            i++, kp++) {
1.1       cgd      1066:                if (kp->kb_calls == 0)
                   1067:                        continue;
1.34      thorpej  1068:                if (first) {
                   1069:                        (void)printf("Memory statistics by bucket size\n");
                   1070:                        (void)printf(
                   1071:                 "    Size   In Use   Free   Requests  HighWater  Couldfree\n");
                   1072:                        first = 0;
                   1073:                }
1.1       cgd      1074:                size = 1 << i;
1.75      enami    1075:                (void)printf("%8d %8ld %6ld %10ld %7ld %10ld\n", size,
                   1076:                    kp->kb_total - kp->kb_totalfree,
                   1077:                    kp->kb_totalfree, kp->kb_calls,
                   1078:                    kp->kb_highwat, kp->kb_couldfree);
1.1       cgd      1079:                totfree += size * kp->kb_totalfree;
1.34      thorpej  1080:        }
                   1081:
                   1082:        /*
                   1083:         * If kmem statistics are not being gathered by the kernel,
                   1084:         * first will still be 1.
                   1085:         */
                   1086:        if (first) {
1.87      lukem    1087:                warnx("Kmem statistics are not being gathered by the kernel.");
1.34      thorpej  1088:                return;
1.1       cgd      1089:        }
                   1090:
1.13      cgd      1091:        (void)printf("\nMemory usage type by bucket size\n");
                   1092:        (void)printf("    Size  Type(s)\n");
                   1093:        kp = &buckets[MINBUCKET];
                   1094:        for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) {
                   1095:                if (kp->kb_calls == 0)
                   1096:                        continue;
                   1097:                first = 1;
                   1098:                len = 8;
1.133     chs      1099:                for (kread(namelist, X_KMEMSTAT, &ksp, sizeof(ksp));
1.109     thorpej  1100:                     ksp != NULL; ksp = ks.ks_next) {
                   1101:                        deref_kptr(ksp, &ks, sizeof(ks), "malloc type");
                   1102:                        if (ks.ks_calls == 0)
1.13      cgd      1103:                                continue;
1.109     thorpej  1104:                        if ((ks.ks_size & j) == 0)
1.13      cgd      1105:                                continue;
1.109     thorpej  1106:                        deref_kptr(ks.ks_shortdesc, memname,
                   1107:                            sizeof(memname), "malloc type name");
                   1108:                        len += 2 + strlen(memname);
1.13      cgd      1109:                        if (first)
1.109     thorpej  1110:                                printf("%8d  %s", j, memname);
1.13      cgd      1111:                        else
                   1112:                                printf(",");
                   1113:                        if (len >= 80) {
                   1114:                                printf("\n\t ");
1.109     thorpej  1115:                                len = 10 + strlen(memname);
1.13      cgd      1116:                        }
                   1117:                        if (!first)
1.109     thorpej  1118:                                printf(" %s", memname);
1.13      cgd      1119:                        first = 0;
                   1120:                }
1.87      lukem    1121:                putchar('\n');
1.13      cgd      1122:        }
                   1123:
1.1       cgd      1124:        (void)printf(
1.119     simonb   1125:            "\nMemory statistics by type                           Type  Kern\n");
1.13      cgd      1126:        (void)printf(
1.36      is       1127: "         Type  InUse MemUse HighUse  Limit Requests Limit Limit Size(s)\n");
1.133     chs      1128:        for (kread(namelist, X_KMEMSTAT, &ksp, sizeof(ksp));
1.109     thorpej  1129:             ksp != NULL; ksp = ks.ks_next) {
                   1130:                deref_kptr(ksp, &ks, sizeof(ks), "malloc type");
                   1131:                if (ks.ks_calls == 0)
1.1       cgd      1132:                        continue;
1.109     thorpej  1133:                deref_kptr(ks.ks_shortdesc, memname,
                   1134:                    sizeof(memname), "malloc type name");
1.36      is       1135:                (void)printf("%14s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u",
1.109     thorpej  1136:                    memname,
                   1137:                    ks.ks_inuse, (ks.ks_memuse + 1023) / 1024,
                   1138:                    (ks.ks_maxused + 1023) / 1024,
                   1139:                    (ks.ks_limit + 1023) / 1024, ks.ks_calls,
                   1140:                    ks.ks_limblocks, ks.ks_mapblocks);
1.13      cgd      1141:                first = 1;
                   1142:                for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
1.109     thorpej  1143:                        if ((ks.ks_size & j) == 0)
1.13      cgd      1144:                                continue;
                   1145:                        if (first)
                   1146:                                printf("  %d", j);
                   1147:                        else
                   1148:                                printf(",%d", j);
                   1149:                        first = 0;
                   1150:                }
                   1151:                printf("\n");
1.109     thorpej  1152:                totuse += ks.ks_memuse;
                   1153:                totreq += ks.ks_calls;
1.1       cgd      1154:        }
1.102     soren    1155:        (void)printf("\nMemory totals:  In Use    Free    Requests\n");
                   1156:        (void)printf("              %7ldK %6ldK    %8ld\n\n",
1.75      enami    1157:            (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq);
1.51      pk       1158: }
                   1159:
                   1160: void
1.126     simonb   1161: dopool(int verbose, int wide)
1.51      pk       1162: {
1.69      enami    1163:        int first, ovflw;
1.87      lukem    1164:        void *addr;
1.126     simonb   1165:        long total, inuse, this_total, this_inuse;
1.137     chs      1166:        LIST_HEAD(,pool) pool_head;
1.51      pk       1167:        struct pool pool, *pp = &pool;
1.98      christos 1168:        struct pool_allocator pa;
1.87      lukem    1169:        char name[32], maxp[32];
1.51      pk       1170:
1.133     chs      1171:        kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head));
1.137     chs      1172:        addr = LIST_FIRST(&pool_head);
1.51      pk       1173:
1.126     simonb   1174:        total = inuse = 0;
                   1175:
1.137     chs      1176:        for (first = 1; addr != NULL; addr = LIST_NEXT(pp, pr_poollist) ) {
1.87      lukem    1177:                deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed");
1.98      christos 1178:                deref_kptr(pp->pr_alloc, &pa, sizeof(pa),
1.125     dsainty  1179:                    "pool allocator trashed");
1.87      lukem    1180:                deref_kptr(pp->pr_wchan, name, sizeof(name),
1.98      christos 1181:                    "pool wait channel trashed");
1.87      lukem    1182:                name[sizeof(name)-1] = '\0';
1.51      pk       1183:
                   1184:                if (first) {
                   1185:                        (void)printf("Memory resource pool statistics\n");
                   1186:                        (void)printf(
1.126     simonb   1187:                            "%-*s%*s%*s%5s%*s%s%s%*s%*s%6s%s%6s%6s%6s%5s%s%s\n",
                   1188:                            wide ? 16 : 11, "Name",
                   1189:                            wide ? 6 : 5, "Size",
                   1190:                            wide ? 12 : 9, "Requests",
1.75      enami    1191:                            "Fail",
1.126     simonb   1192:                            wide ? 12 : 9, "Releases",
                   1193:                            wide ? " InUse" : "",
                   1194:                            wide ? " Avail" : "",
                   1195:                            wide ? 7 : 6, "Pgreq",
                   1196:                            wide ? 7 : 6, "Pgrel",
1.75      enami    1197:                            "Npage",
1.126     simonb   1198:                            wide ? " PageSz" : "",
1.75      enami    1199:                            "Hiwat",
                   1200:                            "Minpg",
                   1201:                            "Maxpg",
1.126     simonb   1202:                            "Idle",
                   1203:                            wide ? " Flags" : "",
                   1204:                            wide ? "   Util" : "");
1.51      pk       1205:                        first = 0;
                   1206:                }
1.113     dsl      1207:                if (pp->pr_nget == 0 && !verbose)
                   1208:                        continue;
1.51      pk       1209:                if (pp->pr_maxpages == UINT_MAX)
1.116     itojun   1210:                        snprintf(maxp, sizeof(maxp), "inf");
1.51      pk       1211:                else
1.116     itojun   1212:                        snprintf(maxp, sizeof(maxp), "%u", pp->pr_maxpages);
1.69      enami    1213: /*
                   1214:  * Print single word.  `ovflow' is number of characters didn't fit
                   1215:  * on the last word.  `fmt' is a format string to print this word.
                   1216:  * It must contain asterisk for field width.  `width' is a width
                   1217:  * occupied by this word.  `fixed' is a number of constant chars in
                   1218:  * `fmt'.  `val' is a value to be printed using format string `fmt'.
                   1219:  */
                   1220: #define        PRWORD(ovflw, fmt, width, fixed, val) do {      \
                   1221:        (ovflw) += printf((fmt),                        \
                   1222:            (width) - (fixed) - (ovflw) > 0 ?           \
                   1223:            (width) - (fixed) - (ovflw) : 0,            \
                   1224:            (val)) - (width);                           \
                   1225:        if ((ovflw) < 0)                                \
                   1226:                (ovflw) = 0;                            \
                   1227: } while (/* CONSTCOND */0)
                   1228:                ovflw = 0;
1.126     simonb   1229:                PRWORD(ovflw, "%-*s", wide ? 16 : 11, 0, name);
                   1230:                PRWORD(ovflw, " %*u", wide ? 6 : 5, 1, pp->pr_size);
                   1231:                PRWORD(ovflw, " %*lu", wide ? 12 : 9, 1, pp->pr_nget);
1.69      enami    1232:                PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nfail);
1.126     simonb   1233:                PRWORD(ovflw, " %*lu", wide ? 12 : 9, 1, pp->pr_nput);
                   1234:                if (wide)
                   1235:                        PRWORD(ovflw, " %*u", 6, 1, pp->pr_nout);
                   1236:                if (wide)
                   1237:                        PRWORD(ovflw, " %*u", 6, 1, pp->pr_nitems);
                   1238:                PRWORD(ovflw, " %*lu", wide ? 7 : 6, 1, pp->pr_npagealloc);
                   1239:                PRWORD(ovflw, " %*lu", wide ? 7 : 6, 1, pp->pr_npagefree);
                   1240:                PRWORD(ovflw, " %*u", 6, 1, pp->pr_npages);
                   1241:                if (wide)
                   1242:                        PRWORD(ovflw, " %*u", 7, 1, pa.pa_pagesz);
                   1243:                PRWORD(ovflw, " %*u", 6, 1, pp->pr_hiwat);
                   1244:                PRWORD(ovflw, " %*u", 6, 1, pp->pr_minpages);
1.69      enami    1245:                PRWORD(ovflw, " %*s", 6, 1, maxp);
1.126     simonb   1246:                PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nidle);
                   1247:                if (wide)
                   1248:                        PRWORD(ovflw, " 0x%0*x", 4, 1,
                   1249:                            pp->pr_flags | pp->pr_roflags);
1.51      pk       1250:
1.126     simonb   1251:                this_inuse = pp->pr_nout * pp->pr_size;
                   1252:                this_total = pp->pr_npages * pa.pa_pagesz;
1.84      bjh21    1253:                if (pp->pr_roflags & PR_RECURSIVE) {
                   1254:                        /*
                   1255:                         * Don't count in-use memory, since it's part
                   1256:                         * of another pool and will be accounted for
                   1257:                         * there.
                   1258:                         */
1.126     simonb   1259:                        total += (this_total - this_inuse);
1.84      bjh21    1260:                } else {
1.126     simonb   1261:                        inuse += this_inuse;
                   1262:                        total += this_total;
1.84      bjh21    1263:                }
1.126     simonb   1264:                if (wide) {
                   1265:                        if (this_total == 0)
                   1266:                                printf("   ---");
                   1267:                        else
                   1268:                                printf(" %5.1f%%",
                   1269:                                    (100.0 * this_inuse) / this_total);
                   1270:                }
                   1271:                printf("\n");
1.96      enami    1272:                dopoolcache(pp, verbose);
1.51      pk       1273:        }
                   1274:
1.76      enami    1275:        inuse /= 1024;
                   1276:        total /= 1024;
1.51      pk       1277:        printf("\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n",
1.126     simonb   1278:            inuse, total, (100.0 * inuse) / total);
1.1       cgd      1279: }
1.96      enami    1280:
                   1281: void
                   1282: dopoolcache(struct pool *pp, int verbose)
                   1283: {
                   1284:        struct pool_cache pool_cache, *pc = &pool_cache;
                   1285:        struct pool_cache_group pool_cache_group, *pcg = &pool_cache_group;
                   1286:        void *addr, *pcg_addr;
                   1287:        int i;
                   1288:
                   1289:        if (verbose < 1)
                   1290:                return;
                   1291:
1.137     chs      1292: #define PR_GROUPLIST                                                   \
                   1293:        deref_kptr(pcg_addr, pcg, sizeof(*pcg),                         \
                   1294:            "pool cache group trashed");                                \
                   1295:        printf("\t\tgroup %p: avail %d\n", pcg_addr,                    \
                   1296:            pcg->pcg_avail);                                            \
                   1297:        for (i = 0; i < PCG_NOBJECTS; i++) {                            \
                   1298:                if (pcg->pcg_objects[i].pcgo_pa !=                      \
                   1299:                    POOL_PADDR_INVALID) {                               \
                   1300:                        printf("\t\t\t%p, 0x%llx\n",                    \
                   1301:                            pcg->pcg_objects[i].pcgo_va,                \
                   1302:                            (unsigned long long)                        \
                   1303:                            pcg->pcg_objects[i].pcgo_pa);               \
                   1304:                } else {                                                \
                   1305:                        printf("\t\t\t%p\n",                            \
                   1306:                            pcg->pcg_objects[i].pcgo_va);               \
                   1307:                }                                                       \
                   1308:        }
                   1309:
                   1310:        for (addr = LIST_FIRST(&pp->pr_cachelist); addr != NULL;
                   1311:            addr = LIST_NEXT(pc, pc_poollist)) {
1.96      enami    1312:                deref_kptr(addr, pc, sizeof(*pc), "pool cache trashed");
                   1313:                printf("\t    hits %lu misses %lu ngroups %lu nitems %lu\n",
                   1314:                    pc->pc_hits, pc->pc_misses, pc->pc_ngroups, pc->pc_nitems);
                   1315:                if (verbose < 2)
                   1316:                        continue;
1.137     chs      1317:                printf("\t    full groups:\n");
                   1318:                for (pcg_addr = LIST_FIRST(&pc->pc_fullgroups);
                   1319:                    pcg_addr != NULL; pcg_addr = LIST_NEXT(pcg, pcg_list)) {
                   1320:                        PR_GROUPLIST;
                   1321:                }
                   1322:                printf("\t    partial groups:\n");
                   1323:                for (pcg_addr = LIST_FIRST(&pc->pc_partgroups);
                   1324:                    pcg_addr != NULL; pcg_addr = LIST_NEXT(pcg, pcg_list)) {
                   1325:                        PR_GROUPLIST;
                   1326:                }
                   1327:                printf("\t    empty groups:\n");
                   1328:                for (pcg_addr = LIST_FIRST(&pc->pc_emptygroups);
                   1329:                    pcg_addr != NULL; pcg_addr = LIST_NEXT(pcg, pcg_list)) {
                   1330:                        PR_GROUPLIST;
1.96      enami    1331:                }
                   1332:        }
                   1333:
1.137     chs      1334: #undef PR_GROUPLIST
                   1335:
1.96      enami    1336: }
1.90      lukem    1337:
1.87      lukem    1338: enum hashtype {                        /* from <sys/systm.h> */
                   1339:        HASH_LIST,
                   1340:        HASH_TAILQ
                   1341: };
                   1342:
                   1343: struct uidinfo {               /* XXX: no kernel header file */
                   1344:        LIST_ENTRY(uidinfo) ui_hash;
                   1345:        uid_t   ui_uid;
                   1346:        long    ui_proccnt;
                   1347: };
                   1348:
                   1349: struct kernel_hash {
1.90      lukem    1350:        const char *    description;    /* description */
                   1351:        int             hashsize;       /* nlist index for hash size */
                   1352:        int             hashtbl;        /* nlist index for hash table */
                   1353:        enum hashtype   type;           /* type of hash table */
1.101     sommerfe 1354:        size_t          offset;         /* offset of {LIST,TAILQ}_NEXT */
1.87      lukem    1355: } khashes[] =
                   1356: {
                   1357:        {
1.90      lukem    1358:                "buffer hash",
                   1359:                X_BUFHASH, X_BUFHASHTBL,
                   1360:                HASH_LIST, offsetof(struct buf, b_hash)
                   1361:        }, {
                   1362:                "inode cache (ihash)",
1.87      lukem    1363:                X_IHASH, X_IHASHTBL,
                   1364:                HASH_LIST, offsetof(struct inode, i_hash)
1.90      lukem    1365:        }, {
                   1366:                "ipv4 address -> interface hash",
1.87      lukem    1367:                X_IFADDRHASH, X_IFADDRHASHTBL,
                   1368:                HASH_LIST, offsetof(struct in_ifaddr, ia_hash),
1.90      lukem    1369:        }, {
                   1370:                "name cache hash",
1.89      lukem    1371:                X_NCHASH, X_NCHASHTBL,
                   1372:                HASH_LIST, offsetof(struct namecache, nc_hash),
1.90      lukem    1373:        }, {
                   1374:                "name cache directory hash",
1.89      lukem    1375:                X_NCVHASH, X_NCVHASHTBL,
                   1376:                HASH_LIST, offsetof(struct namecache, nc_vhash),
1.90      lukem    1377:        }, {
                   1378:                "nfs client node cache",
                   1379:                X_NFSNODE, X_NFSNODETBL,
                   1380:                HASH_LIST, offsetof(struct nfsnode, n_hash)
                   1381:        }, {
                   1382:                "user info (uid -> used processes) hash",
                   1383:                X_UIHASH, X_UIHASHTBL,
                   1384:                HASH_LIST, offsetof(struct uidinfo, ui_hash),
                   1385:        }, {
                   1386:                NULL, -1, -1, 0, 0,
1.87      lukem    1387:        }
                   1388: };
                   1389:
                   1390: void
1.88      lukem    1391: dohashstat(int verbose, int todo, const char *hashname)
1.101     sommerfe 1392: {
1.87      lukem    1393:        LIST_HEAD(, generic)    *hashtbl_list;
                   1394:        TAILQ_HEAD(, generic)   *hashtbl_tailq;
                   1395:        struct kernel_hash      *curhash;
1.118     itojun   1396:        void    *hashaddr, *hashbuf, *nhashbuf, *nextaddr;
1.87      lukem    1397:        size_t  elemsize, hashbufsize, thissize;
                   1398:        u_long  hashsize;
                   1399:        int     i, used, items, chain, maxchain;
                   1400:
                   1401:        hashbuf = NULL;
                   1402:        hashbufsize = 0;
1.88      lukem    1403:
                   1404:        if (todo & HASHLIST) {
1.90      lukem    1405:                printf("Supported hashes:\n");
                   1406:                for (curhash = khashes; curhash->description; curhash++) {
1.101     sommerfe 1407:                        if (hashnl[curhash->hashsize].n_value == 0 ||
1.90      lukem    1408:                            hashnl[curhash->hashtbl].n_value == 0)
                   1409:                                continue;
                   1410:                        printf("\t%-16s%s\n",
                   1411:                            hashnl[curhash->hashsize].n_name + 1,
                   1412:                            curhash->description);
1.88      lukem    1413:                }
                   1414:                return;
                   1415:        }
                   1416:
                   1417:        if (hashname != NULL) {
1.90      lukem    1418:                for (curhash = khashes; curhash->description; curhash++) {
                   1419:                        if (strcmp(hashnl[curhash->hashsize].n_name + 1,
                   1420:                            hashname) == 0 &&
1.101     sommerfe 1421:                            hashnl[curhash->hashsize].n_value != 0 &&
1.90      lukem    1422:                            hashnl[curhash->hashtbl].n_value != 0)
1.88      lukem    1423:                                break;
                   1424:                }
1.90      lukem    1425:                if (curhash->description == NULL) {
                   1426:                        warnx("%s: no such hash", hashname);
                   1427:                        return;
                   1428:                }
1.88      lukem    1429:        }
                   1430:
                   1431:        printf(
                   1432:            "%-16s %8s %8s %8s %8s %8s %8s\n"
                   1433:            "%-16s %8s %8s %8s %8s %8s %8s\n",
                   1434:            "", "total", "used", "util", "num", "average", "maximum",
                   1435:            "hash table", "buckets", "buckets", "%", "items", "chain",
                   1436:            "chain");
1.87      lukem    1437:
1.90      lukem    1438:        for (curhash = khashes; curhash->description; curhash++) {
1.101     sommerfe 1439:                if (hashnl[curhash->hashsize].n_value == 0 ||
1.90      lukem    1440:                    hashnl[curhash->hashtbl].n_value == 0)
                   1441:                        continue;
1.88      lukem    1442:                if (hashname != NULL &&
1.90      lukem    1443:                    strcmp(hashnl[curhash->hashsize].n_name + 1, hashname))
1.88      lukem    1444:                        continue;
1.87      lukem    1445:                elemsize = curhash->type == HASH_LIST ?
                   1446:                    sizeof(*hashtbl_list) : sizeof(*hashtbl_tailq);
1.90      lukem    1447:                deref_kptr((void *)hashnl[curhash->hashsize].n_value,
                   1448:                    &hashsize, sizeof(hashsize),
                   1449:                    hashnl[curhash->hashsize].n_name);
1.87      lukem    1450:                hashsize++;
1.90      lukem    1451:                deref_kptr((void *)hashnl[curhash->hashtbl].n_value,
                   1452:                    &hashaddr, sizeof(hashaddr),
                   1453:                    hashnl[curhash->hashtbl].n_name);
1.87      lukem    1454:                if (verbose)
1.91      jmc      1455:                        printf("%s %lu, %s %p, offset %ld, elemsize %llu\n",
1.90      lukem    1456:                            hashnl[curhash->hashsize].n_name + 1, hashsize,
                   1457:                            hashnl[curhash->hashtbl].n_name + 1, hashaddr,
1.101     sommerfe 1458:                            (long)curhash->offset,
1.91      jmc      1459:                            (unsigned long long)elemsize);
1.87      lukem    1460:                thissize = hashsize * elemsize;
                   1461:                if (thissize > hashbufsize) {
1.118     itojun   1462:                        if ((nhashbuf = realloc(hashbuf, thissize)) == NULL)
1.101     sommerfe 1463:                                errx(1, "malloc hashbuf %llu",
1.91      jmc      1464:                                    (unsigned long long)hashbufsize);
1.118     itojun   1465:                        hashbuf = nhashbuf;
                   1466:                        hashbufsize = thissize;
1.87      lukem    1467:                }
                   1468:                deref_kptr(hashaddr, hashbuf, thissize,
1.90      lukem    1469:                    hashnl[curhash->hashtbl].n_name);
1.87      lukem    1470:                used = 0;
                   1471:                items = maxchain = 0;
1.135     lukem    1472:                if (curhash->type == HASH_LIST) {
1.87      lukem    1473:                        hashtbl_list = hashbuf;
1.135     lukem    1474:                        hashtbl_tailq = NULL;
                   1475:                } else {
                   1476:                        hashtbl_list = NULL;
1.87      lukem    1477:                        hashtbl_tailq = hashbuf;
1.135     lukem    1478:                }
1.87      lukem    1479:                for (i = 0; i < hashsize; i++) {
                   1480:                        if (curhash->type == HASH_LIST)
                   1481:                                nextaddr = LIST_FIRST(&hashtbl_list[i]);
                   1482:                        else
                   1483:                                nextaddr = TAILQ_FIRST(&hashtbl_tailq[i]);
                   1484:                        if (nextaddr == NULL)
                   1485:                                continue;
                   1486:                        if (verbose)
                   1487:                                printf("%5d: %p\n", i, nextaddr);
                   1488:                        used++;
                   1489:                        chain = 0;
                   1490:                        do {
                   1491:                                chain++;
                   1492:                                deref_kptr((char *)nextaddr + curhash->offset,
                   1493:                                    &nextaddr, sizeof(void *),
                   1494:                                    "hash chain corrupted");
                   1495:                                if (verbose > 1)
                   1496:                                        printf("got nextaddr as %p\n",
                   1497:                                            nextaddr);
                   1498:                        } while (nextaddr != NULL);
                   1499:                        items += chain;
                   1500:                        if (verbose && chain > 1)
                   1501:                                printf("\tchain = %d\n", chain);
                   1502:                        if (chain > maxchain)
                   1503:                                maxchain = chain;
                   1504:                }
1.93      lukem    1505:                printf("%-16s %8ld %8d %8.2f %8d %8.2f %8d\n",
1.90      lukem    1506:                    hashnl[curhash->hashsize].n_name + 1,
1.87      lukem    1507:                    hashsize, used, used * 100.0 / hashsize,
1.93      lukem    1508:                    items, used ? (double)items / used : 0.0, maxchain);
1.87      lukem    1509:        }
                   1510: }
                   1511:
1.1       cgd      1512: /*
1.90      lukem    1513:  * kread reads something from the kernel, given its nlist index in namelist[].
1.1       cgd      1514:  */
                   1515: void
1.133     chs      1516: kread(struct nlist *nl, int nlx, void *addr, size_t size)
1.1       cgd      1517: {
1.50      mycroft  1518:        const char *sym;
1.1       cgd      1519:
1.133     chs      1520:        sym = nl[nlx].n_name;
1.87      lukem    1521:        if (*sym == '_')
                   1522:                ++sym;
1.133     chs      1523:        if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0)
1.87      lukem    1524:                errx(1, "symbol %s not defined", sym);
1.133     chs      1525:        deref_kptr((void *)nl[nlx].n_value, addr, size, sym);
1.87      lukem    1526: }
                   1527:
                   1528: /*
1.101     sommerfe 1529:  * Dereference the kernel pointer `kptr' and fill in the local copy
1.87      lukem    1530:  * pointed to by `ptr'.  The storage space must be pre-allocated,
                   1531:  * and the size of the copy passed in `len'.
                   1532:  */
                   1533: void
                   1534: deref_kptr(const void *kptr, void *ptr, size_t len, const char *msg)
                   1535: {
                   1536:
                   1537:        if (*msg == '_')
                   1538:                msg++;
                   1539:        if (kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len)
                   1540:                errx(1, "kptr %lx: %s: %s", (u_long)kptr, msg, kvm_geterr(kd));
1.1       cgd      1541: }
                   1542:
1.45      thorpej  1543: /*
                   1544:  * Traverse the UVM history buffers, performing the requested action.
                   1545:  *
                   1546:  * Note, we assume that if we're not listing, we're dumping.
                   1547:  */
                   1548: void
1.73      simonb   1549: hist_traverse(int todo, const char *histname)
1.45      thorpej  1550: {
                   1551:        struct uvm_history_head histhead;
                   1552:        struct uvm_history hist, *histkva;
                   1553:        char *name = NULL;
                   1554:        size_t namelen = 0;
                   1555:
1.90      lukem    1556:        if (histnl[0].n_value == 0) {
1.87      lukem    1557:                warnx("UVM history is not compiled into the kernel.");
1.45      thorpej  1558:                return;
                   1559:        }
                   1560:
1.87      lukem    1561:        deref_kptr((void *)histnl[X_UVM_HISTORIES].n_value, &histhead,
                   1562:            sizeof(histhead), histnl[X_UVM_HISTORIES].n_name);
1.45      thorpej  1563:
                   1564:        if (histhead.lh_first == NULL) {
1.87      lukem    1565:                warnx("No active UVM history logs.");
1.45      thorpej  1566:                return;
                   1567:        }
                   1568:
                   1569:        if (todo & HISTLIST)
                   1570:                printf("Active UVM histories:");
                   1571:
1.75      enami    1572:        for (histkva = LIST_FIRST(&histhead); histkva != NULL;
                   1573:            histkva = LIST_NEXT(&hist, list)) {
1.87      lukem    1574:                deref_kptr(histkva, &hist, sizeof(hist), "histkva");
1.45      thorpej  1575:                if (hist.namelen > namelen) {
                   1576:                        if (name != NULL)
                   1577:                                free(name);
                   1578:                        namelen = hist.namelen;
                   1579:                        if ((name = malloc(namelen + 1)) == NULL)
                   1580:                                err(1, "malloc history name");
                   1581:                }
                   1582:
1.87      lukem    1583:                deref_kptr(hist.name, name, namelen, "history name");
1.45      thorpej  1584:                name[namelen] = '\0';
                   1585:                if (todo & HISTLIST)
                   1586:                        printf(" %s", name);
                   1587:                else {
                   1588:                        /*
                   1589:                         * If we're dumping all histories, do it, else
                   1590:                         * check to see if this is the one we want.
                   1591:                         */
                   1592:                        if (histname == NULL || strcmp(histname, name) == 0) {
                   1593:                                if (histname == NULL)
                   1594:                                        printf("\nUVM history `%s':\n", name);
                   1595:                                hist_dodump(&hist);
                   1596:                        }
                   1597:                }
                   1598:        }
                   1599:
                   1600:        if (todo & HISTLIST)
1.87      lukem    1601:                putchar('\n');
1.45      thorpej  1602:
                   1603:        if (name != NULL)
                   1604:                free(name);
                   1605: }
                   1606:
                   1607: /*
                   1608:  * Actually dump the history buffer at the specified KVA.
                   1609:  */
                   1610: void
1.73      simonb   1611: hist_dodump(struct uvm_history *histp)
1.45      thorpej  1612: {
                   1613:        struct uvm_history_ent *histents, *e;
                   1614:        size_t histsize;
                   1615:        char *fmt = NULL, *fn = NULL;
                   1616:        size_t fmtlen = 0, fnlen = 0;
                   1617:        int i;
                   1618:
                   1619:        histsize = sizeof(struct uvm_history_ent) * histp->n;
                   1620:
                   1621:        if ((histents = malloc(histsize)) == NULL)
                   1622:                err(1, "malloc history entries");
                   1623:
                   1624:        memset(histents, 0, histsize);
                   1625:
1.87      lukem    1626:        deref_kptr(histp->e, histents, histsize, "history entries");
1.45      thorpej  1627:        i = histp->f;
                   1628:        do {
                   1629:                e = &histents[i];
                   1630:                if (e->fmt != NULL) {
                   1631:                        if (e->fmtlen > fmtlen) {
                   1632:                                if (fmt != NULL)
                   1633:                                        free(fmt);
                   1634:                                fmtlen = e->fmtlen;
                   1635:                                if ((fmt = malloc(fmtlen + 1)) == NULL)
                   1636:                                        err(1, "malloc printf format");
                   1637:                        }
                   1638:                        if (e->fnlen > fnlen) {
                   1639:                                if (fn != NULL)
                   1640:                                        free(fn);
                   1641:                                fnlen = e->fnlen;
                   1642:                                if ((fn = malloc(fnlen + 1)) == NULL)
                   1643:                                        err(1, "malloc function name");
                   1644:                        }
                   1645:
1.87      lukem    1646:                        deref_kptr(e->fmt, fmt, fmtlen, "printf format");
1.45      thorpej  1647:                        fmt[fmtlen] = '\0';
                   1648:
1.87      lukem    1649:                        deref_kptr(e->fn, fn, fnlen, "function name");
1.45      thorpej  1650:                        fn[fnlen] = '\0';
                   1651:
1.61      kleink   1652:                        printf("%06ld.%06ld ", (long int)e->tv.tv_sec,
                   1653:                            (long int)e->tv.tv_usec);
1.75      enami    1654:                        printf("%s#%ld: ", fn, e->call);
1.45      thorpej  1655:                        printf(fmt, e->v[0], e->v[1], e->v[2], e->v[3]);
1.87      lukem    1656:                        putchar('\n');
1.45      thorpej  1657:                }
                   1658:                i = (i + 1) % histp->n;
                   1659:        } while (i != histp->f);
                   1660:
                   1661:        free(histents);
                   1662:        if (fmt != NULL)
                   1663:                free(fmt);
                   1664:        if (fn != NULL)
                   1665:                free(fn);
                   1666: }
                   1667:
1.1       cgd      1668: void
1.73      simonb   1669: usage(void)
1.1       cgd      1670: {
1.47      mrg      1671:
1.1       cgd      1672:        (void)fprintf(stderr,
1.131     wiz      1673:            "usage: %s [-efHiLlmstUvW] [-c count] [-h hashname] [-M core] [-N system]\n"
1.127     wiz      1674:            "\t\t[-u histname] [-w wait] [disks]\n", getprogname());
1.1       cgd      1675:        exit(1);
                   1676: }

CVSweb <webmaster@jp.NetBSD.org>