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>