1 /* $NetBSD: vmstat.c,v 1.165 2009/01/18 07:20:00 lukem Exp $ */
4 * Copyright (c) 1998, 2000, 2001, 2007 The NetBSD Foundation, Inc.
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.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
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.
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.
35 * Copyright (c) 1980, 1986, 1991, 1993
36 * The Regents of the University of California. All rights reserved.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
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.
46 * 3. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
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
63 #include <sys/cdefs.h>
65 __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1991, 1993\
66 The Regents of the University of California. All rights reserved.");
71 static char sccsid
[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95";
73 __RCSID("$NetBSD: vmstat.c,v 1.165 2009/01/18 07:20:00 lukem Exp $");
79 #include <sys/param.h>
80 #include <sys/mount.h>
84 #include <sys/evcnt.h>
85 #include <sys/ioctl.h>
86 #include <sys/malloc.h>
87 #include <sys/mallocvar.h>
88 #include <sys/namei.h>
91 #include <sys/sched.h>
92 #include <sys/socket.h>
93 #include <sys/sysctl.h>
97 #include <uvm/uvm_extern.h>
98 #include <uvm/uvm_stat.h>
101 #include <netinet/in.h>
102 #include <netinet/in_var.h>
104 #include <ufs/ufs/inode.h>
106 #include <nfs/rpcv2.h>
107 #include <nfs/nfsproto.h>
108 #include <nfs/nfsnode.h>
128 #include "drvstats.h"
133 struct nlist namelist
[] =
136 { .n_name
= "_boottime" },
140 { .n_name
= "_stathz" },
142 { .n_name
= "_nchstats" },
144 { .n_name
= "_kmemstatistics" },
145 #define X_KMEMBUCKETS 5
146 { .n_name
= "_kmembuckets" },
147 #define X_ALLEVENTS 6
148 { .n_name
= "_allevents" },
150 { .n_name
= "_pool_head" },
152 { .n_name
= "_uvmexp" },
153 #define X_TIME_SECOND 9
154 { .n_name
= "_time_second" },
156 { .n_name
= "_time" },
162 * Namelist for pre-evcnt interrupt counters.
164 struct nlist intrnl
[] =
166 #define X_INTRNAMES 0
167 { .n_name
= "_intrnames" },
168 #define X_EINTRNAMES 1
169 { .n_name
= "_eintrnames" },
171 { .n_name
= "_intrcnt" },
173 { .n_name
= "_eintrcnt" },
174 #define X_INTRNL_SIZE 4
180 * Namelist for hash statistics
182 struct nlist hashnl
[] =
185 { .n_name
= "_nfsnodehash" },
186 #define X_NFSNODETBL 1
187 { .n_name
= "_nfsnodehashtbl" },
189 { .n_name
= "_ihash" },
191 { .n_name
= "_ihashtbl" },
193 { .n_name
= "_bufhash" },
194 #define X_BUFHASHTBL 5
195 { .n_name
= "_bufhashtbl" },
197 { .n_name
= "_uihash" },
198 #define X_UIHASHTBL 7
199 { .n_name
= "_uihashtbl" },
200 #define X_IFADDRHASH 8
201 { .n_name
= "_in_ifaddrhash" },
202 #define X_IFADDRHASHTBL 9
203 { .n_name
= "_in_ifaddrhashtbl" },
205 { .n_name
= "_nchash" },
206 #define X_NCHASHTBL 11
207 { .n_name
= "_nchashtbl" },
209 { .n_name
= "_ncvhash" },
210 #define X_NCVHASHTBL 13
211 { .n_name
= "_ncvhashtbl" },
212 #define X_HASHNL_SIZE 14 /* must be last */
217 * Namelist for UVM histories
219 struct nlist histnl
[] =
221 { .n_name
= "_uvm_histories" },
222 #define X_UVM_HISTORIES 0
229 struct uvmexp uvmexp
, ouvmexp
;
236 #define FORKSTAT 1<<0
237 #define INTRSTAT 1<<1
240 #define EVCNTSTAT 1<<4
242 #define HISTLIST 1<<6
243 #define HISTDUMP 1<<7
244 #define HASHSTAT 1<<8
245 #define HASHLIST 1<<9
246 #define VMTOTAL 1<<10
247 #define POOLCACHESTAT 1<<11
250 * Print single word. `ovflow' is number of characters didn't fit
251 * on the last word. `fmt' is a format string to print this word.
252 * It must contain asterisk for field width. `width' is a width
253 * occupied by this word. `fixed' is a number of constant chars in
254 * `fmt'. `val' is a value to be printed using format string `fmt'.
256 #define PRWORD(ovflw, fmt, width, fixed, val) do { \
257 (ovflw) += printf((fmt), \
258 (width) - (fixed) - (ovflw) > 0 ? \
259 (width) - (fixed) - (ovflw) : 0, \
263 } while (/* CONSTCOND */0)
265 void cpustats(int *);
266 void deref_kptr(const void *, void *, size_t, const char *);
267 void drvstats(int *);
268 void doevcnt(int verbose
);
269 void dohashstat(int, int, const char *);
270 void dointr(int verbose
);
272 void dopool(int, int);
273 void dopoolcache(void);
275 void dovmstat(struct timespec
*, int);
276 void print_total_hdr(void);
277 void dovmtotal(struct timespec
*, int);
278 void kread(struct nlist
*, int, void *, size_t);
279 int kreadc(struct nlist
*, int, void *, size_t);
281 long getuptime(void);
283 long pct(long, long);
287 void hist_traverse(int, const char *);
288 void hist_dodump(struct uvm_history
*);
290 int main(int, char **);
291 char **choosedrives(char **);
293 /* Namelist and memory file names. */
296 /* allow old usage [vmstat 1] */
297 #define BACKWARD_COMPATIBILITY
300 main(int argc
, char *argv
[])
302 int c
, todo
, verbose
, wide
;
303 struct timespec interval
;
305 char errbuf
[_POSIX2_LINE_MAX
];
306 gid_t egid
= getegid();
307 const char *histname
, *hashname
;
310 histname
= hashname
= NULL
;
311 (void)setegid(getgid());
312 memf
= nlistf
= NULL
;
313 reps
= todo
= verbose
= wide
= 0;
315 interval
.tv_nsec
= 0;
316 while ((c
= getopt(argc
, argv
, "Cc:efh:HilLM:mN:stu:UvWw:")) != -1) {
322 todo
|= POOLCACHESTAT
;
373 interval
.tv_sec
= atol(optarg
);
387 * Discard setgid privileges. If not the running kernel, we toss
388 * them away totally so that bad guys can't print interesting stuff
389 * from kernel memory, otherwise switch back to kmem for the
390 * duration of the kvm_openfiles() call.
392 if (nlistf
!= NULL
|| memf
!= NULL
)
393 (void)setgid(getgid());
397 kd
= kvm_openfiles(nlistf
, memf
, NULL
, O_RDONLY
, errbuf
);
399 errx(1, "kvm_openfiles: %s", errbuf
);
401 if (nlistf
== NULL
&& memf
== NULL
)
402 (void)setgid(getgid());
404 if ((c
= kvm_nlist(kd
, namelist
)) != 0) {
407 errx(1, "kvm_nlist: %s %s", "namelist", kvm_geterr(kd
));
408 for (i
= 0; i
< sizeof(namelist
) / sizeof(namelist
[0])-1; i
++)
409 if (namelist
[i
].n_type
== 0 &&
410 i
!= X_TIME_SECOND
&&
413 (void)fprintf(stderr
, "vmstat: undefined symbols:");
414 (void)fprintf(stderr
, " %s",
418 (void)fputc('\n', stderr
);
423 (void) kvm_nlist(kd
, intrnl
);
424 if ((c
= kvm_nlist(kd
, hashnl
)) == -1 || c
== X_HASHNL_SIZE
)
425 errx(1, "kvm_nlist: %s %s", "hashnl", kvm_geterr(kd
));
426 if (kvm_nlist(kd
, histnl
) == -1)
427 errx(1, "kvm_nlist: %s %s", "histnl", kvm_geterr(kd
));
430 struct winsize winsize
;
432 (void)drvinit(0);/* Initialize disk stats, no disks selected. */
434 (void)setgid(getgid()); /* don't need privs anymore */
436 argv
= choosedrives(argv
); /* Select disks. */
438 (void)ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &winsize
);
439 if (winsize
.ws_row
> 0)
440 winlines
= winsize
.ws_row
;
444 #ifdef BACKWARD_COMPATIBILITY
446 interval
.tv_sec
= atol(*argv
);
452 if (interval
.tv_sec
) {
460 * Statistics dumping is incompatible with the default
461 * VMSTAT/dovmstat() output. So perform the interval/reps handling
464 if ((todo
& (VMSTAT
|VMTOTAL
)) == 0) {
466 if (todo
& (HISTLIST
|HISTDUMP
)) {
467 if ((todo
& (HISTLIST
|HISTDUMP
)) ==
469 errx(1, "you may list or dump,"
471 hist_traverse(todo
, histname
);
474 if (todo
& FORKSTAT
) {
478 if (todo
& MEMSTAT
) {
480 dopool(verbose
, wide
);
483 if (todo
& POOLCACHESTAT
) {
487 if (todo
& SUMSTAT
) {
491 if (todo
& INTRSTAT
) {
495 if (todo
& EVCNTSTAT
) {
499 if (todo
& (HASHLIST
|HASHSTAT
)) {
500 if ((todo
& (HASHLIST
|HASHSTAT
)) ==
502 errx(1, "you may list or display,"
504 dohashstat(verbose
, todo
, hashname
);
509 if (reps
>= 0 && --reps
<=0)
511 (void)nanosleep(&interval
, NULL
);
514 if ((todo
& (VMSTAT
|VMTOTAL
)) == (VMSTAT
|VMTOTAL
)) {
515 errx(1, "you may not both do vmstat and vmtotal");
518 dovmstat(&interval
, reps
);
520 dovmtotal(&interval
, reps
);
526 choosedrives(char **argv
)
531 * Choose drives to be displayed. Priority goes to (in order) drives
532 * supplied as arguments, default drives. If everything isn't filled
533 * in and there are drives not taken care of, display the first few
536 #define BACKWARD_COMPATIBILITY
537 for (ndrives
= 0; *argv
; ++argv
) {
538 #ifdef BACKWARD_COMPATIBILITY
539 if (isdigit((unsigned char)**argv
))
542 for (i
= 0; i
< ndrive
; i
++) {
543 if (strcmp(dr_name
[i
], *argv
))
550 for (i
= 0; i
< ndrive
&& ndrives
< 2; i
++) {
563 static struct timeval boottime
;
565 time_t uptime
, nowsec
;
567 if (boottime
.tv_sec
== 0)
568 kread(namelist
, X_BOOTTIME
, &boottime
, sizeof(boottime
));
569 if (kreadc(namelist
, X_TIME_SECOND
, &nowsec
, sizeof(nowsec
))) {
571 * XXX this assignment dance can be removed once timeval tv_sec
572 * is SUS mandated time_t
577 kread(namelist
, X_TIME
, &now
, sizeof(now
));
579 uptime
= now
.tv_sec
- boottime
.tv_sec
;
580 if (uptime
<= 0 || uptime
> 60*60*24*365*10)
581 errx(1, "time makes no sense; namelist must be wrong.");
591 (void)printf("procs memory\n");
592 (void)printf("ru dw pw sl");
593 (void)printf(" total-v active-v active-r");
594 (void)printf(" vm-sh avm-sh rm-sh arm-sh free\n");
595 hdrcnt
= winlines
- 2;
599 dovmtotal(struct timespec
*interval
, int reps
)
601 struct vmtotal total
;
605 (void)signal(SIGCONT
, needhdr
);
612 "Unable to get vmtotals from crash dump.\n");
613 (void)memset(&total
, 0, sizeof(total
));
615 size
= sizeof(total
);
618 if (sysctl(mib
, 2, &total
, &size
, NULL
, 0) < 0) {
619 (void)printf("Can't get vmtotals: %s\n",
621 (void)memset(&total
, 0, sizeof(total
));
624 (void)printf("%2d ", total
.t_rq
);
625 (void)printf("%2d ", total
.t_dw
);
626 (void)printf("%2d ", total
.t_pw
);
627 (void)printf("%2d ", total
.t_sl
);
629 (void)printf("%9d ", total
.t_vm
);
630 (void)printf("%9d ", total
.t_avm
);
631 (void)printf("%9d ", total
.t_arm
);
632 (void)printf("%5d ", total
.t_vmshr
);
633 (void)printf("%6d ", total
.t_avmshr
);
634 (void)printf("%5d ", total
.t_rmshr
);
635 (void)printf("%6d ", total
.t_armshr
);
636 (void)printf("%5d", total
.t_free
);
640 (void)fflush(stdout
);
641 if (reps
>= 0 && --reps
<= 0)
644 (void)nanosleep(interval
, NULL
);
649 dovmstat(struct timespec
*interval
, int reps
)
651 struct vmtotal total
;
652 time_t uptime
, halfuptime
;
655 int pagesize
= getpagesize();
658 uptime
= getuptime();
659 halfuptime
= uptime
/ 2;
660 (void)signal(SIGCONT
, needhdr
);
662 if (namelist
[X_STATHZ
].n_type
!= 0 && namelist
[X_STATHZ
].n_value
!= 0)
663 kread(namelist
, X_STATHZ
, &hz
, sizeof(hz
));
665 kread(namelist
, X_HZ
, &hz
, sizeof(hz
));
670 /* Read new disk statistics */
674 kread(namelist
, X_UVMEXP
, &uvmexp
, sizeof(uvmexp
));
677 * XXX Can't do this if we're reading a crash
678 * XXX dump because they're lazily-calculated.
681 "Unable to get vmtotals from crash dump.\n");
682 (void)memset(&total
, 0, sizeof(total
));
684 size
= sizeof(total
);
687 if (sysctl(mib
, 2, &total
, &size
, NULL
, 0) < 0) {
688 (void)printf("Can't get vmtotals: %s\n",
690 (void)memset(&total
, 0, sizeof(total
));
694 PRWORD(ovflw
, " %*d", 2, 1, total
.t_rq
- 1);
695 PRWORD(ovflw
, " %*d", 2, 1, total
.t_dw
+ total
.t_pw
);
696 #define pgtok(a) (long)((a) * ((uint32_t)pagesize >> 10))
697 #define rate(x) (u_long)(((x) + halfuptime) / uptime) /* round */
698 PRWORD(ovflw
, " %*ld", 9, 1, pgtok(total
.t_avm
));
699 PRWORD(ovflw
, " %*ld", 7, 1, pgtok(total
.t_free
));
700 PRWORD(ovflw
, " %*ld", 5, 1,
701 rate(uvmexp
.faults
- ouvmexp
.faults
));
702 PRWORD(ovflw
, " %*ld", 4, 1,
703 rate(uvmexp
.pdreact
- ouvmexp
.pdreact
));
704 PRWORD(ovflw
, " %*ld", 4, 1,
705 rate(uvmexp
.pageins
- ouvmexp
.pageins
));
706 PRWORD(ovflw
, " %*ld", 5, 1,
707 rate(uvmexp
.pgswapout
- ouvmexp
.pgswapout
));
708 PRWORD(ovflw
, " %*ld", 5, 1,
709 rate(uvmexp
.pdfreed
- ouvmexp
.pdfreed
));
710 PRWORD(ovflw
, " %*ld", 6, 2,
711 rate(uvmexp
.pdscans
- ouvmexp
.pdscans
));
713 PRWORD(ovflw
, " %*ld", 5, 1,
714 rate(uvmexp
.intrs
- ouvmexp
.intrs
));
715 PRWORD(ovflw
, " %*ld", 5, 1,
716 rate(uvmexp
.syscalls
- ouvmexp
.syscalls
));
717 PRWORD(ovflw
, " %*ld", 4, 1,
718 rate(uvmexp
.swtch
- ouvmexp
.swtch
));
721 (void)fflush(stdout
);
722 if (reps
>= 0 && --reps
<= 0)
725 uptime
= interval
->tv_sec
;
727 * We round upward to avoid losing low-frequency events
728 * (i.e., >= 1 per interval but < 1 per second).
730 halfuptime
= uptime
== 1 ? 0 : (uptime
+ 1) / 2;
731 (void)nanosleep(interval
, NULL
);
740 (void)printf(" procs memory page%*s", 23, "");
742 (void)printf("%s %*sfaults cpu\n",
743 ((ndrives
> 1) ? "disks" : "disk"),
744 ((ndrives
> 1) ? ndrives
* 3 - 4 : 0), "");
746 (void)printf("%*s faults cpu\n",
749 (void)printf(" r b avm fre flt re pi po fr sr ");
750 for (i
= 0; i
< ndrive
; i
++)
752 (void)printf("%c%c ", dr_name
[i
][0],
753 dr_name
[i
][strlen(dr_name
[i
]) - 1]);
754 (void)printf(" in sy cs us sy id\n");
755 hdrcnt
= winlines
- 2;
759 * Force a header to be prepended to the next output.
770 pct(long top
, long bot
)
776 ans
= (long)((quad_t
)top
* 100 / bot
);
780 #define PCT(top, bot) (int)pct((long)(top), (long)(bot))
785 struct nchstats nchstats
;
788 struct uvmexp_sysctl uvmexp2
;
793 * The "active" and "inactive" variables
794 * are now estimated by the kernel and sadly
795 * can not easily be dug out of a crash dump.
797 ssize
= sizeof(uvmexp2
);
798 memset(&uvmexp2
, 0, ssize
);
799 active_kernel
= (memf
== NULL
);
801 /* only on active kernel */
804 if (sysctl(mib
, 2, &uvmexp2
, &ssize
, NULL
, 0) < 0)
805 fprintf(stderr
, "%s: sysctl vm.uvmexp2 failed: %s",
806 getprogname(), strerror(errno
));
809 kread(namelist
, X_UVMEXP
, &uvmexp
, sizeof(uvmexp
));
811 (void)printf("%9u bytes per page\n", uvmexp
.pagesize
);
813 (void)printf("%9u page color%s\n",
814 uvmexp
.ncolors
, uvmexp
.ncolors
== 1 ? "" : "s");
816 (void)printf("%9u pages managed\n", uvmexp
.npages
);
817 (void)printf("%9u pages free\n", uvmexp
.free
);
819 (void)printf("%9" PRIu64
" pages active\n", uvmexp2
.active
);
820 (void)printf("%9" PRIu64
" pages inactive\n", uvmexp2
.inactive
);
822 (void)printf("%9u pages paging\n", uvmexp
.paging
);
823 (void)printf("%9u pages wired\n", uvmexp
.wired
);
824 (void)printf("%9u zero pages\n", uvmexp
.zeropages
);
825 (void)printf("%9u reserve pagedaemon pages\n",
826 uvmexp
.reserve_pagedaemon
);
827 (void)printf("%9u reserve kernel pages\n", uvmexp
.reserve_kernel
);
828 (void)printf("%9u anonymous pages\n", uvmexp
.anonpages
);
829 (void)printf("%9u cached file pages\n", uvmexp
.filepages
);
830 (void)printf("%9u cached executable pages\n", uvmexp
.execpages
);
832 (void)printf("%9u minimum free pages\n", uvmexp
.freemin
);
833 (void)printf("%9u target free pages\n", uvmexp
.freetarg
);
834 (void)printf("%9u maximum wired pages\n", uvmexp
.wiredmax
);
836 (void)printf("%9u swap devices\n", uvmexp
.nswapdev
);
837 (void)printf("%9u swap pages\n", uvmexp
.swpages
);
838 (void)printf("%9u swap pages in use\n", uvmexp
.swpginuse
);
839 (void)printf("%9u swap allocations\n", uvmexp
.nswget
);
841 (void)printf("%9u total faults taken\n", uvmexp
.faults
);
842 (void)printf("%9u traps\n", uvmexp
.traps
);
843 (void)printf("%9u device interrupts\n", uvmexp
.intrs
);
844 (void)printf("%9u CPU context switches\n", uvmexp
.swtch
);
845 (void)printf("%9u software interrupts\n", uvmexp
.softs
);
846 (void)printf("%9u system calls\n", uvmexp
.syscalls
);
847 (void)printf("%9u pagein requests\n", uvmexp
.pageins
);
848 (void)printf("%9u pageout requests\n", uvmexp
.pdpageouts
);
849 (void)printf("%9u pages swapped in\n", uvmexp
.pgswapin
);
850 (void)printf("%9u pages swapped out\n", uvmexp
.pgswapout
);
851 (void)printf("%9u forks total\n", uvmexp
.forks
);
852 (void)printf("%9u forks blocked parent\n", uvmexp
.forks_ppwait
);
853 (void)printf("%9u forks shared address space with parent\n",
854 uvmexp
.forks_sharevm
);
855 (void)printf("%9u pagealloc zero wanted and avail\n",
857 (void)printf("%9u pagealloc zero wanted and not avail\n",
858 uvmexp
.pga_zeromiss
);
859 (void)printf("%9u aborts of idle page zeroing\n",
861 (void)printf("%9u pagealloc desired color avail\n",
863 (void)printf("%9u pagealloc desired color not avail\n",
865 (void)printf("%9u pagealloc local cpu avail\n",
867 (void)printf("%9u pagealloc local cpu not avail\n",
870 (void)printf("%9u faults with no memory\n", uvmexp
.fltnoram
);
871 (void)printf("%9u faults with no anons\n", uvmexp
.fltnoanon
);
872 (void)printf("%9u faults had to wait on pages\n", uvmexp
.fltpgwait
);
873 (void)printf("%9u faults found released page\n", uvmexp
.fltpgrele
);
874 (void)printf("%9u faults relock (%u ok)\n", uvmexp
.fltrelck
,
876 (void)printf("%9u anon page faults\n", uvmexp
.fltanget
);
877 (void)printf("%9u anon retry faults\n", uvmexp
.fltanretry
);
878 (void)printf("%9u amap copy faults\n", uvmexp
.fltamcopy
);
879 (void)printf("%9u neighbour anon page faults\n", uvmexp
.fltnamap
);
880 (void)printf("%9u neighbour object page faults\n", uvmexp
.fltnomap
);
881 (void)printf("%9u locked pager get faults\n", uvmexp
.fltlget
);
882 (void)printf("%9u unlocked pager get faults\n", uvmexp
.fltget
);
883 (void)printf("%9u anon faults\n", uvmexp
.flt_anon
);
884 (void)printf("%9u anon copy on write faults\n", uvmexp
.flt_acow
);
885 (void)printf("%9u object faults\n", uvmexp
.flt_obj
);
886 (void)printf("%9u promote copy faults\n", uvmexp
.flt_prcopy
);
887 (void)printf("%9u promote zero fill faults\n", uvmexp
.flt_przero
);
889 (void)printf("%9u times daemon wokeup\n",uvmexp
.pdwoke
);
890 (void)printf("%9u revolutions of the clock hand\n", uvmexp
.pdrevs
);
891 (void)printf("%9u pages freed by daemon\n", uvmexp
.pdfreed
);
892 (void)printf("%9u pages scanned by daemon\n", uvmexp
.pdscans
);
893 (void)printf("%9u anonymous pages scanned by daemon\n",
895 (void)printf("%9u object pages scanned by daemon\n", uvmexp
.pdobscan
);
896 (void)printf("%9u pages reactivated\n", uvmexp
.pdreact
);
897 (void)printf("%9u pages found busy by daemon\n", uvmexp
.pdbusy
);
898 (void)printf("%9u total pending pageouts\n", uvmexp
.pdpending
);
899 (void)printf("%9u pages deactivated\n", uvmexp
.pddeact
);
901 kread(namelist
, X_NCHSTATS
, &nchstats
, sizeof(nchstats
));
902 nchtotal
= nchstats
.ncs_goodhits
+ nchstats
.ncs_neghits
+
903 nchstats
.ncs_badhits
+ nchstats
.ncs_falsehits
+
904 nchstats
.ncs_miss
+ nchstats
.ncs_long
;
905 (void)printf("%9lu total name lookups\n", nchtotal
);
906 (void)printf("%9lu good hits\n", nchstats
.ncs_goodhits
);
907 (void)printf("%9lu negative hits\n", nchstats
.ncs_neghits
);
908 (void)printf("%9lu bad hits\n", nchstats
.ncs_badhits
);
909 (void)printf("%9lu false hits\n", nchstats
.ncs_falsehits
);
910 (void)printf("%9lu miss\n", nchstats
.ncs_miss
);
911 (void)printf("%9lu too long\n", nchstats
.ncs_long
);
912 (void)printf("%9lu pass2 hits\n", nchstats
.ncs_pass2
);
913 (void)printf("%9lu 2passes\n", nchstats
.ncs_2passes
);
915 "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
916 "", PCT(nchstats
.ncs_goodhits
, nchtotal
),
917 PCT(nchstats
.ncs_neghits
, nchtotal
),
918 PCT(nchstats
.ncs_pass2
, nchtotal
));
919 (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
920 PCT(nchstats
.ncs_badhits
, nchtotal
),
921 PCT(nchstats
.ncs_falsehits
, nchtotal
),
922 PCT(nchstats
.ncs_long
, nchtotal
));
929 kread(namelist
, X_UVMEXP
, &uvmexp
, sizeof(uvmexp
));
931 (void)printf("%u forks total\n", uvmexp
.forks
);
932 (void)printf("%u forks blocked parent\n", uvmexp
.forks_ppwait
);
933 (void)printf("%u forks shared address space with parent\n",
934 uvmexp
.forks_sharevm
);
938 drvstats(int *ovflwp
)
944 /* Calculate disk stat deltas. */
948 etime
= cur
.cp_etime
;
950 for (dn
= 0; dn
< ndrive
; ++dn
) {
953 PRWORD(ovflw
, " %*.0f", 3, 1,
954 (cur
.rxfer
[dn
] + cur
.wxfer
[dn
]) / etime
);
960 cpustats(int *ovflwp
)
964 double stat_us
, stat_sy
, stat_id
;
968 for (state
= 0; state
< CPUSTATES
; ++state
)
969 total
+= cur
.cp_time
[state
];
974 stat_us
= (cur
.cp_time
[CP_USER
] + cur
.cp_time
[CP_NICE
]) * pcnt
;
975 stat_sy
= (cur
.cp_time
[CP_SYS
] + cur
.cp_time
[CP_INTR
]) * pcnt
;
976 stat_id
= cur
.cp_time
[CP_IDLE
] * pcnt
;
977 PRWORD(ovflw
, " %*.0f", ((stat_sy
>= 100) ? 2 : 3), 1, stat_us
);
978 PRWORD(ovflw
, " %*.0f", ((stat_us
>= 100 || stat_id
>= 100) ? 2 : 3), 1,
980 PRWORD(ovflw
, " %*.0f", 3, 1, stat_id
);
987 unsigned long *intrcnt
, *ointrcnt
;
988 unsigned long long inttotal
, uptime
;
990 char *intrname
, *ointrname
;
991 struct evcntlist allevents
;
992 struct evcnt evcnt
, *evptr
;
993 char evgroup
[EVCNT_STRING_MAX
], evname
[EVCNT_STRING_MAX
];
996 uptime
= getuptime();
997 (void)printf("%-34s %16s %8s\n", "interrupt", "total", "rate");
998 nintr
= intrnl
[X_EINTRCNT
].n_value
- intrnl
[X_INTRCNT
].n_value
;
999 inamlen
= intrnl
[X_EINTRNAMES
].n_value
- intrnl
[X_INTRNAMES
].n_value
;
1000 if (nintr
!= 0 && inamlen
!= 0) {
1001 ointrcnt
= intrcnt
= malloc((size_t)nintr
);
1002 ointrname
= intrname
= malloc((size_t)inamlen
);
1003 if (intrcnt
== NULL
|| intrname
== NULL
)
1005 kread(intrnl
, X_INTRCNT
, intrcnt
, (size_t)nintr
);
1006 kread(intrnl
, X_INTRNAMES
, intrname
, (size_t)inamlen
);
1007 nintr
/= sizeof(long);
1008 while (--nintr
>= 0) {
1009 if (*intrcnt
|| verbose
)
1010 (void)printf("%-34s %16llu %8llu\n", intrname
,
1011 (unsigned long long)*intrcnt
,
1012 (unsigned long long)
1013 (*intrcnt
/ uptime
));
1014 intrname
+= strlen(intrname
) + 1;
1015 inttotal
+= *intrcnt
++;
1021 kread(namelist
, X_ALLEVENTS
, &allevents
, sizeof allevents
);
1022 evptr
= TAILQ_FIRST(&allevents
);
1024 deref_kptr(evptr
, &evcnt
, sizeof(evcnt
), "event chain trashed");
1025 evptr
= TAILQ_NEXT(&evcnt
, ev_list
);
1026 if (evcnt
.ev_type
!= EVCNT_TYPE_INTR
)
1029 if (evcnt
.ev_count
== 0 && !verbose
)
1032 deref_kptr(evcnt
.ev_group
, evgroup
,
1033 (size_t)evcnt
.ev_grouplen
+ 1, "event chain trashed");
1034 deref_kptr(evcnt
.ev_name
, evname
,
1035 (size_t)evcnt
.ev_namelen
+ 1, "event chain trashed");
1037 (void)printf("%s %s%*s %16llu %8llu\n", evgroup
, evname
,
1038 34 - (evcnt
.ev_grouplen
+ 1 + evcnt
.ev_namelen
), "",
1039 (unsigned long long)evcnt
.ev_count
,
1040 (unsigned long long)(evcnt
.ev_count
/ uptime
));
1042 inttotal
+= evcnt
.ev_count
++;
1044 (void)printf("%-34s %16llu %8llu\n", "Total", inttotal
,
1045 (unsigned long long)(inttotal
/ uptime
));
1049 doevcnt(int verbose
)
1051 static const char * evtypes
[] = { "misc", "intr", "trap" };
1052 unsigned long long uptime
;
1053 struct evcntlist allevents
;
1054 struct evcnt evcnt
, *evptr
;
1055 char evgroup
[EVCNT_STRING_MAX
], evname
[EVCNT_STRING_MAX
];
1057 /* XXX should print type! */
1059 uptime
= getuptime();
1060 (void)printf("%-34s %16s %8s %s\n", "event", "total", "rate", "type");
1061 kread(namelist
, X_ALLEVENTS
, &allevents
, sizeof allevents
);
1062 evptr
= TAILQ_FIRST(&allevents
);
1064 deref_kptr(evptr
, &evcnt
, sizeof(evcnt
), "event chain trashed");
1066 evptr
= TAILQ_NEXT(&evcnt
, ev_list
);
1067 if (evcnt
.ev_count
== 0 && !verbose
)
1070 deref_kptr(evcnt
.ev_group
, evgroup
,
1071 (size_t)evcnt
.ev_grouplen
+ 1, "event chain trashed");
1072 deref_kptr(evcnt
.ev_name
, evname
,
1073 (size_t)evcnt
.ev_namelen
+ 1, "event chain trashed");
1075 (void)printf("%s %s%*s %16llu %8llu %s\n", evgroup
, evname
,
1076 34 - (evcnt
.ev_grouplen
+ 1 + evcnt
.ev_namelen
), "",
1077 (unsigned long long)evcnt
.ev_count
,
1078 (unsigned long long)(evcnt
.ev_count
/ uptime
),
1079 (evcnt
.ev_type
< sizeof(evtypes
)/sizeof(evtypes
[0]) ?
1080 evtypes
[evcnt
.ev_type
] : "?"));
1084 static char memname
[64];
1089 struct kmembuckets
*kp
;
1090 struct malloc_type ks
, *ksp
;
1092 int len
, size
, first
;
1093 long totuse
= 0, totfree
= 0, totreq
= 0;
1094 struct kmembuckets buckets
[MINBUCKET
+ 16];
1096 kread(namelist
, X_KMEMBUCKETS
, buckets
, sizeof(buckets
));
1097 for (first
= 1, i
= MINBUCKET
, kp
= &buckets
[i
]; i
< MINBUCKET
+ 16;
1099 if (kp
->kb_calls
== 0)
1102 (void)printf("Memory statistics by bucket size\n");
1104 " Size In Use Free Requests HighWater Couldfree\n");
1108 (void)printf("%8d %8ld %6ld %10ld %7ld %10ld\n", size
,
1109 kp
->kb_total
- kp
->kb_totalfree
,
1110 kp
->kb_totalfree
, kp
->kb_calls
,
1111 kp
->kb_highwat
, kp
->kb_couldfree
);
1112 totfree
+= size
* kp
->kb_totalfree
;
1116 * If kmem statistics are not being gathered by the kernel,
1117 * first will still be 1.
1120 warnx("Kmem statistics are not being gathered by the kernel.");
1124 (void)printf("\nMemory usage type by bucket size\n");
1125 (void)printf(" Size Type(s)\n");
1126 kp
= &buckets
[MINBUCKET
];
1127 for (j
= 1 << MINBUCKET
; j
< 1 << (MINBUCKET
+ 16); j
<<= 1, kp
++) {
1128 if (kp
->kb_calls
== 0)
1132 for (kread(namelist
, X_KMEMSTAT
, &ksp
, sizeof(ksp
));
1133 ksp
!= NULL
; ksp
= ks
.ks_next
) {
1134 deref_kptr(ksp
, &ks
, sizeof(ks
), "malloc type");
1135 if (ks
.ks_calls
== 0)
1137 if ((ks
.ks_size
& j
) == 0)
1139 deref_kptr(ks
.ks_shortdesc
, memname
,
1140 sizeof(memname
), "malloc type name");
1141 len
+= 2 + strlen(memname
);
1143 (void)printf("%8d %s", j
, memname
);
1147 (void)printf("\n\t ");
1148 len
= 10 + strlen(memname
);
1151 (void)printf(" %s", memname
);
1154 (void)putchar('\n');
1158 "\nMemory statistics by type Type Kern\n");
1160 " Type InUse MemUse HighUse Limit Requests Limit Limit Size(s)\n");
1161 for (kread(namelist
, X_KMEMSTAT
, &ksp
, sizeof(ksp
));
1162 ksp
!= NULL
; ksp
= ks
.ks_next
) {
1163 deref_kptr(ksp
, &ks
, sizeof(ks
), "malloc type");
1164 if (ks
.ks_calls
== 0)
1166 deref_kptr(ks
.ks_shortdesc
, memname
,
1167 sizeof(memname
), "malloc type name");
1168 (void)printf("%15s %5ld %6ldK %6ldK %6ldK %10ld %5u %5u",
1170 ks
.ks_inuse
, howmany(ks
.ks_memuse
, KILO
),
1171 howmany(ks
.ks_maxused
, KILO
),
1172 howmany(ks
.ks_limit
, KILO
), ks
.ks_calls
,
1173 ks
.ks_limblocks
, ks
.ks_mapblocks
);
1175 for (j
= 1 << MINBUCKET
; j
< 1 << (MINBUCKET
+ 16); j
<<= 1) {
1176 if ((ks
.ks_size
& j
) == 0)
1179 (void)printf(" %d", j
);
1181 (void)printf(",%d", j
);
1185 totuse
+= ks
.ks_memuse
;
1186 totreq
+= ks
.ks_calls
;
1188 (void)printf("\nMemory totals: In Use Free Requests\n");
1189 (void)printf(" %7ldK %6ldK %8ld\n\n",
1190 howmany(totuse
, KILO
), howmany(totfree
, KILO
), totreq
);
1194 dopool(int verbose
, int wide
)
1198 long total
, inuse
, this_total
, this_inuse
;
1199 TAILQ_HEAD(,pool
) pool_head
;
1200 struct pool pool
, *pp
= &pool
;
1201 struct pool_allocator pa
;
1202 char name
[32], maxp
[32];
1204 kread(namelist
, X_POOLHEAD
, &pool_head
, sizeof(pool_head
));
1205 addr
= TAILQ_FIRST(&pool_head
);
1209 for (first
= 1; addr
!= NULL
; addr
= TAILQ_NEXT(pp
, pr_poollist
) ) {
1210 deref_kptr(addr
, pp
, sizeof(*pp
), "pool chain trashed");
1211 deref_kptr(pp
->pr_alloc
, &pa
, sizeof(pa
),
1212 "pool allocator trashed");
1213 deref_kptr(pp
->pr_wchan
, name
, sizeof(name
),
1214 "pool wait channel trashed");
1215 name
[sizeof(name
)-1] = '\0';
1218 (void)printf("Memory resource pool statistics\n");
1220 "%-*s%*s%*s%5s%*s%s%s%*s%*s%6s%s%6s%6s%6s%5s%s%s\n",
1221 wide
? 16 : 11, "Name",
1222 wide
? 6 : 5, "Size",
1223 wide
? 12 : 9, "Requests",
1225 wide
? 12 : 9, "Releases",
1226 wide
? " InUse" : "",
1227 wide
? " Avail" : "",
1228 wide
? 7 : 6, "Pgreq",
1229 wide
? 7 : 6, "Pgrel",
1231 wide
? " PageSz" : "",
1236 wide
? " Flags" : "",
1237 wide
? " Util" : "");
1240 if (pp
->pr_nget
== 0 && !verbose
)
1242 if (pp
->pr_maxpages
== UINT_MAX
)
1243 (void)snprintf(maxp
, sizeof(maxp
), "inf");
1245 (void)snprintf(maxp
, sizeof(maxp
), "%u",
1248 PRWORD(ovflw
, "%-*s", wide
? 16 : 11, 0, name
);
1249 PRWORD(ovflw
, " %*u", wide
? 6 : 5, 1, pp
->pr_size
);
1250 PRWORD(ovflw
, " %*lu", wide
? 12 : 9, 1, pp
->pr_nget
);
1251 PRWORD(ovflw
, " %*lu", 5, 1, pp
->pr_nfail
);
1252 PRWORD(ovflw
, " %*lu", wide
? 12 : 9, 1, pp
->pr_nput
);
1254 PRWORD(ovflw
, " %*u", 7, 1, pp
->pr_nout
);
1256 PRWORD(ovflw
, " %*u", 6, 1, pp
->pr_nitems
);
1257 PRWORD(ovflw
, " %*lu", wide
? 7 : 6, 1, pp
->pr_npagealloc
);
1258 PRWORD(ovflw
, " %*lu", wide
? 7 : 6, 1, pp
->pr_npagefree
);
1259 PRWORD(ovflw
, " %*u", 6, 1, pp
->pr_npages
);
1261 PRWORD(ovflw
, " %*u", 7, 1, pa
.pa_pagesz
);
1262 PRWORD(ovflw
, " %*u", 6, 1, pp
->pr_hiwat
);
1263 PRWORD(ovflw
, " %*u", 6, 1, pp
->pr_minpages
);
1264 PRWORD(ovflw
, " %*s", 6, 1, maxp
);
1265 PRWORD(ovflw
, " %*lu", 5, 1, pp
->pr_nidle
);
1267 PRWORD(ovflw
, " 0x%0*x", 4, 1,
1268 pp
->pr_flags
| pp
->pr_roflags
);
1270 this_inuse
= pp
->pr_nout
* pp
->pr_size
;
1271 this_total
= pp
->pr_npages
* pa
.pa_pagesz
;
1272 if (pp
->pr_roflags
& PR_RECURSIVE
) {
1274 * Don't count in-use memory, since it's part
1275 * of another pool and will be accounted for
1278 total
+= (this_total
- this_inuse
);
1280 inuse
+= this_inuse
;
1281 total
+= this_total
;
1284 if (this_total
== 0)
1285 (void)printf(" ---");
1287 (void)printf(" %5.1f%%",
1288 (100.0 * this_inuse
) / this_total
);
1296 "\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n",
1297 inuse
, total
, (100.0 * inuse
) / total
);
1303 struct pool_cache pool_cache
, *pc
= &pool_cache
;
1304 pool_cache_cpu_t cache_cpu
, *cc
= &cache_cpu
;
1305 TAILQ_HEAD(,pool
) pool_head
;
1306 struct pool pool
, *pp
= &pool
;
1308 uint64_t cpuhit
, cpumiss
, tot
;
1314 kread(namelist
, X_POOLHEAD
, &pool_head
, sizeof(pool_head
));
1315 addr
= TAILQ_FIRST(&pool_head
);
1317 for (first
= 1; addr
!= NULL
; addr
= TAILQ_NEXT(pp
, pr_poollist
) ) {
1318 deref_kptr(addr
, pp
, sizeof(*pp
), "pool chain trashed");
1319 if (pp
->pr_cache
== NULL
)
1321 deref_kptr(pp
->pr_wchan
, name
, sizeof(name
),
1322 "pool wait channel trashed");
1323 deref_kptr(pp
->pr_cache
, pc
, sizeof(*pc
), "pool cache trashed");
1324 name
[sizeof(name
)-1] = '\0';
1328 for (i
= 0; i
< sizeof(pc
->pc_cpus
) / sizeof(pc
->pc_cpus
[0]);
1330 if ((addr
= pc
->pc_cpus
[i
]) == NULL
)
1332 deref_kptr(addr
, cc
, sizeof(*cc
),
1333 "pool cache cpu trashed");
1334 cpuhit
+= cc
->cc_hits
;
1335 cpumiss
+= cc
->cc_misses
;
1339 (void)printf("Pool cache statistics.\n");
1340 (void)printf("%-*s%*s%*s%*s%*s%*s%*s%*s%*s%*s\n",
1356 PRWORD(ovflw
, "%-*s", 13, 1, name
);
1357 PRWORD(ovflw
, " %*llu", 6, 1, (long long)pc
->pc_contended
);
1358 PRWORD(ovflw
, " %*u", 6, 1, pc
->pc_pcgsize
);
1359 PRWORD(ovflw
, " %*u", 5, 1, pc
->pc_nfull
);
1360 PRWORD(ovflw
, " %*u", 5, 1, pc
->pc_nempty
);
1361 PRWORD(ovflw
, " %*llu", 10, 1, (long long)pc
->pc_misses
);
1363 tot
= pc
->pc_hits
+ pc
->pc_misses
;
1364 p
= pc
->pc_hits
* 100.0 / (tot
);
1365 PRWORD(ovflw
, " %*llu", 11, 1, (long long)tot
);
1366 PRWORD(ovflw
, " %*.1f", 6, 1, p
);
1368 tot
= cpuhit
+ cpumiss
;
1369 p
= cpuhit
* 100.0 / (tot
);
1370 PRWORD(ovflw
, " %*llu", 12, 1, (long long)tot
);
1371 PRWORD(ovflw
, " %*.1f", 6, 1, p
);
1376 enum hashtype
{ /* from <sys/systm.h> */
1381 struct uidinfo
{ /* XXX: no kernel header file */
1382 LIST_ENTRY(uidinfo
) ui_hash
;
1387 struct kernel_hash
{
1388 const char * description
; /* description */
1389 int hashsize
; /* nlist index for hash size */
1390 int hashtbl
; /* nlist index for hash table */
1391 enum hashtype type
; /* type of hash table */
1392 size_t offset
; /* offset of {LIST,TAILQ}_NEXT */
1397 X_BUFHASH
, X_BUFHASHTBL
,
1398 HASH_LIST
, offsetof(struct buf
, b_hash
)
1400 "inode cache (ihash)",
1401 X_IHASH
, X_IHASHTBL
,
1402 HASH_LIST
, offsetof(struct inode
, i_hash
)
1404 "ipv4 address -> interface hash",
1405 X_IFADDRHASH
, X_IFADDRHASHTBL
,
1406 HASH_LIST
, offsetof(struct in_ifaddr
, ia_hash
),
1409 X_NCHASH
, X_NCHASHTBL
,
1410 HASH_LIST
, offsetof(struct namecache
, nc_hash
),
1412 "name cache directory hash",
1413 X_NCVHASH
, X_NCVHASHTBL
,
1414 HASH_LIST
, offsetof(struct namecache
, nc_vhash
),
1416 "user info (uid -> used processes) hash",
1417 X_UIHASH
, X_UIHASHTBL
,
1418 HASH_LIST
, offsetof(struct uidinfo
, ui_hash
),
1425 dohashstat(int verbose
, int todo
, const char *hashname
)
1427 LIST_HEAD(, generic
) *hashtbl_list
;
1428 TAILQ_HEAD(, generic
) *hashtbl_tailq
;
1429 struct kernel_hash
*curhash
;
1430 void *hashaddr
, *hashbuf
, *nhashbuf
, *nextaddr
;
1431 size_t elemsize
, hashbufsize
, thissize
;
1433 int used
, items
, chain
, maxchain
;
1438 if (todo
& HASHLIST
) {
1439 (void)printf("Supported hashes:\n");
1440 for (curhash
= khashes
; curhash
->description
; curhash
++) {
1441 if (hashnl
[curhash
->hashsize
].n_value
== 0 ||
1442 hashnl
[curhash
->hashtbl
].n_value
== 0)
1444 (void)printf("\t%-16s%s\n",
1445 hashnl
[curhash
->hashsize
].n_name
+ 1,
1446 curhash
->description
);
1451 if (hashname
!= NULL
) {
1452 for (curhash
= khashes
; curhash
->description
; curhash
++) {
1453 if (strcmp(hashnl
[curhash
->hashsize
].n_name
+ 1,
1455 hashnl
[curhash
->hashsize
].n_value
!= 0 &&
1456 hashnl
[curhash
->hashtbl
].n_value
!= 0)
1459 if (curhash
->description
== NULL
) {
1460 warnx("%s: no such hash", hashname
);
1466 "%-16s %8s %8s %8s %8s %8s %8s\n"
1467 "%-16s %8s %8s %8s %8s %8s %8s\n",
1468 "", "total", "used", "util", "num", "average", "maximum",
1469 "hash table", "buckets", "buckets", "%", "items", "chain",
1472 for (curhash
= khashes
; curhash
->description
; curhash
++) {
1473 if (hashnl
[curhash
->hashsize
].n_value
== 0 ||
1474 hashnl
[curhash
->hashtbl
].n_value
== 0)
1476 if (hashname
!= NULL
&&
1477 strcmp(hashnl
[curhash
->hashsize
].n_name
+ 1, hashname
))
1479 elemsize
= curhash
->type
== HASH_LIST
?
1480 sizeof(*hashtbl_list
) : sizeof(*hashtbl_tailq
);
1481 deref_kptr((void *)hashnl
[curhash
->hashsize
].n_value
,
1482 &hashsize
, sizeof(hashsize
),
1483 hashnl
[curhash
->hashsize
].n_name
);
1485 deref_kptr((void *)hashnl
[curhash
->hashtbl
].n_value
,
1486 &hashaddr
, sizeof(hashaddr
),
1487 hashnl
[curhash
->hashtbl
].n_name
);
1490 "%s %lu, %s %p, offset %ld, elemsize %llu\n",
1491 hashnl
[curhash
->hashsize
].n_name
+ 1, hashsize
,
1492 hashnl
[curhash
->hashtbl
].n_name
+ 1, hashaddr
,
1493 (long)curhash
->offset
,
1494 (unsigned long long)elemsize
);
1495 thissize
= hashsize
* elemsize
;
1496 if (hashbuf
== NULL
|| thissize
> hashbufsize
) {
1497 if ((nhashbuf
= realloc(hashbuf
, thissize
)) == NULL
)
1498 errx(1, "malloc hashbuf %llu",
1499 (unsigned long long)hashbufsize
);
1501 hashbufsize
= thissize
;
1503 deref_kptr(hashaddr
, hashbuf
, thissize
,
1504 hashnl
[curhash
->hashtbl
].n_name
);
1506 items
= maxchain
= 0;
1507 if (curhash
->type
== HASH_LIST
) {
1508 hashtbl_list
= hashbuf
;
1509 hashtbl_tailq
= NULL
;
1511 hashtbl_list
= NULL
;
1512 hashtbl_tailq
= hashbuf
;
1514 for (i
= 0; i
< hashsize
; i
++) {
1515 if (curhash
->type
== HASH_LIST
)
1516 nextaddr
= LIST_FIRST(&hashtbl_list
[i
]);
1518 nextaddr
= TAILQ_FIRST(&hashtbl_tailq
[i
]);
1519 if (nextaddr
== NULL
)
1522 (void)printf("%5lu: %p\n", i
, nextaddr
);
1527 deref_kptr((char *)nextaddr
+ curhash
->offset
,
1528 &nextaddr
, sizeof(void *),
1529 "hash chain corrupted");
1531 (void)printf("got nextaddr as %p\n",
1533 } while (nextaddr
!= NULL
);
1535 if (verbose
&& chain
> 1)
1536 (void)printf("\tchain = %d\n", chain
);
1537 if (chain
> maxchain
)
1540 (void)printf("%-16s %8ld %8d %8.2f %8d %8.2f %8d\n",
1541 hashnl
[curhash
->hashsize
].n_name
+ 1,
1542 hashsize
, used
, used
* 100.0 / hashsize
,
1543 items
, used
? (double)items
/ used
: 0.0, maxchain
);
1548 * kreadc like kread but returns 1 if sucessful, 0 otherwise
1551 kreadc(struct nlist
*nl
, int nlx
, void *addr
, size_t size
)
1555 sym
= nl
[nlx
].n_name
;
1558 if (nl
[nlx
].n_type
== 0 || nl
[nlx
].n_value
== 0)
1560 deref_kptr((void *)nl
[nlx
].n_value
, addr
, size
, sym
);
1565 * kread reads something from the kernel, given its nlist index in namelist[].
1568 kread(struct nlist
*nl
, int nlx
, void *addr
, size_t size
)
1572 sym
= nl
[nlx
].n_name
;
1575 if (nl
[nlx
].n_type
== 0 || nl
[nlx
].n_value
== 0)
1576 errx(1, "symbol %s not defined", sym
);
1577 deref_kptr((void *)nl
[nlx
].n_value
, addr
, size
, sym
);
1581 * Dereference the kernel pointer `kptr' and fill in the local copy
1582 * pointed to by `ptr'. The storage space must be pre-allocated,
1583 * and the size of the copy passed in `len'.
1586 deref_kptr(const void *kptr
, void *ptr
, size_t len
, const char *msg
)
1591 if ((size_t)kvm_read(kd
, (u_long
)kptr
, (char *)ptr
, len
) != len
)
1592 errx(1, "kptr %lx: %s: %s", (u_long
)kptr
, msg
, kvm_geterr(kd
));
1596 * Traverse the UVM history buffers, performing the requested action.
1598 * Note, we assume that if we're not listing, we're dumping.
1601 hist_traverse(int todo
, const char *histname
)
1603 struct uvm_history_head histhead
;
1604 struct uvm_history hist
, *histkva
;
1608 if (histnl
[0].n_value
== 0) {
1609 warnx("UVM history is not compiled into the kernel.");
1613 deref_kptr((void *)histnl
[X_UVM_HISTORIES
].n_value
, &histhead
,
1614 sizeof(histhead
), histnl
[X_UVM_HISTORIES
].n_name
);
1616 if (histhead
.lh_first
== NULL
) {
1617 warnx("No active UVM history logs.");
1621 if (todo
& HISTLIST
)
1622 (void)printf("Active UVM histories:");
1624 for (histkva
= LIST_FIRST(&histhead
); histkva
!= NULL
;
1625 histkva
= LIST_NEXT(&hist
, list
)) {
1626 deref_kptr(histkva
, &hist
, sizeof(hist
), "histkva");
1627 if (name
== NULL
|| hist
.namelen
> namelen
) {
1630 namelen
= hist
.namelen
;
1631 if ((name
= malloc(namelen
+ 1)) == NULL
)
1632 err(1, "malloc history name");
1635 deref_kptr(hist
.name
, name
, namelen
, "history name");
1636 name
[namelen
] = '\0';
1637 if (todo
& HISTLIST
)
1638 (void)printf(" %s", name
);
1641 * If we're dumping all histories, do it, else
1642 * check to see if this is the one we want.
1644 if (histname
== NULL
|| strcmp(histname
, name
) == 0) {
1645 if (histname
== NULL
)
1647 "\nUVM history `%s':\n", name
);
1653 if (todo
& HISTLIST
)
1654 (void)putchar('\n');
1661 * Actually dump the history buffer at the specified KVA.
1664 hist_dodump(struct uvm_history
*histp
)
1666 struct uvm_history_ent
*histents
, *e
;
1668 char *fmt
= NULL
, *fn
= NULL
;
1669 size_t fmtlen
= 0, fnlen
= 0;
1672 histsize
= sizeof(struct uvm_history_ent
) * histp
->n
;
1674 if ((histents
= malloc(histsize
)) == NULL
)
1675 err(1, "malloc history entries");
1677 (void)memset(histents
, 0, histsize
);
1679 deref_kptr(histp
->e
, histents
, histsize
, "history entries");
1683 if (e
->fmt
!= NULL
) {
1684 if (fmt
== NULL
|| e
->fmtlen
> fmtlen
) {
1688 if ((fmt
= malloc(fmtlen
+ 1)) == NULL
)
1689 err(1, "malloc printf format");
1691 if (fn
== NULL
|| e
->fnlen
> fnlen
) {
1695 if ((fn
= malloc(fnlen
+ 1)) == NULL
)
1696 err(1, "malloc function name");
1699 deref_kptr(e
->fmt
, fmt
, fmtlen
, "printf format");
1702 deref_kptr(e
->fn
, fn
, fnlen
, "function name");
1705 (void)printf("%06ld.%06ld ", (long int)e
->tv
.tv_sec
,
1706 (long int)e
->tv
.tv_usec
);
1707 (void)printf("%s#%ld: ", fn
, e
->call
);
1708 (void)printf(fmt
, e
->v
[0], e
->v
[1], e
->v
[2], e
->v
[3]);
1709 (void)putchar('\n');
1711 i
= (i
+ 1) % histp
->n
;
1712 } while (i
!= histp
->f
);
1725 (void)fprintf(stderr
,
1726 "usage: %s [-CefHiLlmstUvW] [-c count] [-h hashname] [-M core] [-N system]\n"
1727 "\t\t[-u histname] [-w wait] [disks]\n", getprogname());