Annotation of src/usr.bin/vmstat/vmstat.c, Revision 1.216.6.2
1.216.6.2! snj 1: /* $NetBSD: vmstat.c,v 1.216.6.1 2017/07/25 01:43:37 snj Exp $ */
1.45 thorpej 2:
3: /*-
1.154 ad 4: * Copyright (c) 1998, 2000, 2001, 2007 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: *
21: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31: * POSSIBILITY OF SUCH DAMAGE.
32: */
1.21 cgd 33:
1.1 cgd 34: /*
1.13 cgd 35: * Copyright (c) 1980, 1986, 1991, 1993
36: * The Regents of the University of California. All rights reserved.
1.1 cgd 37: *
38: * Redistribution and use in source and binary forms, with or without
39: * modification, are permitted provided that the following conditions
40: * are met:
41: * 1. Redistributions of source code must retain the above copyright
42: * notice, this list of conditions and the following disclaimer.
43: * 2. Redistributions in binary form must reproduce the above copyright
44: * notice, this list of conditions and the following disclaimer in the
45: * documentation and/or other materials provided with the distribution.
1.117 agc 46: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 47: * may be used to endorse or promote products derived from this software
48: * without specific prior written permission.
49: *
50: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60: * SUCH DAMAGE.
61: */
62:
1.38 mrg 63: #include <sys/cdefs.h>
1.1 cgd 64: #ifndef lint
1.161 lukem 65: __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1991, 1993\
66: The Regents of the University of California. All rights reserved.");
1.1 cgd 67: #endif /* not lint */
68:
69: #ifndef lint
1.21 cgd 70: #if 0
1.37 mrg 71: static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95";
1.21 cgd 72: #else
1.216.6.2! snj 73: __RCSID("$NetBSD: vmstat.c,v 1.216.6.1 2017/07/25 01:43:37 snj Exp $");
1.21 cgd 74: #endif
1.1 cgd 75: #endif /* not lint */
1.57 thorpej 76:
77: #define __POOL_EXPOSE
1.1 cgd 78:
79: #include <sys/param.h>
1.174 christos 80: #include <sys/types.h>
1.87 lukem 81: #include <sys/mount.h>
82: #include <sys/uio.h>
83:
84: #include <sys/buf.h>
1.146 yamt 85: #include <sys/evcnt.h>
1.87 lukem 86: #include <sys/ioctl.h>
87: #include <sys/malloc.h>
1.109 thorpej 88: #include <sys/mallocvar.h>
1.1 cgd 89: #include <sys/namei.h>
1.87 lukem 90: #include <sys/pool.h>
91: #include <sys/proc.h>
1.64 perry 92: #include <sys/sched.h>
1.87 lukem 93: #include <sys/socket.h>
1.13 cgd 94: #include <sys/sysctl.h>
1.87 lukem 95: #include <sys/time.h>
1.171 christos 96: #include <sys/queue.h>
1.181 mrg 97: #include <sys/kernhist.h>
1.67 mrg 98:
99: #include <uvm/uvm_extern.h>
100: #include <uvm/uvm_stat.h>
101:
1.87 lukem 102: #include <net/if.h>
103: #include <netinet/in.h>
104: #include <netinet/in_var.h>
105:
106: #include <ufs/ufs/inode.h>
107:
108: #include <nfs/rpcv2.h>
109: #include <nfs/nfsproto.h>
110: #include <nfs/nfsnode.h>
111:
112: #include <ctype.h>
1.45 thorpej 113: #include <err.h>
1.87 lukem 114: #include <errno.h>
1.55 kleink 115: #include <fcntl.h>
1.87 lukem 116: #include <kvm.h>
117: #include <limits.h>
1.1 cgd 118: #include <nlist.h>
1.87 lukem 119: #undef n_hash
120: #include <paths.h>
1.22 jtc 121: #include <signal.h>
1.1 cgd 122: #include <stdio.h>
1.87 lukem 123: #include <stddef.h>
1.1 cgd 124: #include <stdlib.h>
125: #include <string.h>
1.87 lukem 126: #include <time.h>
127: #include <unistd.h>
1.104 mrg 128: #include <util.h>
1.87 lukem 129:
1.140 blymn 130: #include "drvstats.h"
1.45 thorpej 131:
1.90 lukem 132: /*
1.174 christos 133: * All this mess will go away once everything is converted.
134: */
135: #ifdef __HAVE_CPU_DATA_FIRST
1.175 christos 136:
137: # include <sys/cpu_data.h>
138: struct cpu_info {
1.174 christos 139: struct cpu_data ci_data;
140: };
141: #else
1.190 rmind 142: # include <sys/cpu.h>
143: #endif
1.175 christos 144:
1.174 christos 145: /*
1.90 lukem 146: * General namelist
147: */
1.87 lukem 148: struct nlist namelist[] =
149: {
1.65 itojun 150: #define X_BOOTTIME 0
1.153 christos 151: { .n_name = "_boottime" },
1.75 enami 152: #define X_HZ 1
1.153 christos 153: { .n_name = "_hz" },
1.75 enami 154: #define X_STATHZ 2
1.153 christos 155: { .n_name = "_stathz" },
1.75 enami 156: #define X_NCHSTATS 3
1.153 christos 157: { .n_name = "_nchstats" },
1.188 para 158: #define X_ALLEVENTS 4
1.153 christos 159: { .n_name = "_allevents" },
1.188 para 160: #define X_POOLHEAD 5
1.153 christos 161: { .n_name = "_pool_head" },
1.188 para 162: #define X_UVMEXP 6
1.153 christos 163: { .n_name = "_uvmexp" },
1.188 para 164: #define X_TIME_SECOND 7
1.153 christos 165: { .n_name = "_time_second" },
1.188 para 166: #define X_TIME 8
1.153 christos 167: { .n_name = "_time" },
1.190 rmind 168: #define X_CPU_INFOS 9
169: { .n_name = "_cpu_infos" },
1.188 para 170: #define X_NL_SIZE 10
1.153 christos 171: { .n_name = NULL },
1.90 lukem 172: };
173:
174: /*
1.133 chs 175: * Namelist for pre-evcnt interrupt counters.
176: */
177: struct nlist intrnl[] =
178: {
179: #define X_INTRNAMES 0
1.153 christos 180: { .n_name = "_intrnames" },
1.133 chs 181: #define X_EINTRNAMES 1
1.153 christos 182: { .n_name = "_eintrnames" },
1.133 chs 183: #define X_INTRCNT 2
1.153 christos 184: { .n_name = "_intrcnt" },
1.133 chs 185: #define X_EINTRCNT 3
1.153 christos 186: { .n_name = "_eintrcnt" },
1.133 chs 187: #define X_INTRNL_SIZE 4
1.153 christos 188: { .n_name = NULL },
1.133 chs 189: };
190:
191:
192: /*
1.90 lukem 193: * Namelist for hash statistics
194: */
195: struct nlist hashnl[] =
196: {
197: #define X_NFSNODE 0
1.153 christos 198: { .n_name = "_nfsnodehash" },
1.90 lukem 199: #define X_NFSNODETBL 1
1.153 christos 200: { .n_name = "_nfsnodehashtbl" },
1.90 lukem 201: #define X_IHASH 2
1.153 christos 202: { .n_name = "_ihash" },
1.90 lukem 203: #define X_IHASHTBL 3
1.153 christos 204: { .n_name = "_ihashtbl" },
1.90 lukem 205: #define X_BUFHASH 4
1.153 christos 206: { .n_name = "_bufhash" },
1.90 lukem 207: #define X_BUFHASHTBL 5
1.153 christos 208: { .n_name = "_bufhashtbl" },
1.122 junyoung 209: #define X_UIHASH 6
1.153 christos 210: { .n_name = "_uihash" },
1.122 junyoung 211: #define X_UIHASHTBL 7
1.153 christos 212: { .n_name = "_uihashtbl" },
1.122 junyoung 213: #define X_IFADDRHASH 8
1.153 christos 214: { .n_name = "_in_ifaddrhash" },
1.122 junyoung 215: #define X_IFADDRHASHTBL 9
1.153 christos 216: { .n_name = "_in_ifaddrhashtbl" },
1.122 junyoung 217: #define X_NCHASH 10
1.153 christos 218: { .n_name = "_nchash" },
1.122 junyoung 219: #define X_NCHASHTBL 11
1.153 christos 220: { .n_name = "_nchashtbl" },
1.122 junyoung 221: #define X_NCVHASH 12
1.153 christos 222: { .n_name = "_ncvhash" },
1.122 junyoung 223: #define X_NCVHASHTBL 13
1.153 christos 224: { .n_name = "_ncvhashtbl" },
1.122 junyoung 225: #define X_HASHNL_SIZE 14 /* must be last */
1.153 christos 226: { .n_name = NULL },
1.90 lukem 227: };
1.87 lukem 228:
1.90 lukem 229: /*
1.181 mrg 230: * Namelist for kernel histories
1.90 lukem 231: */
232: struct nlist histnl[] =
233: {
1.181 mrg 234: { .n_name = "_kern_histories" },
235: #define X_KERN_HISTORIES 0
1.153 christos 236: { .n_name = NULL },
1.1 cgd 237: };
238:
1.87 lukem 239:
1.205 skrll 240: #define KILO 1024
1.90 lukem 241:
1.171 christos 242: struct cpu_counter {
243: uint64_t nintr;
244: uint64_t nsyscall;
245: uint64_t nswtch;
246: uint64_t nfault;
247: uint64_t ntrap;
248: uint64_t nsoft;
249: } cpucounter, ocpucounter;
250:
1.196 joerg 251: struct uvmexp_sysctl uvmexp, ouvmexp;
1.73 simonb 252: int ndrives;
1.1 cgd 253:
254: int winlines = 20;
255:
1.13 cgd 256: kvm_t *kd;
257:
1.174 christos 258:
1.185 christos 259: #define FORKSTAT 0x001
260: #define INTRSTAT 0x002
261: #define MEMSTAT 0x004
262: #define SUMSTAT 0x008
263: #define EVCNTSTAT 0x010
264: #define VMSTAT 0x020
265: #define HISTLIST 0x040
266: #define HISTDUMP 0x080
267: #define HASHSTAT 0x100
268: #define HASHLIST 0x200
269: #define VMTOTAL 0x400
270: #define POOLCACHESTAT 0x800
1.1 cgd 271:
1.151 yamt 272: /*
273: * Print single word. `ovflow' is number of characters didn't fit
274: * on the last word. `fmt' is a format string to print this word.
275: * It must contain asterisk for field width. `width' is a width
276: * occupied by this word. `fixed' is a number of constant chars in
277: * `fmt'. `val' is a value to be printed using format string `fmt'.
278: */
279: #define PRWORD(ovflw, fmt, width, fixed, val) do { \
280: (ovflw) += printf((fmt), \
281: (width) - (fixed) - (ovflw) > 0 ? \
282: (width) - (fixed) - (ovflw) : 0, \
283: (val)) - (width); \
284: if ((ovflw) < 0) \
285: (ovflw) = 0; \
286: } while (/* CONSTCOND */0)
287:
288: void cpustats(int *);
1.171 christos 289: void cpucounters(struct cpu_counter *);
1.87 lukem 290: void deref_kptr(const void *, void *, size_t, const char *);
1.151 yamt 291: void drvstats(int *);
1.176 matt 292: void doevcnt(int verbose, int type);
1.88 lukem 293: void dohashstat(int, int, const char *);
1.73 simonb 294: void dointr(int verbose);
1.126 simonb 295: void dopool(int, int);
1.182 yamt 296: void dopoolcache(int);
1.73 simonb 297: void dosum(void);
1.103 mycroft 298: void dovmstat(struct timespec *, int);
1.130 he 299: void print_total_hdr(void);
300: void dovmtotal(struct timespec *, int);
1.133 chs 301: void kread(struct nlist *, int, void *, size_t);
1.147 kardel 302: int kreadc(struct nlist *, int, void *, size_t);
1.73 simonb 303: void needhdr(int);
1.176 matt 304: void getnlist(int);
1.73 simonb 305: long getuptime(void);
306: void printhdr(void);
1.203 nakayama 307: long pct(u_long, u_long);
1.183 joerg 308: __dead static void usage(void);
1.73 simonb 309: void doforkst(void);
310:
311: void hist_traverse(int, const char *);
1.210 pgoyette 312: void hist_dodump(struct kern_history *);
313: void hist_traverse_sysctl(int, const char *);
314: void hist_dodump_sysctl(int[], unsigned int);
1.73 simonb 315:
316: char **choosedrives(char **);
1.38 mrg 317:
1.29 thorpej 318: /* Namelist and memory file names. */
319: char *nlistf, *memf;
320:
1.47 mrg 321: /* allow old usage [vmstat 1] */
322: #define BACKWARD_COMPATIBILITY
323:
1.197 joerg 324: static const int clockrate_mib[] = { CTL_KERN, KERN_CLOCKRATE };
1.170 christos 325: static const int vmmeter_mib[] = { CTL_VM, VM_METER };
326: static const int uvmexp2_mib[] = { CTL_VM, VM_UVMEXP2 };
1.176 matt 327: static const int boottime_mib[] = { CTL_KERN, KERN_BOOTTIME };
328: static char kvm_errbuf[_POSIX2_LINE_MAX];
1.170 christos 329:
1.38 mrg 330: int
1.75 enami 331: main(int argc, char *argv[])
1.1 cgd 332: {
1.126 simonb 333: int c, todo, verbose, wide;
1.103 mycroft 334: struct timespec interval;
1.1 cgd 335: int reps;
1.75 enami 336: gid_t egid = getegid();
1.88 lukem 337: const char *histname, *hashname;
1.1 cgd 338:
1.88 lukem 339: histname = hashname = NULL;
1.48 mrg 340: (void)setegid(getgid());
1.13 cgd 341: memf = nlistf = NULL;
1.126 simonb 342: reps = todo = verbose = wide = 0;
1.103 mycroft 343: interval.tv_sec = 0;
344: interval.tv_nsec = 0;
1.154 ad 345: while ((c = getopt(argc, argv, "Cc:efh:HilLM:mN:stu:UvWw:")) != -1) {
1.1 cgd 346: switch (c) {
347: case 'c':
348: reps = atoi(optarg);
349: break;
1.154 ad 350: case 'C':
351: todo |= POOLCACHESTAT;
352: break;
1.66 cgd 353: case 'e':
354: todo |= EVCNTSTAT;
355: break;
1.1 cgd 356: case 'f':
357: todo |= FORKSTAT;
358: break;
1.45 thorpej 359: case 'h':
1.88 lukem 360: hashname = optarg;
361: /* FALLTHROUGH */
362: case 'H':
1.87 lukem 363: todo |= HASHSTAT;
1.45 thorpej 364: break;
1.1 cgd 365: case 'i':
366: todo |= INTRSTAT;
367: break;
1.45 thorpej 368: case 'l':
369: todo |= HISTLIST;
370: break;
1.88 lukem 371: case 'L':
372: todo |= HASHLIST;
373: break;
1.1 cgd 374: case 'M':
1.13 cgd 375: memf = optarg;
1.1 cgd 376: break;
377: case 'm':
378: todo |= MEMSTAT;
379: break;
380: case 'N':
1.13 cgd 381: nlistf = optarg;
1.1 cgd 382: break;
383: case 's':
384: todo |= SUMSTAT;
385: break;
1.130 he 386: case 't':
387: todo |= VMTOTAL;
388: break;
1.87 lukem 389: case 'u':
390: histname = optarg;
391: /* FALLTHROUGH */
392: case 'U':
393: todo |= HISTDUMP;
394: break;
1.66 cgd 395: case 'v':
1.87 lukem 396: verbose++;
1.66 cgd 397: break;
1.126 simonb 398: case 'W':
399: wide++;
400: break;
1.1 cgd 401: case 'w':
1.103 mycroft 402: interval.tv_sec = atol(optarg);
1.1 cgd 403: break;
404: case '?':
405: default:
406: usage();
407: }
408: }
409: argc -= optind;
410: argv += optind;
411:
412: if (todo == 0)
413: todo = VMSTAT;
414:
1.13 cgd 415: /*
1.48 mrg 416: * Discard setgid privileges. If not the running kernel, we toss
417: * them away totally so that bad guys can't print interesting stuff
418: * from kernel memory, otherwise switch back to kmem for the
419: * duration of the kvm_openfiles() call.
1.13 cgd 420: */
421: if (nlistf != NULL || memf != NULL)
1.48 mrg 422: (void)setgid(getgid());
423: else
424: (void)setegid(egid);
1.13 cgd 425:
1.176 matt 426: kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, kvm_errbuf);
427: if (kd == NULL) {
428: if (nlistf != NULL || memf != NULL) {
429: errx(1, "kvm_openfiles: %s", kvm_errbuf);
430: }
431: }
1.48 mrg 432:
1.95 simonb 433: if (nlistf == NULL && memf == NULL)
434: (void)setgid(getgid());
1.1 cgd 435:
436:
437: if (todo & VMSTAT) {
438: struct winsize winsize;
439:
1.153 christos 440: (void)drvinit(0);/* Initialize disk stats, no disks selected. */
1.49 drochner 441:
442: (void)setgid(getgid()); /* don't need privs anymore */
443:
1.29 thorpej 444: argv = choosedrives(argv); /* Select disks. */
1.1 cgd 445: winsize.ws_row = 0;
1.115 simonb 446: (void)ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize);
1.1 cgd 447: if (winsize.ws_row > 0)
448: winlines = winsize.ws_row;
449:
450: }
451:
452: #ifdef BACKWARD_COMPATIBILITY
453: if (*argv) {
1.103 mycroft 454: interval.tv_sec = atol(*argv);
1.1 cgd 455: if (*++argv)
456: reps = atoi(*argv);
457: }
458: #endif
459:
1.103 mycroft 460: if (interval.tv_sec) {
1.1 cgd 461: if (!reps)
462: reps = -1;
463: } else if (reps)
1.103 mycroft 464: interval.tv_sec = 1;
1.1 cgd 465:
1.78 jhawk 466:
1.185 christos 467: getnlist(todo);
1.78 jhawk 468: /*
469: * Statistics dumping is incompatible with the default
470: * VMSTAT/dovmstat() output. So perform the interval/reps handling
471: * for it here.
472: */
1.130 he 473: if ((todo & (VMSTAT|VMTOTAL)) == 0) {
1.99 enami 474: for (;;) {
475: if (todo & (HISTLIST|HISTDUMP)) {
476: if ((todo & (HISTLIST|HISTDUMP)) ==
477: (HISTLIST|HISTDUMP))
478: errx(1, "you may list or dump,"
479: " but not both!");
1.210 pgoyette 480: if (memf != NULL)
481: hist_traverse(todo, histname);
482: else
483: hist_traverse_sysctl(todo, histname);
1.153 christos 484: (void)putchar('\n');
1.99 enami 485: }
486: if (todo & FORKSTAT) {
487: doforkst();
1.153 christos 488: (void)putchar('\n');
1.99 enami 489: }
490: if (todo & MEMSTAT) {
1.126 simonb 491: dopool(verbose, wide);
1.153 christos 492: (void)putchar('\n');
1.99 enami 493: }
1.154 ad 494: if (todo & POOLCACHESTAT) {
1.182 yamt 495: dopoolcache(verbose);
1.154 ad 496: (void)putchar('\n');
497: }
1.99 enami 498: if (todo & SUMSTAT) {
499: dosum();
1.153 christos 500: (void)putchar('\n');
1.99 enami 501: }
502: if (todo & INTRSTAT) {
503: dointr(verbose);
1.153 christos 504: (void)putchar('\n');
1.99 enami 505: }
506: if (todo & EVCNTSTAT) {
1.176 matt 507: doevcnt(verbose, EVCNT_TYPE_ANY);
1.153 christos 508: (void)putchar('\n');
1.99 enami 509: }
510: if (todo & (HASHLIST|HASHSTAT)) {
511: if ((todo & (HASHLIST|HASHSTAT)) ==
512: (HASHLIST|HASHSTAT))
513: errx(1, "you may list or display,"
514: " but not both!");
515: dohashstat(verbose, todo, hashname);
1.153 christos 516: (void)putchar('\n');
1.99 enami 517: }
1.101 sommerfe 518:
1.164 dholland 519: fflush(stdout);
1.101 sommerfe 520: if (reps >= 0 && --reps <=0)
1.99 enami 521: break;
1.153 christos 522: (void)nanosleep(&interval, NULL);
1.87 lukem 523: }
1.130 he 524: } else {
525: if ((todo & (VMSTAT|VMTOTAL)) == (VMSTAT|VMTOTAL)) {
526: errx(1, "you may not both do vmstat and vmtotal");
527: }
528: if (todo & VMSTAT)
529: dovmstat(&interval, reps);
530: if (todo & VMTOTAL)
531: dovmtotal(&interval, reps);
532: }
1.153 christos 533: return 0;
1.1 cgd 534: }
535:
1.176 matt 536: void
537: getnlist(int todo)
538: {
539: static int namelist_done = 0;
1.185 christos 540: static int done = 0;
1.176 matt 541: int c;
542: size_t i;
543:
544: if (kd == NULL)
545: errx(1, "kvm_openfiles: %s", kvm_errbuf);
546:
547: if (!namelist_done) {
548: namelist_done = 1;
549: if ((c = kvm_nlist(kd, namelist)) != 0) {
550: int doexit = 0;
551: if (c == -1)
552: errx(1, "kvm_nlist: %s %s",
553: "namelist", kvm_geterr(kd));
554: for (i = 0; i < __arraycount(namelist)-1; i++)
555: if (namelist[i].n_type == 0 &&
556: i != X_TIME_SECOND &&
557: i != X_TIME) {
558: if (doexit++ == 0)
559: (void)fprintf(stderr,
560: "%s: undefined symbols:",
561: getprogname());
562: (void)fprintf(stderr, " %s",
563: namelist[i].n_name);
564: }
565: if (doexit) {
566: (void)fputc('\n', stderr);
567: exit(1);
568: }
569: }
570: }
1.185 christos 571: if ((todo & (SUMSTAT|INTRSTAT)) && !(done & (SUMSTAT|INTRSTAT))) {
572: done |= SUMSTAT|INTRSTAT;
1.176 matt 573: (void) kvm_nlist(kd, intrnl);
574: }
1.185 christos 575: if ((todo & (HASHLIST|HASHSTAT)) && !(done & (HASHLIST|HASHSTAT))) {
576: done |= HASHLIST|HASHSTAT;
1.176 matt 577: if ((c = kvm_nlist(kd, hashnl)) == -1 || c == X_HASHNL_SIZE)
578: errx(1, "kvm_nlist: %s %s", "hashnl", kvm_geterr(kd));
579: }
1.185 christos 580: if ((todo & (HISTLIST|HISTDUMP)) && !(done & (HISTLIST|HISTDUMP))) {
581: done |= HISTLIST|HISTDUMP;
1.176 matt 582: if (kvm_nlist(kd, histnl) == -1)
583: errx(1, "kvm_nlist: %s %s", "histnl", kvm_geterr(kd));
584: }
585: }
586:
1.1 cgd 587: char **
1.73 simonb 588: choosedrives(char **argv)
1.1 cgd 589: {
1.165 lukem 590: size_t i;
1.1 cgd 591:
592: /*
593: * Choose drives to be displayed. Priority goes to (in order) drives
594: * supplied as arguments, default drives. If everything isn't filled
595: * in and there are drives not taken care of, display the first few
596: * that fit.
597: */
1.75 enami 598: #define BACKWARD_COMPATIBILITY
1.1 cgd 599: for (ndrives = 0; *argv; ++argv) {
600: #ifdef BACKWARD_COMPATIBILITY
1.124 dsl 601: if (isdigit((unsigned char)**argv))
1.1 cgd 602: break;
603: #endif
1.140 blymn 604: for (i = 0; i < ndrive; i++) {
1.1 cgd 605: if (strcmp(dr_name[i], *argv))
606: continue;
1.140 blymn 607: drv_select[i] = 1;
1.136 blymn 608: ++ndrives;
609: break;
610: }
1.1 cgd 611: }
1.151 yamt 612: for (i = 0; i < ndrive && ndrives < 2; i++) {
1.140 blymn 613: if (drv_select[i])
1.1 cgd 614: continue;
1.140 blymn 615: drv_select[i] = 1;
1.1 cgd 616: ++ndrives;
617: }
1.140 blymn 618:
1.75 enami 619: return (argv);
1.1 cgd 620: }
621:
622: long
1.73 simonb 623: getuptime(void)
1.1 cgd 624: {
1.176 matt 625: static struct timespec boottime;
626: struct timespec now;
1.149 kardel 627: time_t uptime, nowsec;
1.1 cgd 628:
1.176 matt 629: if (memf == NULL) {
630: if (boottime.tv_sec == 0) {
631: size_t buflen = sizeof(boottime);
632: if (sysctl(boottime_mib, __arraycount(boottime_mib),
633: &boottime, &buflen, NULL, 0) == -1)
634: warn("Can't get boottime");
635: }
636: clock_gettime(CLOCK_REALTIME, &now);
1.147 kardel 637: } else {
1.176 matt 638: if (boottime.tv_sec == 0)
639: kread(namelist, X_BOOTTIME, &boottime,
640: sizeof(boottime));
641: if (kreadc(namelist, X_TIME_SECOND, &nowsec, sizeof(nowsec))) {
642: /*
643: * XXX this assignment dance can be removed once
644: * timeval tv_sec is SUS mandated time_t
645: */
646: now.tv_sec = nowsec;
647: now.tv_nsec = 0;
648: } else {
649: kread(namelist, X_TIME, &now, sizeof(now));
650: }
1.147 kardel 651: }
1.145 kardel 652: uptime = now.tv_sec - boottime.tv_sec;
1.87 lukem 653: if (uptime <= 0 || uptime > 60*60*24*365*10)
654: errx(1, "time makes no sense; namelist must be wrong.");
1.75 enami 655: return (uptime);
1.1 cgd 656: }
657:
658: int hz, hdrcnt;
659:
660: void
1.187 matt 661: print_total_hdr(void)
1.130 he 662: {
663:
1.166 rmind 664: (void)printf("procs memory\n");
665: (void)printf("ru dw pw sl");
1.130 he 666: (void)printf(" total-v active-v active-r");
667: (void)printf(" vm-sh avm-sh rm-sh arm-sh free\n");
668: hdrcnt = winlines - 2;
669: }
670:
671: void
672: dovmtotal(struct timespec *interval, int reps)
673: {
674: struct vmtotal total;
675: size_t size;
676:
677: (void)signal(SIGCONT, needhdr);
678:
679: for (hdrcnt = 1;;) {
680: if (!--hdrcnt)
681: print_total_hdr();
682: if (memf != NULL) {
1.170 christos 683: warnx("Unable to get vmtotals from crash dump.");
1.153 christos 684: (void)memset(&total, 0, sizeof(total));
1.130 he 685: } else {
686: size = sizeof(total);
1.170 christos 687: if (sysctl(vmmeter_mib, __arraycount(vmmeter_mib),
688: &total, &size, NULL, 0) == -1) {
689: warn("Can't get vmtotals");
1.153 christos 690: (void)memset(&total, 0, sizeof(total));
1.130 he 691: }
692: }
1.153 christos 693: (void)printf("%2d ", total.t_rq);
694: (void)printf("%2d ", total.t_dw);
695: (void)printf("%2d ", total.t_pw);
696: (void)printf("%2d ", total.t_sl);
697:
698: (void)printf("%9d ", total.t_vm);
699: (void)printf("%9d ", total.t_avm);
700: (void)printf("%9d ", total.t_arm);
701: (void)printf("%5d ", total.t_vmshr);
702: (void)printf("%6d ", total.t_avmshr);
703: (void)printf("%5d ", total.t_rmshr);
704: (void)printf("%6d ", total.t_armshr);
705: (void)printf("%5d", total.t_free);
1.130 he 706:
1.153 christos 707: (void)putchar('\n');
1.130 he 708:
709: (void)fflush(stdout);
710: if (reps >= 0 && --reps <= 0)
711: break;
712:
1.153 christos 713: (void)nanosleep(interval, NULL);
1.130 he 714: }
715: }
716:
717: void
1.103 mycroft 718: dovmstat(struct timespec *interval, int reps)
1.1 cgd 719: {
720: struct vmtotal total;
721: time_t uptime, halfuptime;
1.17 cgd 722: size_t size;
1.41 mrg 723: int pagesize = getpagesize();
1.151 yamt 724: int ovflw;
1.1 cgd 725:
726: uptime = getuptime();
727: halfuptime = uptime / 2;
728: (void)signal(SIGCONT, needhdr);
729:
1.197 joerg 730: if (memf != NULL) {
731: if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0)
732: kread(namelist, X_STATHZ, &hz, sizeof(hz));
733: if (!hz)
734: kread(namelist, X_HZ, &hz, sizeof(hz));
735: } else {
736: struct clockinfo clockinfo;
737: size = sizeof(clockinfo);
738: if (sysctl(clockrate_mib, 2, &clockinfo, &size, NULL, 0) == -1)
739: err(1, "sysctl kern.clockrate failed");
740: hz = clockinfo.stathz;
741: if (!hz)
742: hz = clockinfo.hz;
743: }
1.1 cgd 744:
745: for (hdrcnt = 1;;) {
746: if (!--hdrcnt)
747: printhdr();
1.29 thorpej 748: /* Read new disk statistics */
1.139 dsl 749: cpureadstats();
1.140 blymn 750: drvreadstats();
1.139 dsl 751: tkreadstats();
1.58 thorpej 752: if (memf != NULL) {
1.196 joerg 753: struct uvmexp uvmexp_kernel;
1.58 thorpej 754: /*
755: * XXX Can't do this if we're reading a crash
756: * XXX dump because they're lazily-calculated.
757: */
1.170 christos 758: warnx("Unable to get vmtotals from crash dump.");
1.153 christos 759: (void)memset(&total, 0, sizeof(total));
1.196 joerg 760: kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel));
761: #define COPY(field) uvmexp.field = uvmexp_kernel.field
762: COPY(pdreact);
763: COPY(pageins);
764: COPY(pgswapout);
765: COPY(pdfreed);
766: COPY(pdscans);
767: #undef COPY
1.58 thorpej 768: } else {
769: size = sizeof(total);
1.170 christos 770: if (sysctl(vmmeter_mib, __arraycount(vmmeter_mib),
771: &total, &size, NULL, 0) == -1) {
772: warn("Can't get vmtotals");
1.153 christos 773: (void)memset(&total, 0, sizeof(total));
1.58 thorpej 774: }
1.196 joerg 775: size = sizeof(uvmexp);
776: if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp,
777: &size, NULL, 0) == -1)
778: warn("sysctl vm.uvmexp2 failed");
1.13 cgd 779: }
1.171 christos 780: cpucounters(&cpucounter);
1.151 yamt 781: ovflw = 0;
782: PRWORD(ovflw, " %*d", 2, 1, total.t_rq - 1);
783: PRWORD(ovflw, " %*d", 2, 1, total.t_dw + total.t_pw);
1.153 christos 784: #define pgtok(a) (long)((a) * ((uint32_t)pagesize >> 10))
1.38 mrg 785: #define rate(x) (u_long)(((x) + halfuptime) / uptime) /* round */
1.166 rmind 786: PRWORD(ovflw, " %*ld", 9, 1, pgtok(total.t_avm));
1.151 yamt 787: PRWORD(ovflw, " %*ld", 7, 1, pgtok(total.t_free));
788: PRWORD(ovflw, " %*ld", 5, 1,
1.171 christos 789: rate(cpucounter.nfault - ocpucounter.nfault));
1.151 yamt 790: PRWORD(ovflw, " %*ld", 4, 1,
791: rate(uvmexp.pdreact - ouvmexp.pdreact));
792: PRWORD(ovflw, " %*ld", 4, 1,
793: rate(uvmexp.pageins - ouvmexp.pageins));
794: PRWORD(ovflw, " %*ld", 5, 1,
1.44 mrg 795: rate(uvmexp.pgswapout - ouvmexp.pgswapout));
1.151 yamt 796: PRWORD(ovflw, " %*ld", 5, 1,
797: rate(uvmexp.pdfreed - ouvmexp.pdfreed));
798: PRWORD(ovflw, " %*ld", 6, 2,
799: rate(uvmexp.pdscans - ouvmexp.pdscans));
800: drvstats(&ovflw);
801: PRWORD(ovflw, " %*ld", 5, 1,
1.171 christos 802: rate(cpucounter.nintr - ocpucounter.nintr));
1.151 yamt 803: PRWORD(ovflw, " %*ld", 5, 1,
1.171 christos 804: rate(cpucounter.nsyscall - ocpucounter.nsyscall));
1.151 yamt 805: PRWORD(ovflw, " %*ld", 4, 1,
1.171 christos 806: rate(cpucounter.nswtch - ocpucounter.nswtch));
1.151 yamt 807: cpustats(&ovflw);
1.153 christos 808: (void)putchar('\n');
1.42 mrg 809: (void)fflush(stdout);
810: if (reps >= 0 && --reps <= 0)
811: break;
1.172 enami 812: ouvmexp = uvmexp;
1.171 christos 813: ocpucounter = cpucounter;
1.103 mycroft 814: uptime = interval->tv_sec;
1.1 cgd 815: /*
816: * We round upward to avoid losing low-frequency events
817: * (i.e., >= 1 per interval but < 1 per second).
818: */
1.33 thorpej 819: halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2;
1.153 christos 820: (void)nanosleep(interval, NULL);
1.1 cgd 821: }
822: }
823:
1.38 mrg 824: void
1.73 simonb 825: printhdr(void)
1.1 cgd 826: {
1.165 lukem 827: size_t i;
1.1 cgd 828:
1.104 mrg 829: (void)printf(" procs memory page%*s", 23, "");
1.29 thorpej 830: if (ndrives > 0)
1.70 sommerfe 831: (void)printf("%s %*sfaults cpu\n",
1.75 enami 832: ((ndrives > 1) ? "disks" : "disk"),
833: ((ndrives > 1) ? ndrives * 3 - 4 : 0), "");
1.1 cgd 834: else
1.29 thorpej 835: (void)printf("%*s faults cpu\n",
1.75 enami 836: ndrives * 3, "");
1.29 thorpej 837:
1.166 rmind 838: (void)printf(" r b avm fre flt re pi po fr sr ");
1.140 blymn 839: for (i = 0; i < ndrive; i++)
840: if (drv_select[i])
1.1 cgd 841: (void)printf("%c%c ", dr_name[i][0],
842: dr_name[i][strlen(dr_name[i]) - 1]);
843: (void)printf(" in sy cs us sy id\n");
844: hdrcnt = winlines - 2;
845: }
846:
847: /*
848: * Force a header to be prepended to the next output.
849: */
850: void
1.153 christos 851: /*ARGSUSED*/
1.73 simonb 852: needhdr(int dummy)
1.1 cgd 853: {
854:
855: hdrcnt = 1;
856: }
857:
1.38 mrg 858: long
1.203 nakayama 859: pct(u_long top, u_long bot)
1.1 cgd 860: {
1.13 cgd 861: long ans;
862:
1.1 cgd 863: if (bot == 0)
1.75 enami 864: return (0);
1.153 christos 865: ans = (long)((quad_t)top * 100 / bot);
1.13 cgd 866: return (ans);
1.1 cgd 867: }
868:
1.203 nakayama 869: #define PCT(top, bot) (int)pct((u_long)(top), (u_long)(bot))
1.1 cgd 870:
871: void
1.73 simonb 872: dosum(void)
1.1 cgd 873: {
1.206 dennis 874: struct nchstats nch_stats;
1.194 joerg 875: uint64_t nchtotal;
1.162 he 876: size_t ssize;
877: int active_kernel;
1.171 christos 878: struct cpu_counter cc;
1.162 he 879:
880: /*
881: * The "active" and "inactive" variables
882: * are now estimated by the kernel and sadly
883: * can not easily be dug out of a crash dump.
884: */
1.195 joerg 885: ssize = sizeof(uvmexp);
886: memset(&uvmexp, 0, ssize);
1.162 he 887: active_kernel = (memf == NULL);
888: if (active_kernel) {
889: /* only on active kernel */
1.195 joerg 890: if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp,
1.170 christos 891: &ssize, NULL, 0) == -1)
892: warn("sysctl vm.uvmexp2 failed");
1.195 joerg 893: } else {
894: struct uvmexp uvmexp_kernel;
895: kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel));
896: #define COPY(field) uvmexp.field = uvmexp_kernel.field
897: COPY(pagesize);
898: COPY(ncolors);
899: COPY(npages);
900: COPY(free);
901: COPY(paging);
902: COPY(wired);
903: COPY(zeropages);
904: COPY(reserve_pagedaemon);
905: COPY(reserve_kernel);
906: COPY(anonpages);
907: COPY(filepages);
908: COPY(execpages);
909: COPY(freemin);
910: COPY(freetarg);
911: COPY(wiredmax);
912: COPY(nswapdev);
913: COPY(swpages);
914: COPY(swpginuse);
915: COPY(nswget);
916: COPY(pageins);
917: COPY(pdpageouts);
918: COPY(pgswapin);
919: COPY(pgswapout);
920: COPY(forks);
921: COPY(forks_ppwait);
922: COPY(forks_sharevm);
923: COPY(pga_zerohit);
924: COPY(pga_zeromiss);
925: COPY(zeroaborts);
926: COPY(colorhit);
927: COPY(colormiss);
928: COPY(cpuhit);
929: COPY(cpumiss);
930: COPY(fltnoram);
931: COPY(fltnoanon);
932: COPY(fltpgwait);
933: COPY(fltpgrele);
934: COPY(fltrelck);
935: COPY(fltrelckok);
936: COPY(fltanget);
937: COPY(fltanretry);
938: COPY(fltamcopy);
939: COPY(fltamcopy);
940: COPY(fltnomap);
941: COPY(fltlget);
942: COPY(fltget);
943: COPY(flt_anon);
944: COPY(flt_acow);
945: COPY(flt_obj);
946: COPY(flt_prcopy);
947: COPY(flt_przero);
948: COPY(pdwoke);
949: COPY(pdrevs);
950: COPY(pdfreed);
951: COPY(pdscans);
952: COPY(pdanscan);
953: COPY(pdobscan);
954: COPY(pdreact);
955: COPY(pdbusy);
956: COPY(pdpending);
957: COPY(pddeact);
958: #undef COPY
1.162 he 959: }
1.1 cgd 960:
1.41 mrg 961:
1.195 joerg 962: (void)printf("%9" PRIu64 " bytes per page\n", uvmexp.pagesize);
1.44 mrg 963:
1.195 joerg 964: (void)printf("%9" PRIu64 " page color%s\n",
1.81 thorpej 965: uvmexp.ncolors, uvmexp.ncolors == 1 ? "" : "s");
966:
1.195 joerg 967: (void)printf("%9" PRIu64 " pages managed\n", uvmexp.npages);
968: (void)printf("%9" PRIu64 " pages free\n", uvmexp.free);
1.162 he 969: if (active_kernel) {
1.195 joerg 970: (void)printf("%9" PRIu64 " pages active\n", uvmexp.active);
971: (void)printf("%9" PRIu64 " pages inactive\n", uvmexp.inactive);
1.162 he 972: }
1.195 joerg 973: (void)printf("%9" PRIu64 " pages paging\n", uvmexp.paging);
974: (void)printf("%9" PRIu64 " pages wired\n", uvmexp.wired);
975: (void)printf("%9" PRIu64 " zero pages\n", uvmexp.zeropages);
976: (void)printf("%9" PRIu64 " reserve pagedaemon pages\n",
1.44 mrg 977: uvmexp.reserve_pagedaemon);
1.195 joerg 978: (void)printf("%9" PRIu64 " reserve kernel pages\n", uvmexp.reserve_kernel);
979: (void)printf("%9" PRIu64 " anonymous pages\n", uvmexp.anonpages);
980: (void)printf("%9" PRIu64 " cached file pages\n", uvmexp.filepages);
981: (void)printf("%9" PRIu64 " cached executable pages\n", uvmexp.execpages);
982:
983: (void)printf("%9" PRIu64 " minimum free pages\n", uvmexp.freemin);
984: (void)printf("%9" PRIu64 " target free pages\n", uvmexp.freetarg);
985: (void)printf("%9" PRIu64 " maximum wired pages\n", uvmexp.wiredmax);
986:
987: (void)printf("%9" PRIu64 " swap devices\n", uvmexp.nswapdev);
988: (void)printf("%9" PRIu64 " swap pages\n", uvmexp.swpages);
989: (void)printf("%9" PRIu64 " swap pages in use\n", uvmexp.swpginuse);
990: (void)printf("%9" PRIu64 " swap allocations\n", uvmexp.nswget);
1.44 mrg 991:
1.171 christos 992: cpucounters(&cc);
1.190 rmind 993:
1.171 christos 994: (void)printf("%9" PRIu64 " total faults taken\n", cc.nfault);
995: (void)printf("%9" PRIu64 " traps\n", cc.ntrap);
996: (void)printf("%9" PRIu64 " device interrupts\n", cc.nintr);
997: (void)printf("%9" PRIu64 " CPU context switches\n", cc.nswtch);
998: (void)printf("%9" PRIu64 " software interrupts\n", cc.nsoft);
999: (void)printf("%9" PRIu64 " system calls\n", cc.nsyscall);
1.195 joerg 1000: (void)printf("%9" PRIu64 " pagein requests\n", uvmexp.pageins);
1001: (void)printf("%9" PRIu64 " pageout requests\n", uvmexp.pdpageouts);
1002: (void)printf("%9" PRIu64 " pages swapped in\n", uvmexp.pgswapin);
1003: (void)printf("%9" PRIu64 " pages swapped out\n", uvmexp.pgswapout);
1004: (void)printf("%9" PRIu64 " forks total\n", uvmexp.forks);
1005: (void)printf("%9" PRIu64 " forks blocked parent\n", uvmexp.forks_ppwait);
1006: (void)printf("%9" PRIu64 " forks shared address space with parent\n",
1.43 mrg 1007: uvmexp.forks_sharevm);
1.195 joerg 1008: (void)printf("%9" PRIu64 " pagealloc zero wanted and avail\n",
1.63 thorpej 1009: uvmexp.pga_zerohit);
1.195 joerg 1010: (void)printf("%9" PRIu64 " pagealloc zero wanted and not avail\n",
1.63 thorpej 1011: uvmexp.pga_zeromiss);
1.195 joerg 1012: (void)printf("%9" PRIu64 " aborts of idle page zeroing\n",
1.68 thorpej 1013: uvmexp.zeroaborts);
1.195 joerg 1014: (void)printf("%9" PRIu64 " pagealloc desired color avail\n",
1.79 thorpej 1015: uvmexp.colorhit);
1.195 joerg 1016: (void)printf("%9" PRIu64 " pagealloc desired color not avail\n",
1.79 thorpej 1017: uvmexp.colormiss);
1.195 joerg 1018: (void)printf("%9" PRIu64 " pagealloc local cpu avail\n",
1.159 ad 1019: uvmexp.cpuhit);
1.195 joerg 1020: (void)printf("%9" PRIu64 " pagealloc local cpu not avail\n",
1.159 ad 1021: uvmexp.cpumiss);
1.44 mrg 1022:
1.195 joerg 1023: (void)printf("%9" PRIu64 " faults with no memory\n", uvmexp.fltnoram);
1024: (void)printf("%9" PRIu64 " faults with no anons\n", uvmexp.fltnoanon);
1025: (void)printf("%9" PRIu64 " faults had to wait on pages\n", uvmexp.fltpgwait);
1026: (void)printf("%9" PRIu64 " faults found released page\n", uvmexp.fltpgrele);
1027: (void)printf("%9" PRIu64 " faults relock (%" PRIu64 " ok)\n", uvmexp.fltrelck,
1.43 mrg 1028: uvmexp.fltrelckok);
1.195 joerg 1029: (void)printf("%9" PRIu64 " anon page faults\n", uvmexp.fltanget);
1030: (void)printf("%9" PRIu64 " anon retry faults\n", uvmexp.fltanretry);
1031: (void)printf("%9" PRIu64 " amap copy faults\n", uvmexp.fltamcopy);
1032: (void)printf("%9" PRIu64 " neighbour anon page faults\n", uvmexp.fltnamap);
1033: (void)printf("%9" PRIu64 " neighbour object page faults\n", uvmexp.fltnomap);
1034: (void)printf("%9" PRIu64 " locked pager get faults\n", uvmexp.fltlget);
1035: (void)printf("%9" PRIu64 " unlocked pager get faults\n", uvmexp.fltget);
1036: (void)printf("%9" PRIu64 " anon faults\n", uvmexp.flt_anon);
1037: (void)printf("%9" PRIu64 " anon copy on write faults\n", uvmexp.flt_acow);
1038: (void)printf("%9" PRIu64 " object faults\n", uvmexp.flt_obj);
1039: (void)printf("%9" PRIu64 " promote copy faults\n", uvmexp.flt_prcopy);
1040: (void)printf("%9" PRIu64 " promote zero fill faults\n", uvmexp.flt_przero);
1041:
1042: (void)printf("%9" PRIu64 " times daemon wokeup\n",uvmexp.pdwoke);
1043: (void)printf("%9" PRIu64 " revolutions of the clock hand\n", uvmexp.pdrevs);
1044: (void)printf("%9" PRIu64 " pages freed by daemon\n", uvmexp.pdfreed);
1045: (void)printf("%9" PRIu64 " pages scanned by daemon\n", uvmexp.pdscans);
1046: (void)printf("%9" PRIu64 " anonymous pages scanned by daemon\n",
1.75 enami 1047: uvmexp.pdanscan);
1.195 joerg 1048: (void)printf("%9" PRIu64 " object pages scanned by daemon\n", uvmexp.pdobscan);
1049: (void)printf("%9" PRIu64 " pages reactivated\n", uvmexp.pdreact);
1050: (void)printf("%9" PRIu64 " pages found busy by daemon\n", uvmexp.pdbusy);
1051: (void)printf("%9" PRIu64 " total pending pageouts\n", uvmexp.pdpending);
1052: (void)printf("%9" PRIu64 " pages deactivated\n", uvmexp.pddeact);
1.123 enami 1053:
1.194 joerg 1054: if (active_kernel) {
1055: ssize = sizeof(nch_stats);
1056: if (sysctlbyname("vfs.namecache_stats", &nch_stats, &ssize,
1057: NULL, 0)) {
1058: warn("vfs.namecache_stats failed");
1059: memset(&nch_stats, 0, sizeof(nch_stats));
1060: }
1061: } else {
1.206 dennis 1062: kread(namelist, X_NCHSTATS, &nch_stats, sizeof(nch_stats));
1.194 joerg 1063: }
1064:
1065: nchtotal = nch_stats.ncs_goodhits + nch_stats.ncs_neghits +
1066: nch_stats.ncs_badhits + nch_stats.ncs_falsehits +
1067: nch_stats.ncs_miss + nch_stats.ncs_long;
1068: (void)printf("%9" PRIu64 " total name lookups\n", nchtotal);
1069: (void)printf("%9" PRIu64 " good hits\n", nch_stats.ncs_goodhits);
1070: (void)printf("%9" PRIu64 " negative hits\n", nch_stats.ncs_neghits);
1071: (void)printf("%9" PRIu64 " bad hits\n", nch_stats.ncs_badhits);
1072: (void)printf("%9" PRIu64 " false hits\n", nch_stats.ncs_falsehits);
1073: (void)printf("%9" PRIu64 " miss\n", nch_stats.ncs_miss);
1074: (void)printf("%9" PRIu64 " too long\n", nch_stats.ncs_long);
1075: (void)printf("%9" PRIu64 " pass2 hits\n", nch_stats.ncs_pass2);
1076: (void)printf("%9" PRIu64 " 2passes\n", nch_stats.ncs_2passes);
1.1 cgd 1077: (void)printf(
1078: "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
1.194 joerg 1079: "", PCT(nch_stats.ncs_goodhits, nchtotal),
1080: PCT(nch_stats.ncs_neghits, nchtotal),
1081: PCT(nch_stats.ncs_pass2, nchtotal));
1.1 cgd 1082: (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
1.194 joerg 1083: PCT(nch_stats.ncs_badhits, nchtotal),
1084: PCT(nch_stats.ncs_falsehits, nchtotal),
1085: PCT(nch_stats.ncs_long, nchtotal));
1.1 cgd 1086: }
1087:
1088: void
1.73 simonb 1089: doforkst(void)
1.1 cgd 1090: {
1.196 joerg 1091: if (memf != NULL) {
1092: struct uvmexp uvmexp_kernel;
1093: kread(namelist, X_UVMEXP, &uvmexp_kernel, sizeof(uvmexp_kernel));
1094: #define COPY(field) uvmexp.field = uvmexp_kernel.field
1095: COPY(forks);
1096: COPY(forks_ppwait);
1097: COPY(forks_sharevm);
1098: #undef COPY
1099: } else {
1100: size_t size = sizeof(uvmexp);
1101: if (sysctl(uvmexp2_mib, __arraycount(uvmexp2_mib), &uvmexp,
1102: &size, NULL, 0) == -1)
1103: warn("sysctl vm.uvmexp2 failed");
1104: }
1.58 thorpej 1105:
1.196 joerg 1106: (void)printf("%" PRIu64 " forks total\n", uvmexp.forks);
1107: (void)printf("%" PRIu64 " forks blocked parent\n", uvmexp.forks_ppwait);
1108: (void)printf("%" PRIu64 " forks shared address space with parent\n",
1.41 mrg 1109: uvmexp.forks_sharevm);
1.1 cgd 1110: }
1111:
1112: void
1.151 yamt 1113: drvstats(int *ovflwp)
1.1 cgd 1114: {
1.165 lukem 1115: size_t dn;
1.216.6.1 snj 1116: double dtime;
1.151 yamt 1117: int ovflw = *ovflwp;
1.1 cgd 1118:
1.29 thorpej 1119: /* Calculate disk stat deltas. */
1.139 dsl 1120: cpuswap();
1.140 blymn 1121: drvswap();
1.139 dsl 1122: tkswap();
1.101 sommerfe 1123:
1.140 blymn 1124: for (dn = 0; dn < ndrive; ++dn) {
1.216.6.1 snj 1125: /* elapsed time for disk stats */
1126: dtime = (double)cur.timestamp[dn].tv_sec +
1127: ((double)cur.timestamp[dn].tv_usec / (double)1000000);
1128:
1.140 blymn 1129: if (!drv_select[dn])
1.151 yamt 1130: continue;
1131: PRWORD(ovflw, " %*.0f", 3, 1,
1.216.6.1 snj 1132: (cur.rxfer[dn] + cur.wxfer[dn]) / dtime);
1.136 blymn 1133: }
1.151 yamt 1134: *ovflwp = ovflw;
1.136 blymn 1135: }
1136:
1137: void
1.171 christos 1138: cpucounters(struct cpu_counter *cc)
1139: {
1.198 joerg 1140: static struct cpu_info **cpu_infos;
1141: static int initialised;
1142: struct cpu_info **slot;
1143:
1144: if (memf == NULL) {
1145: cc->nintr = uvmexp.intrs;
1146: cc->nsyscall = uvmexp.syscalls;
1147: cc->nswtch = uvmexp.swtch;
1148: cc->nfault = uvmexp.faults;
1149: cc->ntrap = uvmexp.traps;
1150: cc->nsoft = uvmexp.softs;
1151: return;
1152: }
1153:
1154: if (!initialised) {
1155: kread(namelist, X_CPU_INFOS, &cpu_infos, sizeof(cpu_infos));
1156: initialised = 1;
1157: }
1158:
1159: slot = cpu_infos;
1.190 rmind 1160:
1161: memset(cc, 0, sizeof(*cc));
1162:
1163: for (;;) {
1164: struct cpu_info tci, *ci = NULL;
1165:
1166: deref_kptr(slot++, &ci, sizeof(ci), "CPU array trashed");
1167: if (!ci) {
1168: break;
1169: }
1170:
1.171 christos 1171: if ((size_t)kvm_read(kd, (u_long)ci, &tci, sizeof(tci))
1172: != sizeof(tci)) {
1.190 rmind 1173: warnx("Can't read cpu info from %p (%s)",
1174: ci, kvm_geterr(kd));
1175: memset(cc, 0, sizeof(*cc));
1176: return;
1.171 christos 1177: }
1178: cc->nintr += tci.ci_data.cpu_nintr;
1179: cc->nsyscall += tci.ci_data.cpu_nsyscall;
1180: cc->nswtch = tci.ci_data.cpu_nswtch;
1181: cc->nfault = tci.ci_data.cpu_nfault;
1182: cc->ntrap = tci.ci_data.cpu_ntrap;
1183: cc->nsoft = tci.ci_data.cpu_nsoft;
1184: }
1185: }
1186:
1187: void
1.151 yamt 1188: cpustats(int *ovflwp)
1.1 cgd 1189: {
1.38 mrg 1190: int state;
1.129 dsl 1191: double pcnt, total;
1.120 dbj 1192: double stat_us, stat_sy, stat_id;
1.151 yamt 1193: int ovflw = *ovflwp;
1.1 cgd 1194:
1195: total = 0;
1196: for (state = 0; state < CPUSTATES; ++state)
1.29 thorpej 1197: total += cur.cp_time[state];
1.1 cgd 1198: if (total)
1.129 dsl 1199: pcnt = 100 / total;
1.1 cgd 1200: else
1.129 dsl 1201: pcnt = 0;
1202: stat_us = (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * pcnt;
1203: stat_sy = (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * pcnt;
1204: stat_id = cur.cp_time[CP_IDLE] * pcnt;
1.151 yamt 1205: PRWORD(ovflw, " %*.0f", ((stat_sy >= 100) ? 2 : 3), 1, stat_us);
1206: PRWORD(ovflw, " %*.0f", ((stat_us >= 100 || stat_id >= 100) ? 2 : 3), 1,
1207: stat_sy);
1208: PRWORD(ovflw, " %*.0f", 3, 1, stat_id);
1209: *ovflwp = ovflw;
1.1 cgd 1210: }
1211:
1212: void
1.66 cgd 1213: dointr(int verbose)
1.1 cgd 1214: {
1.138 nonaka 1215: unsigned long *intrcnt, *ointrcnt;
1.85 enami 1216: unsigned long long inttotal, uptime;
1.38 mrg 1217: int nintr, inamlen;
1.138 nonaka 1218: char *intrname, *ointrname;
1.1 cgd 1219:
1.133 chs 1220: inttotal = 0;
1.1 cgd 1221: uptime = getuptime();
1.133 chs 1222: nintr = intrnl[X_EINTRCNT].n_value - intrnl[X_INTRCNT].n_value;
1223: inamlen = intrnl[X_EINTRNAMES].n_value - intrnl[X_INTRNAMES].n_value;
1224: if (nintr != 0 && inamlen != 0) {
1.216 ryo 1225: (void)printf("%-34s %16s %8s\n", "interrupt", "total", "rate");
1226:
1.138 nonaka 1227: ointrcnt = intrcnt = malloc((size_t)nintr);
1228: ointrname = intrname = malloc((size_t)inamlen);
1.133 chs 1229: if (intrcnt == NULL || intrname == NULL)
1230: errx(1, "%s", "");
1231: kread(intrnl, X_INTRCNT, intrcnt, (size_t)nintr);
1232: kread(intrnl, X_INTRNAMES, intrname, (size_t)inamlen);
1233: nintr /= sizeof(long);
1234: while (--nintr >= 0) {
1235: if (*intrcnt || verbose)
1236: (void)printf("%-34s %16llu %8llu\n", intrname,
1237: (unsigned long long)*intrcnt,
1238: (unsigned long long)
1239: (*intrcnt / uptime));
1240: intrname += strlen(intrname) + 1;
1241: inttotal += *intrcnt++;
1242: }
1.138 nonaka 1243: free(ointrcnt);
1244: free(ointrname);
1.1 cgd 1245: }
1.133 chs 1246:
1.176 matt 1247: doevcnt(verbose, EVCNT_TYPE_INTR);
1.66 cgd 1248: }
1249:
1250: void
1.176 matt 1251: doevcnt(int verbose, int type)
1.66 cgd 1252: {
1.176 matt 1253: static const char * const evtypes [] = { "misc", "intr", "trap" };
1254: uint64_t counttotal, uptime;
1.66 cgd 1255: struct evcntlist allevents;
1256: struct evcnt evcnt, *evptr;
1.216 ryo 1257: size_t evlen_max, total_max, rate_max;
1.66 cgd 1258: char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX];
1259:
1.176 matt 1260: counttotal = 0;
1.66 cgd 1261: uptime = getuptime();
1.176 matt 1262:
1263: if (memf == NULL) do {
1264: const int mib[4] = { CTL_KERN, KERN_EVCNT, type,
1265: verbose ? KERN_EVCNT_COUNT_ANY : KERN_EVCNT_COUNT_NONZERO };
1.216 ryo 1266: size_t buflen0, buflen = 0;
1267: void *buf0, *buf = NULL;
1.176 matt 1268: const struct evcnt_sysctl *evs, *last_evs;
1269: for (;;) {
1270: size_t newlen;
1271: int error;
1272: if (buflen)
1273: buf = malloc(buflen);
1274: error = sysctl(mib, __arraycount(mib),
1275: buf, &newlen, NULL, 0);
1276: if (error) {
1.193 joerg 1277: err(1, "kern.evcnt");
1.176 matt 1278: if (buf)
1279: free(buf);
1280: return;
1281: }
1282: if (newlen <= buflen) {
1283: buflen = newlen;
1284: break;
1285: }
1286: if (buf)
1287: free(buf);
1288: buflen = newlen;
1289: }
1.216 ryo 1290: buflen0 = buflen;
1291: evs = buf0 = buf;
1292: last_evs = (void *)((char *)buf + buflen);
1293: buflen /= sizeof(uint64_t);
1294: /* calc columns */
1295: evlen_max = 0;
1296: total_max = sizeof("total") - 1;
1297: rate_max = sizeof("rate") - 1;
1298: while (evs < last_evs
1299: && buflen >= sizeof(*evs)/sizeof(uint64_t)
1300: && buflen >= evs->ev_len) {
1301: char cbuf[64];
1302: size_t len;
1303: len = strlen(evs->ev_strings + evs->ev_grouplen + 1);
1304: len += evs->ev_grouplen + 1;
1305: if (evlen_max < len)
1306: evlen_max= len;
1307: len = snprintf(cbuf, sizeof(cbuf), "%"PRIu64,
1308: evs->ev_count);
1309: if (total_max < len)
1310: total_max = len;
1311: len = snprintf(cbuf, sizeof(cbuf), "%"PRIu64,
1312: evs->ev_count / uptime);
1313: if (rate_max < len)
1314: rate_max = len;
1315: buflen -= evs->ev_len;
1316: evs = (const void *)
1317: ((const uint64_t *)evs + evs->ev_len);
1318: }
1319:
1320: (void)printf(type == EVCNT_TYPE_ANY ?
1321: "%-*s %*s %*s %s\n" :
1322: "%-*s %*s %*s\n",
1323: (int)evlen_max, "interrupt",
1324: (int)total_max, "total",
1325: (int)rate_max, "rate",
1326: "type");
1327:
1328: buflen = buflen0;
1329: evs = buf0;
1.176 matt 1330: last_evs = (void *)((char *)buf + buflen);
1331: buflen /= sizeof(uint64_t);
1332: while (evs < last_evs
1333: && buflen >= sizeof(*evs)/sizeof(uint64_t)
1334: && buflen >= evs->ev_len) {
1.180 nakayama 1335: (void)printf(type == EVCNT_TYPE_ANY ?
1.216 ryo 1336: "%s %s%*s %*"PRIu64" %*"PRIu64" %s\n" :
1337: "%s %s%*s %*"PRIu64" %*"PRIu64"\n",
1.176 matt 1338: evs->ev_strings,
1339: evs->ev_strings + evs->ev_grouplen + 1,
1.216 ryo 1340: (int)evlen_max - (evs->ev_grouplen + 1
1341: + evs->ev_namelen), "",
1342: (int)total_max, evs->ev_count,
1343: (int)rate_max, evs->ev_count / uptime,
1.176 matt 1344: (evs->ev_type < __arraycount(evtypes) ?
1.216 ryo 1345: evtypes[evs->ev_type] : "?"));
1.176 matt 1346: buflen -= evs->ev_len;
1.180 nakayama 1347: counttotal += evs->ev_count;
1.216 ryo 1348: evs = (const void *)
1349: ((const uint64_t *)evs + evs->ev_len);
1.176 matt 1350: }
1351: free(buf);
1352: if (type != EVCNT_TYPE_ANY)
1.216 ryo 1353: (void)printf("%-*s %*"PRIu64" %*"PRIu64"\n",
1354: (int)evlen_max, "Total",
1355: (int)total_max, counttotal,
1356: (int)rate_max, counttotal / uptime);
1.176 matt 1357: return;
1358: } while (/*CONSTCOND*/ 0);
1359:
1.216 ryo 1360: if (type == EVCNT_TYPE_ANY)
1361: (void)printf("%-34s %16s %8s %s\n", "event", "total", "rate",
1362: "type");
1363:
1.133 chs 1364: kread(namelist, X_ALLEVENTS, &allevents, sizeof allevents);
1365: evptr = TAILQ_FIRST(&allevents);
1.66 cgd 1366: while (evptr) {
1.87 lukem 1367: deref_kptr(evptr, &evcnt, sizeof(evcnt), "event chain trashed");
1.32 cgd 1368:
1.133 chs 1369: evptr = TAILQ_NEXT(&evcnt, ev_list);
1.66 cgd 1370: if (evcnt.ev_count == 0 && !verbose)
1371: continue;
1.176 matt 1372: if (type != EVCNT_TYPE_ANY && evcnt.ev_type != type)
1373: continue;
1.66 cgd 1374:
1.153 christos 1375: deref_kptr(evcnt.ev_group, evgroup,
1376: (size_t)evcnt.ev_grouplen + 1, "event chain trashed");
1377: deref_kptr(evcnt.ev_name, evname,
1378: (size_t)evcnt.ev_namelen + 1, "event chain trashed");
1.66 cgd 1379:
1.180 nakayama 1380: (void)printf(type == EVCNT_TYPE_ANY ?
1381: "%s %s%*s %16"PRIu64" %8"PRIu64" %s\n" :
1382: "%s %s%*s %16"PRIu64" %8"PRIu64"\n",
1.176 matt 1383: evgroup, evname,
1.83 matt 1384: 34 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "",
1.176 matt 1385: evcnt.ev_count,
1386: (evcnt.ev_count / uptime),
1387: (evcnt.ev_type < __arraycount(evtypes) ?
1.86 enami 1388: evtypes[evcnt.ev_type] : "?"));
1.176 matt 1389:
1.180 nakayama 1390: counttotal += evcnt.ev_count;
1.18 pk 1391: }
1.176 matt 1392: if (type != EVCNT_TYPE_ANY)
1393: (void)printf("%-34s %16"PRIu64" %8"PRIu64"\n",
1394: "Total", counttotal, counttotal / uptime);
1.1 cgd 1395: }
1396:
1.200 joerg 1397: static void
1398: dopool_sysctl(int verbose, int wide)
1399: {
1400: uint64_t total, inuse, this_total, this_inuse;
1401: struct {
1402: uint64_t pt_nget;
1403: uint64_t pt_nfail;
1404: uint64_t pt_nput;
1405: uint64_t pt_nout;
1406: uint64_t pt_nitems;
1407: uint64_t pt_npagealloc;
1408: uint64_t pt_npagefree;
1409: uint64_t pt_npages;
1410: } pool_totals;
1411: size_t i, len;
1412: int name_len, ovflw;
1413: struct pool_sysctl *pp, *data;
1414: char in_use[8], avail[8], maxp[32];
1415:
1416: data = asysctlbyname("kern.pool", &len);
1417: if (data == NULL)
1418: err(1, "failed to reead kern.pool");
1419:
1.202 joerg 1420: memset(&pool_totals, 0, sizeof pool_totals);
1.200 joerg 1421: total = inuse = 0;
1422: len /= sizeof(*data);
1423:
1424: (void)printf("Memory resource pool statistics\n");
1425: (void)printf(
1426: "%-*s%*s%*s%5s%*s%s%s%*s%*s%6s%s%6s%6s%6s%5s%s%s\n",
1427: wide ? 16 : 11, "Name",
1428: wide ? 6 : 5, "Size",
1429: wide ? 12 : 9, "Requests",
1430: "Fail",
1431: wide ? 12 : 9, "Releases",
1432: wide ? " InUse" : "",
1433: wide ? " Avail" : "",
1434: wide ? 7 : 6, "Pgreq",
1435: wide ? 7 : 6, "Pgrel",
1436: "Npage",
1437: wide ? " PageSz" : "",
1438: "Hiwat",
1439: "Minpg",
1440: "Maxpg",
1441: "Idle",
1442: wide ? " Flags" : "",
1443: wide ? " Util" : "");
1444:
1445: name_len = MIN((int)sizeof(pp->pr_wchan), wide ? 16 : 11);
1446: for (i = 0; i < len; ++i) {
1447: pp = &data[i];
1448: if (pp->pr_nget == 0 && !verbose)
1449: continue;
1450: if (pp->pr_maxpages == UINT_MAX)
1451: (void)snprintf(maxp, sizeof(maxp), "inf");
1452: else
1453: (void)snprintf(maxp, sizeof(maxp), "%" PRIu64,
1454: pp->pr_maxpages);
1455: ovflw = 0;
1456: PRWORD(ovflw, "%-*s", name_len, 0, pp->pr_wchan);
1457: PRWORD(ovflw, " %*" PRIu64, wide ? 6 : 5, 1, pp->pr_size);
1458: PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pp->pr_nget);
1459: pool_totals.pt_nget += pp->pr_nget;
1460: PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_nfail);
1461: pool_totals.pt_nfail += pp->pr_nfail;
1462: PRWORD(ovflw, " %*" PRIu64, wide ? 12 : 9, 1, pp->pr_nput);
1463: pool_totals.pt_nput += pp->pr_nput;
1464: if (wide) {
1465: PRWORD(ovflw, " %*" PRIu64, 7, 1, pp->pr_nout);
1466: pool_totals.pt_nout += pp->pr_nout;
1467: }
1468: if (wide) {
1469: PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_nitems);
1470: pool_totals.pt_nitems += pp->pr_nitems;
1471: }
1472: PRWORD(ovflw, " %*" PRIu64, wide ? 7 : 6, 1, pp->pr_npagealloc);
1473: pool_totals.pt_npagealloc += pp->pr_npagealloc;
1474: PRWORD(ovflw, " %*" PRIu64, wide ? 7 : 6, 1, pp->pr_npagefree);
1475: pool_totals.pt_npagefree += pp->pr_npagefree;
1476: PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_npages);
1477: pool_totals.pt_npages += pp->pr_npages;
1478: if (wide)
1479: PRWORD(ovflw, " %*" PRIu64, 7, 1, pp->pr_pagesize);
1480: PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_hiwat);
1481: PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_minpages);
1482: PRWORD(ovflw, " %*s", 6, 1, maxp);
1483: PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_nidle);
1484: if (wide)
1485: PRWORD(ovflw, " 0x%0*" PRIx64, 4, 1,
1486: pp->pr_flags);
1487:
1488: this_inuse = pp->pr_nout * pp->pr_size;
1489: this_total = pp->pr_npages * pp->pr_pagesize;
1490: if (pp->pr_flags & PR_RECURSIVE) {
1491: /*
1492: * Don't count in-use memory, since it's part
1493: * of another pool and will be accounted for
1494: * there.
1495: */
1496: total += (this_total - this_inuse);
1497: } else {
1498: inuse += this_inuse;
1499: total += this_total;
1500: }
1501: if (wide) {
1502: if (this_total == 0)
1503: (void)printf(" ---");
1504: else
1505: (void)printf(" %5.1f%%",
1506: (100.0 * this_inuse) / this_total);
1507: }
1508: (void)printf("\n");
1509: }
1510: if (wide) {
1511: snprintf(in_use, sizeof in_use, "%7"PRId64, pool_totals.pt_nout);
1512: snprintf(avail, sizeof avail, "%6"PRId64, pool_totals.pt_nitems);
1513: } else {
1514: in_use[0] = '\0';
1515: avail[0] = '\0';
1516: }
1517: (void)printf(
1518: "%-*s%*s%*"PRId64"%5"PRId64"%*"PRId64"%s%s%*"PRId64"%*"PRId64"%6"PRId64"\n",
1519: wide ? 16 : 11, "Totals",
1520: wide ? 6 : 5, "",
1521: wide ? 12 : 9, pool_totals.pt_nget,
1522: pool_totals.pt_nfail,
1523: wide ? 12 : 9, pool_totals.pt_nput,
1524: in_use,
1525: avail,
1526: wide ? 7 : 6, pool_totals.pt_npagealloc,
1527: wide ? 7 : 6, pool_totals.pt_npagefree,
1528: pool_totals.pt_npages);
1529:
1530: inuse /= KILO;
1531: total /= KILO;
1532: (void)printf(
1.201 joerg 1533: "\nIn use %" PRIu64 "K, "
1534: "total allocated %" PRIu64 "K; utilization %.1f%%\n",
1.200 joerg 1535: inuse, total, (100.0 * inuse) / total);
1536:
1537: free(data);
1538: }
1539:
1.51 pk 1540: void
1.126 simonb 1541: dopool(int verbose, int wide)
1.51 pk 1542: {
1.69 enami 1543: int first, ovflw;
1.87 lukem 1544: void *addr;
1.126 simonb 1545: long total, inuse, this_total, this_inuse;
1.189 mrg 1546: struct {
1547: uint64_t pt_nget;
1548: uint64_t pt_nfail;
1549: uint64_t pt_nput;
1550: uint64_t pt_nout;
1551: uint64_t pt_nitems;
1552: uint64_t pt_npagealloc;
1553: uint64_t pt_npagefree;
1554: uint64_t pt_npages;
1555: } pool_totals;
1556: char in_use[8];
1557: char avail[8];
1.157 ad 1558: TAILQ_HEAD(,pool) pool_head;
1.51 pk 1559: struct pool pool, *pp = &pool;
1.98 christos 1560: struct pool_allocator pa;
1.87 lukem 1561: char name[32], maxp[32];
1.51 pk 1562:
1.200 joerg 1563: if (memf == NULL)
1564: return dopool_sysctl(verbose, wide);
1565:
1.189 mrg 1566: memset(&pool_totals, 0, sizeof pool_totals);
1.133 chs 1567: kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head));
1.157 ad 1568: addr = TAILQ_FIRST(&pool_head);
1.51 pk 1569:
1.126 simonb 1570: total = inuse = 0;
1571:
1.157 ad 1572: for (first = 1; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist) ) {
1.87 lukem 1573: deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed");
1.98 christos 1574: deref_kptr(pp->pr_alloc, &pa, sizeof(pa),
1.125 dsainty 1575: "pool allocator trashed");
1.87 lukem 1576: deref_kptr(pp->pr_wchan, name, sizeof(name),
1.98 christos 1577: "pool wait channel trashed");
1.87 lukem 1578: name[sizeof(name)-1] = '\0';
1.51 pk 1579:
1580: if (first) {
1581: (void)printf("Memory resource pool statistics\n");
1582: (void)printf(
1.126 simonb 1583: "%-*s%*s%*s%5s%*s%s%s%*s%*s%6s%s%6s%6s%6s%5s%s%s\n",
1584: wide ? 16 : 11, "Name",
1585: wide ? 6 : 5, "Size",
1586: wide ? 12 : 9, "Requests",
1.75 enami 1587: "Fail",
1.126 simonb 1588: wide ? 12 : 9, "Releases",
1.148 simonb 1589: wide ? " InUse" : "",
1.126 simonb 1590: wide ? " Avail" : "",
1591: wide ? 7 : 6, "Pgreq",
1592: wide ? 7 : 6, "Pgrel",
1.75 enami 1593: "Npage",
1.126 simonb 1594: wide ? " PageSz" : "",
1.75 enami 1595: "Hiwat",
1596: "Minpg",
1597: "Maxpg",
1.126 simonb 1598: "Idle",
1599: wide ? " Flags" : "",
1600: wide ? " Util" : "");
1.51 pk 1601: first = 0;
1602: }
1.113 dsl 1603: if (pp->pr_nget == 0 && !verbose)
1604: continue;
1.51 pk 1605: if (pp->pr_maxpages == UINT_MAX)
1.153 christos 1606: (void)snprintf(maxp, sizeof(maxp), "inf");
1.51 pk 1607: else
1.153 christos 1608: (void)snprintf(maxp, sizeof(maxp), "%u",
1609: pp->pr_maxpages);
1.69 enami 1610: ovflw = 0;
1.126 simonb 1611: PRWORD(ovflw, "%-*s", wide ? 16 : 11, 0, name);
1612: PRWORD(ovflw, " %*u", wide ? 6 : 5, 1, pp->pr_size);
1613: PRWORD(ovflw, " %*lu", wide ? 12 : 9, 1, pp->pr_nget);
1.189 mrg 1614: pool_totals.pt_nget += pp->pr_nget;
1.69 enami 1615: PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nfail);
1.189 mrg 1616: pool_totals.pt_nfail += pp->pr_nfail;
1.126 simonb 1617: PRWORD(ovflw, " %*lu", wide ? 12 : 9, 1, pp->pr_nput);
1.189 mrg 1618: pool_totals.pt_nput += pp->pr_nput;
1619: if (wide) {
1.148 simonb 1620: PRWORD(ovflw, " %*u", 7, 1, pp->pr_nout);
1.189 mrg 1621: pool_totals.pt_nout += pp->pr_nout;
1622: }
1623: if (wide) {
1.126 simonb 1624: PRWORD(ovflw, " %*u", 6, 1, pp->pr_nitems);
1.189 mrg 1625: pool_totals.pt_nitems += pp->pr_nitems;
1626: }
1.126 simonb 1627: PRWORD(ovflw, " %*lu", wide ? 7 : 6, 1, pp->pr_npagealloc);
1.189 mrg 1628: pool_totals.pt_npagealloc += pp->pr_npagealloc;
1.126 simonb 1629: PRWORD(ovflw, " %*lu", wide ? 7 : 6, 1, pp->pr_npagefree);
1.189 mrg 1630: pool_totals.pt_npagefree += pp->pr_npagefree;
1.126 simonb 1631: PRWORD(ovflw, " %*u", 6, 1, pp->pr_npages);
1.189 mrg 1632: pool_totals.pt_npages += pp->pr_npages;
1.126 simonb 1633: if (wide)
1634: PRWORD(ovflw, " %*u", 7, 1, pa.pa_pagesz);
1635: PRWORD(ovflw, " %*u", 6, 1, pp->pr_hiwat);
1636: PRWORD(ovflw, " %*u", 6, 1, pp->pr_minpages);
1.69 enami 1637: PRWORD(ovflw, " %*s", 6, 1, maxp);
1.126 simonb 1638: PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nidle);
1639: if (wide)
1640: PRWORD(ovflw, " 0x%0*x", 4, 1,
1641: pp->pr_flags | pp->pr_roflags);
1.51 pk 1642:
1.126 simonb 1643: this_inuse = pp->pr_nout * pp->pr_size;
1644: this_total = pp->pr_npages * pa.pa_pagesz;
1.84 bjh21 1645: if (pp->pr_roflags & PR_RECURSIVE) {
1646: /*
1647: * Don't count in-use memory, since it's part
1648: * of another pool and will be accounted for
1649: * there.
1650: */
1.126 simonb 1651: total += (this_total - this_inuse);
1.84 bjh21 1652: } else {
1.126 simonb 1653: inuse += this_inuse;
1654: total += this_total;
1.84 bjh21 1655: }
1.126 simonb 1656: if (wide) {
1657: if (this_total == 0)
1.153 christos 1658: (void)printf(" ---");
1.126 simonb 1659: else
1.153 christos 1660: (void)printf(" %5.1f%%",
1.126 simonb 1661: (100.0 * this_inuse) / this_total);
1662: }
1.153 christos 1663: (void)printf("\n");
1.51 pk 1664: }
1.189 mrg 1665: if (wide) {
1666: snprintf(in_use, sizeof in_use, "%7"PRId64, pool_totals.pt_nout);
1667: snprintf(avail, sizeof avail, "%6"PRId64, pool_totals.pt_nitems);
1668: } else {
1669: in_use[0] = '\0';
1670: avail[0] = '\0';
1671: }
1672: (void)printf(
1673: "%-*s%*s%*"PRId64"%5"PRId64"%*"PRId64"%s%s%*"PRId64"%*"PRId64"%6"PRId64"\n",
1674: wide ? 16 : 11, "Totals",
1675: wide ? 6 : 5, "",
1676: wide ? 12 : 9, pool_totals.pt_nget,
1677: pool_totals.pt_nfail,
1678: wide ? 12 : 9, pool_totals.pt_nput,
1679: in_use,
1680: avail,
1681: wide ? 7 : 6, pool_totals.pt_npagealloc,
1682: wide ? 7 : 6, pool_totals.pt_npagefree,
1683: pool_totals.pt_npages);
1.51 pk 1684:
1.152 christos 1685: inuse /= KILO;
1686: total /= KILO;
1.153 christos 1687: (void)printf(
1688: "\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n",
1.126 simonb 1689: inuse, total, (100.0 * inuse) / total);
1.1 cgd 1690: }
1.96 enami 1691:
1.200 joerg 1692: static void
1693: dopoolcache_sysctl(int verbose)
1694: {
1695: struct pool_sysctl *data, *pp;
1696: size_t i, len;
1697: bool first = true;
1698: int ovflw;
1699: uint64_t tot;
1.208 christos 1700: double p;
1.200 joerg 1701:
1702: data = asysctlbyname("kern.pool", &len);
1703: if (data == NULL)
1704: err(1, "failed to reead kern.pool");
1705: len /= sizeof(*data);
1706:
1707: for (i = 0; i < len; ++i) {
1708: pp = &data[i];
1709: if (pp->pr_cache_meta_size == 0)
1710: continue;
1711:
1712: if (pp->pr_cache_nmiss_global == 0 && !verbose)
1713: continue;
1714:
1715: if (first) {
1716: (void)printf("Pool cache statistics.\n");
1717: (void)printf("%-*s%*s%*s%*s%*s%*s%*s%*s%*s%*s\n",
1718: 12, "Name",
1719: 6, "Spin",
1720: 6, "GrpSz",
1721: 5, "Full",
1722: 5, "Emty",
1723: 10, "PoolLayer",
1724: 11, "CacheLayer",
1725: 6, "Hit%",
1726: 12, "CpuLayer",
1727: 6, "Hit%"
1728: );
1729: first = false;
1730: }
1731:
1732: ovflw = 0;
1733: PRWORD(ovflw, "%-*s", MIN((int)sizeof(pp->pr_wchan), 13), 1,
1734: pp->pr_wchan);
1735: PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_cache_ncontended);
1736: PRWORD(ovflw, " %*" PRIu64, 6, 1, pp->pr_cache_meta_size);
1737: PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_cache_nfull);
1738: PRWORD(ovflw, " %*" PRIu64, 5, 1, pp->pr_cache_nempty);
1739: PRWORD(ovflw, " %*" PRIu64, 10, 1, pp->pr_cache_nmiss_global);
1740:
1741: tot = pp->pr_cache_nhit_global + pp->pr_cache_nmiss_global;
1742: p = pp->pr_cache_nhit_global * 100.0 / tot;
1743: PRWORD(ovflw, " %*" PRIu64, 11, 1, tot);
1744: PRWORD(ovflw, " %*.1f", 6, 1, p);
1745:
1746: tot = pp->pr_cache_nhit_pcpu + pp->pr_cache_nmiss_pcpu;
1747: p = pp->pr_cache_nhit_pcpu * 100.0 / tot;
1748: PRWORD(ovflw, " %*" PRIu64, 12, 1, tot);
1749: PRWORD(ovflw, " %*.1f", 6, 1, p);
1750: printf("\n");
1751: }
1752: }
1753:
1.96 enami 1754: void
1.182 yamt 1755: dopoolcache(int verbose)
1.96 enami 1756: {
1757: struct pool_cache pool_cache, *pc = &pool_cache;
1.154 ad 1758: pool_cache_cpu_t cache_cpu, *cc = &cache_cpu;
1.157 ad 1759: TAILQ_HEAD(,pool) pool_head;
1.154 ad 1760: struct pool pool, *pp = &pool;
1761: char name[32];
1762: uint64_t cpuhit, cpumiss, tot;
1763: void *addr;
1.165 lukem 1764: int first, ovflw;
1765: size_t i;
1.154 ad 1766: double p;
1.96 enami 1767:
1.200 joerg 1768: if (memf == NULL)
1769: return dopoolcache_sysctl(verbose);
1770:
1.154 ad 1771: kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head));
1.157 ad 1772: addr = TAILQ_FIRST(&pool_head);
1.96 enami 1773:
1.157 ad 1774: for (first = 1; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist) ) {
1.154 ad 1775: deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed");
1776: if (pp->pr_cache == NULL)
1.96 enami 1777: continue;
1.154 ad 1778: deref_kptr(pp->pr_wchan, name, sizeof(name),
1779: "pool wait channel trashed");
1780: deref_kptr(pp->pr_cache, pc, sizeof(*pc), "pool cache trashed");
1.182 yamt 1781: if (pc->pc_misses == 0 && !verbose)
1782: continue;
1.154 ad 1783: name[sizeof(name)-1] = '\0';
1784:
1785: cpuhit = 0;
1786: cpumiss = 0;
1.184 jym 1787: for (i = 0; i < __arraycount(pc->pc_cpus); i++) {
1.154 ad 1788: if ((addr = pc->pc_cpus[i]) == NULL)
1789: continue;
1790: deref_kptr(addr, cc, sizeof(*cc),
1791: "pool cache cpu trashed");
1792: cpuhit += cc->cc_hits;
1793: cpumiss += cc->cc_misses;
1.137 chs 1794: }
1.154 ad 1795:
1796: if (first) {
1797: (void)printf("Pool cache statistics.\n");
1.156 ad 1798: (void)printf("%-*s%*s%*s%*s%*s%*s%*s%*s%*s%*s\n",
1.154 ad 1799: 12, "Name",
1800: 6, "Spin",
1.156 ad 1801: 6, "GrpSz",
1802: 5, "Full",
1803: 5, "Emty",
1804: 10, "PoolLayer",
1805: 11, "CacheLayer",
1.154 ad 1806: 6, "Hit%",
1807: 12, "CpuLayer",
1808: 6, "Hit%"
1809: );
1810: first = 0;
1.96 enami 1811: }
1.154 ad 1812:
1813: ovflw = 0;
1814: PRWORD(ovflw, "%-*s", 13, 1, name);
1815: PRWORD(ovflw, " %*llu", 6, 1, (long long)pc->pc_contended);
1.156 ad 1816: PRWORD(ovflw, " %*u", 6, 1, pc->pc_pcgsize);
1817: PRWORD(ovflw, " %*u", 5, 1, pc->pc_nfull);
1818: PRWORD(ovflw, " %*u", 5, 1, pc->pc_nempty);
1819: PRWORD(ovflw, " %*llu", 10, 1, (long long)pc->pc_misses);
1.154 ad 1820:
1821: tot = pc->pc_hits + pc->pc_misses;
1822: p = pc->pc_hits * 100.0 / (tot);
1.156 ad 1823: PRWORD(ovflw, " %*llu", 11, 1, (long long)tot);
1.154 ad 1824: PRWORD(ovflw, " %*.1f", 6, 1, p);
1825:
1826: tot = cpuhit + cpumiss;
1827: p = cpuhit * 100.0 / (tot);
1828: PRWORD(ovflw, " %*llu", 12, 1, (long long)tot);
1829: PRWORD(ovflw, " %*.1f", 6, 1, p);
1830: printf("\n");
1.96 enami 1831: }
1832: }
1.90 lukem 1833:
1.87 lukem 1834: enum hashtype { /* from <sys/systm.h> */
1835: HASH_LIST,
1836: HASH_TAILQ
1837: };
1838:
1839: struct uidinfo { /* XXX: no kernel header file */
1840: LIST_ENTRY(uidinfo) ui_hash;
1841: uid_t ui_uid;
1842: long ui_proccnt;
1843: };
1844:
1845: struct kernel_hash {
1.90 lukem 1846: const char * description; /* description */
1847: int hashsize; /* nlist index for hash size */
1848: int hashtbl; /* nlist index for hash table */
1849: enum hashtype type; /* type of hash table */
1.101 sommerfe 1850: size_t offset; /* offset of {LIST,TAILQ}_NEXT */
1.87 lukem 1851: } khashes[] =
1852: {
1853: {
1.90 lukem 1854: "buffer hash",
1855: X_BUFHASH, X_BUFHASHTBL,
1856: HASH_LIST, offsetof(struct buf, b_hash)
1857: }, {
1858: "ipv4 address -> interface hash",
1.87 lukem 1859: X_IFADDRHASH, X_IFADDRHASHTBL,
1860: HASH_LIST, offsetof(struct in_ifaddr, ia_hash),
1.90 lukem 1861: }, {
1862: "name cache hash",
1.89 lukem 1863: X_NCHASH, X_NCHASHTBL,
1864: HASH_LIST, offsetof(struct namecache, nc_hash),
1.90 lukem 1865: }, {
1866: "name cache directory hash",
1.89 lukem 1867: X_NCVHASH, X_NCVHASHTBL,
1868: HASH_LIST, offsetof(struct namecache, nc_vhash),
1.90 lukem 1869: }, {
1870: "user info (uid -> used processes) hash",
1871: X_UIHASH, X_UIHASHTBL,
1872: HASH_LIST, offsetof(struct uidinfo, ui_hash),
1873: }, {
1874: NULL, -1, -1, 0, 0,
1.87 lukem 1875: }
1876: };
1877:
1878: void
1.88 lukem 1879: dohashstat(int verbose, int todo, const char *hashname)
1.101 sommerfe 1880: {
1.87 lukem 1881: LIST_HEAD(, generic) *hashtbl_list;
1882: TAILQ_HEAD(, generic) *hashtbl_tailq;
1883: struct kernel_hash *curhash;
1.118 itojun 1884: void *hashaddr, *hashbuf, *nhashbuf, *nextaddr;
1.87 lukem 1885: size_t elemsize, hashbufsize, thissize;
1.165 lukem 1886: u_long hashsize, i;
1887: int used, items, chain, maxchain;
1.87 lukem 1888:
1889: hashbuf = NULL;
1890: hashbufsize = 0;
1.88 lukem 1891:
1892: if (todo & HASHLIST) {
1.153 christos 1893: (void)printf("Supported hashes:\n");
1.90 lukem 1894: for (curhash = khashes; curhash->description; curhash++) {
1.101 sommerfe 1895: if (hashnl[curhash->hashsize].n_value == 0 ||
1.90 lukem 1896: hashnl[curhash->hashtbl].n_value == 0)
1897: continue;
1.153 christos 1898: (void)printf("\t%-16s%s\n",
1.90 lukem 1899: hashnl[curhash->hashsize].n_name + 1,
1900: curhash->description);
1.88 lukem 1901: }
1902: return;
1903: }
1904:
1905: if (hashname != NULL) {
1.90 lukem 1906: for (curhash = khashes; curhash->description; curhash++) {
1907: if (strcmp(hashnl[curhash->hashsize].n_name + 1,
1908: hashname) == 0 &&
1.101 sommerfe 1909: hashnl[curhash->hashsize].n_value != 0 &&
1.90 lukem 1910: hashnl[curhash->hashtbl].n_value != 0)
1.88 lukem 1911: break;
1912: }
1.90 lukem 1913: if (curhash->description == NULL) {
1914: warnx("%s: no such hash", hashname);
1915: return;
1916: }
1.88 lukem 1917: }
1918:
1.153 christos 1919: (void)printf(
1.88 lukem 1920: "%-16s %8s %8s %8s %8s %8s %8s\n"
1921: "%-16s %8s %8s %8s %8s %8s %8s\n",
1922: "", "total", "used", "util", "num", "average", "maximum",
1923: "hash table", "buckets", "buckets", "%", "items", "chain",
1924: "chain");
1.87 lukem 1925:
1.90 lukem 1926: for (curhash = khashes; curhash->description; curhash++) {
1.101 sommerfe 1927: if (hashnl[curhash->hashsize].n_value == 0 ||
1.90 lukem 1928: hashnl[curhash->hashtbl].n_value == 0)
1929: continue;
1.88 lukem 1930: if (hashname != NULL &&
1.90 lukem 1931: strcmp(hashnl[curhash->hashsize].n_name + 1, hashname))
1.88 lukem 1932: continue;
1.87 lukem 1933: elemsize = curhash->type == HASH_LIST ?
1934: sizeof(*hashtbl_list) : sizeof(*hashtbl_tailq);
1.90 lukem 1935: deref_kptr((void *)hashnl[curhash->hashsize].n_value,
1936: &hashsize, sizeof(hashsize),
1937: hashnl[curhash->hashsize].n_name);
1.87 lukem 1938: hashsize++;
1.90 lukem 1939: deref_kptr((void *)hashnl[curhash->hashtbl].n_value,
1940: &hashaddr, sizeof(hashaddr),
1941: hashnl[curhash->hashtbl].n_name);
1.87 lukem 1942: if (verbose)
1.153 christos 1943: (void)printf(
1944: "%s %lu, %s %p, offset %ld, elemsize %llu\n",
1.90 lukem 1945: hashnl[curhash->hashsize].n_name + 1, hashsize,
1946: hashnl[curhash->hashtbl].n_name + 1, hashaddr,
1.101 sommerfe 1947: (long)curhash->offset,
1.91 jmc 1948: (unsigned long long)elemsize);
1.87 lukem 1949: thissize = hashsize * elemsize;
1.144 christos 1950: if (hashbuf == NULL || thissize > hashbufsize) {
1.118 itojun 1951: if ((nhashbuf = realloc(hashbuf, thissize)) == NULL)
1.101 sommerfe 1952: errx(1, "malloc hashbuf %llu",
1.91 jmc 1953: (unsigned long long)hashbufsize);
1.118 itojun 1954: hashbuf = nhashbuf;
1955: hashbufsize = thissize;
1.87 lukem 1956: }
1957: deref_kptr(hashaddr, hashbuf, thissize,
1.90 lukem 1958: hashnl[curhash->hashtbl].n_name);
1.87 lukem 1959: used = 0;
1960: items = maxchain = 0;
1.135 lukem 1961: if (curhash->type == HASH_LIST) {
1.87 lukem 1962: hashtbl_list = hashbuf;
1.135 lukem 1963: hashtbl_tailq = NULL;
1964: } else {
1965: hashtbl_list = NULL;
1.87 lukem 1966: hashtbl_tailq = hashbuf;
1.135 lukem 1967: }
1.87 lukem 1968: for (i = 0; i < hashsize; i++) {
1969: if (curhash->type == HASH_LIST)
1970: nextaddr = LIST_FIRST(&hashtbl_list[i]);
1971: else
1972: nextaddr = TAILQ_FIRST(&hashtbl_tailq[i]);
1973: if (nextaddr == NULL)
1974: continue;
1975: if (verbose)
1.165 lukem 1976: (void)printf("%5lu: %p\n", i, nextaddr);
1.87 lukem 1977: used++;
1978: chain = 0;
1979: do {
1980: chain++;
1981: deref_kptr((char *)nextaddr + curhash->offset,
1982: &nextaddr, sizeof(void *),
1983: "hash chain corrupted");
1984: if (verbose > 1)
1.153 christos 1985: (void)printf("got nextaddr as %p\n",
1.87 lukem 1986: nextaddr);
1987: } while (nextaddr != NULL);
1988: items += chain;
1989: if (verbose && chain > 1)
1.153 christos 1990: (void)printf("\tchain = %d\n", chain);
1.87 lukem 1991: if (chain > maxchain)
1992: maxchain = chain;
1993: }
1.153 christos 1994: (void)printf("%-16s %8ld %8d %8.2f %8d %8.2f %8d\n",
1.90 lukem 1995: hashnl[curhash->hashsize].n_name + 1,
1.87 lukem 1996: hashsize, used, used * 100.0 / hashsize,
1.93 lukem 1997: items, used ? (double)items / used : 0.0, maxchain);
1.87 lukem 1998: }
1999: }
2000:
1.1 cgd 2001: /*
1.147 kardel 2002: * kreadc like kread but returns 1 if sucessful, 0 otherwise
2003: */
2004: int
2005: kreadc(struct nlist *nl, int nlx, void *addr, size_t size)
2006: {
2007: const char *sym;
2008:
2009: sym = nl[nlx].n_name;
2010: if (*sym == '_')
2011: ++sym;
2012: if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0)
2013: return 0;
2014: deref_kptr((void *)nl[nlx].n_value, addr, size, sym);
2015: return 1;
2016: }
2017:
2018: /*
1.90 lukem 2019: * kread reads something from the kernel, given its nlist index in namelist[].
1.1 cgd 2020: */
2021: void
1.133 chs 2022: kread(struct nlist *nl, int nlx, void *addr, size_t size)
1.1 cgd 2023: {
1.50 mycroft 2024: const char *sym;
1.1 cgd 2025:
1.133 chs 2026: sym = nl[nlx].n_name;
1.87 lukem 2027: if (*sym == '_')
2028: ++sym;
1.133 chs 2029: if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0)
1.87 lukem 2030: errx(1, "symbol %s not defined", sym);
1.133 chs 2031: deref_kptr((void *)nl[nlx].n_value, addr, size, sym);
1.87 lukem 2032: }
2033:
2034: /*
1.101 sommerfe 2035: * Dereference the kernel pointer `kptr' and fill in the local copy
1.87 lukem 2036: * pointed to by `ptr'. The storage space must be pre-allocated,
2037: * and the size of the copy passed in `len'.
2038: */
2039: void
2040: deref_kptr(const void *kptr, void *ptr, size_t len, const char *msg)
2041: {
2042:
2043: if (*msg == '_')
2044: msg++;
1.165 lukem 2045: if ((size_t)kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len)
1.87 lukem 2046: errx(1, "kptr %lx: %s: %s", (u_long)kptr, msg, kvm_geterr(kd));
1.1 cgd 2047: }
2048:
1.45 thorpej 2049: /*
1.181 mrg 2050: * Traverse the kernel history buffers, performing the requested action.
1.45 thorpej 2051: *
2052: * Note, we assume that if we're not listing, we're dumping.
2053: */
2054: void
1.73 simonb 2055: hist_traverse(int todo, const char *histname)
1.45 thorpej 2056: {
1.210 pgoyette 2057: struct kern_history_head histhead;
2058: struct kern_history hist, *histkva;
2059: char *name = NULL;
2060: size_t namelen = 0;
2061:
2062: if (histnl[0].n_value == 0) {
2063: warnx("kernel history is not compiled into the kernel.");
2064: return;
2065: }
2066:
2067: deref_kptr((void *)histnl[X_KERN_HISTORIES].n_value, &histhead,
2068: sizeof(histhead), histnl[X_KERN_HISTORIES].n_name);
2069:
2070: if (histhead.lh_first == NULL) {
2071: warnx("No active kernel history logs.");
2072: return;
2073: }
2074:
2075: if (todo & HISTLIST)
2076: (void)printf("Active kernel histories:");
2077:
2078: for (histkva = LIST_FIRST(&histhead); histkva != NULL;
2079: histkva = LIST_NEXT(&hist, list)) {
2080: deref_kptr(histkva, &hist, sizeof(hist), "histkva");
2081: if (name == NULL || hist.namelen > namelen) {
2082: if (name != NULL)
2083: free(name);
2084: namelen = hist.namelen;
2085: if ((name = malloc(namelen + 1)) == NULL)
2086: err(1, "malloc history name");
2087: }
2088:
2089: deref_kptr(hist.name, name, namelen, "history name");
2090: name[namelen] = '\0';
2091: if (todo & HISTLIST)
2092: (void)printf(" %s", name);
2093: else {
2094: /*
2095: * If we're dumping all histories, do it, else
2096: * check to see if this is the one we want.
2097: */
2098: if (histname == NULL || strcmp(histname, name) == 0) {
2099: if (histname == NULL)
2100: (void)printf(
2101: "\nkernel history `%s':\n", name);
2102: hist_dodump(&hist);
2103: }
2104: }
2105: }
2106:
2107: if (todo & HISTLIST)
2108: (void)putchar('\n');
2109:
2110: if (name != NULL)
2111: free(name);
2112: }
2113:
2114: /*
2115: * Actually dump the history buffer at the specified KVA.
2116: */
2117: void
2118: hist_dodump(struct kern_history *histp)
2119: {
2120: struct kern_history_ent *histents, *e;
1.215 pgoyette 2121: struct timeval tv;
1.210 pgoyette 2122: size_t histsize;
2123: char *fmt = NULL, *fn = NULL;
2124: size_t fmtlen = 0, fnlen = 0;
2125: unsigned i;
2126:
2127: histsize = sizeof(struct kern_history_ent) * histp->n;
2128:
2129: if ((histents = malloc(histsize)) == NULL)
2130: err(1, "malloc history entries");
2131:
2132: (void)memset(histents, 0, histsize);
2133:
1.211 pgoyette 2134: (void)printf("%"PRIu32" entries, next is %"PRIu32"\n",
2135: histp->n, histp->f);
2136:
1.210 pgoyette 2137: deref_kptr(histp->e, histents, histsize, "history entries");
2138: i = histp->f;
2139: do {
2140: e = &histents[i];
2141: if (e->fmt != NULL) {
2142: if (fmt == NULL || e->fmtlen > fmtlen) {
2143: if (fmt != NULL)
2144: free(fmt);
2145: fmtlen = e->fmtlen;
2146: if ((fmt = malloc(fmtlen + 1)) == NULL)
2147: err(1, "malloc printf format");
2148: }
2149: if (fn == NULL || e->fnlen > fnlen) {
2150: if (fn != NULL)
2151: free(fn);
2152: fnlen = e->fnlen;
2153: if ((fn = malloc(fnlen + 1)) == NULL)
2154: err(1, "malloc function name");
2155: }
2156:
2157: deref_kptr(e->fmt, fmt, fmtlen, "printf format");
2158: fmt[fmtlen] = '\0';
2159:
2160: deref_kptr(e->fn, fn, fnlen, "function name");
2161: fn[fnlen] = '\0';
2162:
1.215 pgoyette 2163: bintime2timeval(&e->bt, &tv);
2164: (void)printf("%06ld.%06ld ", (long int)tv.tv_sec,
2165: (long int)tv.tv_usec);
1.216.6.2! snj 2166: (void)printf("%s#%" PRId32 "@%" PRId32 "d: ",
! 2167: fn, e->call, e->cpunum);
1.210 pgoyette 2168: (void)printf(fmt, e->v[0], e->v[1], e->v[2], e->v[3]);
2169: (void)putchar('\n');
2170: }
2171: i = (i + 1) % histp->n;
2172: } while (i != histp->f);
2173:
2174: free(histents);
2175: if (fmt != NULL)
2176: free(fmt);
2177: if (fn != NULL)
2178: free(fn);
2179: }
2180:
2181: void
2182: hist_traverse_sysctl(int todo, const char *histname)
2183: {
1.209 pgoyette 2184: int error;
2185: int mib[4];
2186: unsigned int i;
2187: size_t len, miblen;
2188: struct sysctlnode query, histnode[32];
2189:
2190: /* retrieve names of available histories */
2191: miblen = __arraycount(mib);
2192: error = sysctlnametomib("kern.hist", mib, &miblen);
2193: if (error != 0) {
1.214 pgoyette 2194: if (errno == ENOENT) {
2195: warnx("kernel history is not compiled into the kernel.");
2196: return;
2197: } else
2198: err(EXIT_FAILURE, "nametomib failed");
1.209 pgoyette 2199: }
1.210 pgoyette 2200:
1.209 pgoyette 2201: /* get the list of nodenames below kern.hist */
2202: mib[2] = CTL_QUERY;
2203: memset(&query, 0, sizeof(query));
2204: query.sysctl_flags = SYSCTL_VERSION;
2205: len = sizeof(histnode);
2206: error = sysctl(mib, 3, &histnode[0], &len, &query, sizeof(query));
2207: if (error != 0) {
2208: err(1, "query failed");
2209: return;
2210: }
2211: if (len == 0) {
1.210 pgoyette 2212: warnx("No active kernel history logs.");
2213: return;
2214: }
2215:
1.209 pgoyette 2216: len = len / sizeof(histnode[0]); /* get # of entries returned */
2217:
1.210 pgoyette 2218: if (todo & HISTLIST)
2219: (void)printf("Active kernel histories:");
2220:
1.209 pgoyette 2221: for (i = 0; i < len; i++) {
1.210 pgoyette 2222: if (todo & HISTLIST)
1.209 pgoyette 2223: (void)printf(" %s", histnode[i].sysctl_name);
1.210 pgoyette 2224: else {
2225: /*
2226: * If we're dumping all histories, do it, else
2227: * check to see if this is the one we want.
2228: */
1.209 pgoyette 2229: if (histname == NULL ||
2230: strcmp(histname, histnode[i].sysctl_name) == 0) {
1.210 pgoyette 2231: if (histname == NULL)
2232: (void)printf(
1.209 pgoyette 2233: "\nkernel history `%s':\n",
2234: histnode[i].sysctl_name);
2235: mib[2] = histnode[i].sysctl_num;
2236: mib[3] = CTL_EOL;
1.210 pgoyette 2237: hist_dodump_sysctl(mib, 4);
2238: }
2239: }
2240: }
2241:
2242: if (todo & HISTLIST)
2243: (void)putchar('\n');
1.216.6.2! snj 2244: else if (mib[2] == CTL_QUERY)
! 2245: warnx("history %s not found", histname);
1.210 pgoyette 2246: }
2247:
2248: /*
2249: * Actually dump the history buffer at the specified KVA.
2250: */
2251: void
2252: hist_dodump_sysctl(int mib[], unsigned int miblen)
2253: {
1.209 pgoyette 2254: struct sysctl_history *hist;
1.215 pgoyette 2255: struct timeval tv;
1.209 pgoyette 2256: struct sysctl_history_event *e;
1.210 pgoyette 2257: size_t histsize;
1.209 pgoyette 2258: char *strp;
1.210 pgoyette 2259: unsigned i;
1.45 thorpej 2260: char *fmt = NULL, *fn = NULL;
1.210 pgoyette 2261:
1.209 pgoyette 2262: hist = NULL;
2263: histsize = 0;
1.210 pgoyette 2264: do {
1.209 pgoyette 2265: errno = 0;
2266: if (sysctl(mib, miblen, hist, &histsize, NULL, 0) == 0)
2267: break;
2268: if (errno != ENOMEM)
2269: break;
2270: if ((hist = realloc(hist, histsize)) == NULL)
2271: errx(1, "realloc history buffer");
2272: } while (errno == ENOMEM);
2273: if (errno != 0)
2274: err(1, "sysctl failed");
1.210 pgoyette 2275:
1.216.6.2! snj 2276: /* Make sure we've got matching versions */
! 2277: if (hist->sh_version != KERNHIST_SYSCTL_VERSION ||
! 2278: hist->sh_arglen != sizeof(uintmax_t))
! 2279: errx(1, "Kernel version or argument length mismatch!");
! 2280:
! 2281: strp = (char *)(&hist->sh_events[hist->sh_numentries]);
1.210 pgoyette 2282:
1.209 pgoyette 2283: (void)printf("%"PRIu32" entries, next is %"PRIu32"\n",
1.216.6.2! snj 2284: hist->sh_numentries,
! 2285: hist->sh_nextfree);
1.210 pgoyette 2286:
1.216.6.2! snj 2287: i = hist->sh_nextfree;
1.45 thorpej 2288:
2289: do {
1.209 pgoyette 2290: e = &hist->sh_events[i];
2291: if (e->she_fmtoffset != 0) {
2292: fmt = &strp[e->she_fmtoffset];
2293: fn = &strp[e->she_funcoffset];
1.215 pgoyette 2294: bintime2timeval(&e->she_bintime, &tv);
1.216.6.2! snj 2295: (void)printf("%06ld.%06ld %s#%"PRIu32"@%"PRIu32": ",
1.215 pgoyette 2296: (long int)tv.tv_sec, (long int)tv.tv_usec,
1.213 pgoyette 2297: fn, e->she_callnumber, e->she_cpunum);
1.209 pgoyette 2298: (void)printf(fmt, e->she_values[0], e->she_values[1],
2299: e->she_values[2], e->she_values[3]);
1.210 pgoyette 2300: (void)putchar('\n');
2301: }
1.216.6.2! snj 2302: i = (i + 1) % hist->sh_numentries;
! 2303: } while (i != hist->sh_nextfree);
1.210 pgoyette 2304:
1.209 pgoyette 2305: free(hist);
1.210 pgoyette 2306: }
1.45 thorpej 2307:
1.183 joerg 2308: static void
1.73 simonb 2309: usage(void)
1.1 cgd 2310: {
1.47 mrg 2311:
1.1 cgd 2312: (void)fprintf(stderr,
1.155 yamt 2313: "usage: %s [-CefHiLlmstUvW] [-c count] [-h hashname] [-M core] [-N system]\n"
1.127 wiz 2314: "\t\t[-u histname] [-w wait] [disks]\n", getprogname());
1.1 cgd 2315: exit(1);
2316: }
CVSweb <webmaster@jp.NetBSD.org>