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