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