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