[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.98

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

CVSweb <webmaster@jp.NetBSD.org>