11590Srgrimes/*
21590Srgrimes * Copyright (c) 1980, 1986, 1991, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
301590Srgrimes#ifndef lint
3128693Scharnierstatic const char copyright[] =
321590Srgrimes"@(#) Copyright (c) 1980, 1986, 1991, 1993\n\
331590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
34123441Sbde#endif /* not lint */
351590Srgrimes
36123441Sbde#if 0
371590Srgrimes#ifndef lint
38123441Sbdestatic char sccsid[] = "@(#)vmstat.c	8.1 (Berkeley) 6/6/93";
39123441Sbde#endif /* not lint */
4028693Scharnier#endif
411590Srgrimes
42123441Sbde#include <sys/cdefs.h>
43123441Sbde__FBSDID("$FreeBSD$");
44123441Sbde
451590Srgrimes#include <sys/param.h>
461590Srgrimes#include <sys/proc.h>
4712811Sbde#include <sys/uio.h>
481590Srgrimes#include <sys/namei.h>
491590Srgrimes#include <sys/malloc.h>
501590Srgrimes#include <sys/signal.h>
511590Srgrimes#include <sys/fcntl.h>
521590Srgrimes#include <sys/ioctl.h>
53111008Sphk#include <sys/resource.h>
541590Srgrimes#include <sys/sysctl.h>
55208389Ssbruno#include <sys/time.h>
5612804Speter#include <sys/vmmeter.h>
57198620Sjhb#include <sys/pcpu.h>
5812811Sbde
5912811Sbde#include <vm/vm_param.h>
6012811Sbde
6128693Scharnier#include <ctype.h>
6287690Smarkm#include <devstat.h>
6328693Scharnier#include <err.h>
6428693Scharnier#include <errno.h>
65228654Sdim#include <inttypes.h>
6628693Scharnier#include <kvm.h>
6728693Scharnier#include <limits.h>
68148413Srwatson#include <memstat.h>
691590Srgrimes#include <nlist.h>
7028693Scharnier#include <paths.h>
711590Srgrimes#include <stdio.h>
721590Srgrimes#include <stdlib.h>
731590Srgrimes#include <string.h>
7430180Sdima#include <sysexits.h>
7528693Scharnier#include <time.h>
7628693Scharnier#include <unistd.h>
77174573Speter#include <libutil.h>
781590Srgrimes
7987690Smarkmstatic char da[] = "da";
8087690Smarkm
8187690Smarkmstatic struct nlist namelist[] = {
82181881Sjhb#define X_SUM		0
831590Srgrimes	{ "_cnt" },
84233298Spluknet#define X_HZ		1
851590Srgrimes	{ "_hz" },
86233298Spluknet#define X_STATHZ	2
871590Srgrimes	{ "_stathz" },
88233298Spluknet#define X_NCHSTATS	3
891590Srgrimes	{ "_nchstats" },
90233298Spluknet#define	X_INTRNAMES	4
911590Srgrimes	{ "_intrnames" },
92233298Spluknet#define	X_SINTRNAMES	5
93224187Sattilio	{ "_sintrnames" },
94233298Spluknet#define	X_INTRCNT	6
951590Srgrimes	{ "_intrcnt" },
96233298Spluknet#define	X_SINTRCNT	7
97224187Sattilio	{ "_sintrcnt" },
9830180Sdima#ifdef notyet
99131300Sgreen#define	X_DEFICIT	XXX
1001590Srgrimes	{ "_deficit" },
101131300Sgreen#define X_REC		XXX
1021590Srgrimes	{ "_rectime" },
103131300Sgreen#define X_PGIN		XXX
1041590Srgrimes	{ "_pgintime" },
105131300Sgreen#define	X_XSTATS	XXX
1061590Srgrimes	{ "_xstats" },
107131300Sgreen#define X_END		XXX
10892653Sjeff#else
109233298Spluknet#define X_END		8
1101590Srgrimes#endif
1111590Srgrimes	{ "" },
1121590Srgrimes};
1131590Srgrimes
114123250Sdesstatic struct statinfo cur, last;
115123250Sdesstatic int num_devices, maxshowdevs;
116123250Sdesstatic long generation;
117123250Sdesstatic struct device_selection *dev_select;
118123250Sdesstatic int num_selected;
119123250Sdesstatic struct devstat_match *matches;
120123250Sdesstatic int num_matches = 0;
121123250Sdesstatic int num_devices_specified, num_selections;
122123250Sdesstatic long select_generation;
123123250Sdesstatic char **specified_devices;
124123250Sdesstatic devstat_select_mode select_mode;
1251590Srgrimes
126123250Sdesstatic struct	vmmeter sum, osum;
1271590Srgrimes
128184645Skeramida#define	VMSTAT_DEFAULT_LINES	20	/* Default number of `winlines'. */
129184645Skeramidavolatile sig_atomic_t wresized;		/* Tty resized, when non-zero. */
130184645Skeramidastatic int winlines = VMSTAT_DEFAULT_LINES; /* Current number of tty rows. */
131184645Skeramida
132123250Sdesstatic int	aflag;
133123250Sdesstatic int	nflag;
134174573Speterstatic int	Pflag;
135174573Speterstatic int	hflag;
1361590Srgrimes
137123250Sdesstatic kvm_t   *kd;
1381590Srgrimes
1391590Srgrimes#define	FORKSTAT	0x01
1401590Srgrimes#define	INTRSTAT	0x02
1411590Srgrimes#define	MEMSTAT		0x04
1421590Srgrimes#define	SUMSTAT		0x08
1431590Srgrimes#define	TIMESTAT	0x10
1441590Srgrimes#define	VMSTAT		0x20
14543962Sdillon#define ZMEMSTAT	0x40
1461590Srgrimes
14792922Simpstatic void	cpustats(void);
148174573Speterstatic void	pcpustats(int, u_long, int);
14992922Simpstatic void	devstats(void);
150122300Sjmgstatic void	doforkst(void);
15192922Simpstatic void	dointr(void);
15292922Simpstatic void	dosum(void);
153123407Sdesstatic void	dovmstat(unsigned int, int);
154148790Srwatsonstatic void	domemstat_malloc(void);
155148630Srwatsonstatic void	domemstat_zone(void);
15692922Simpstatic void	kread(int, void *, size_t);
157131300Sgreenstatic void	kreado(int, void *, size_t, size_t);
158131300Sgreenstatic char    *kgetstr(const char *);
15992922Simpstatic void	needhdr(int);
160184645Skeramidastatic void	needresize(int);
161184645Skeramidastatic void	doresize(void);
162174573Speterstatic void	printhdr(int, u_long);
16392922Simpstatic void	usage(void);
1641590Srgrimes
16592922Simpstatic long	pct(long, long);
16692922Simpstatic long	getuptime(void);
16787690Smarkm
168123250Sdesstatic char   **getdrivedata(char **);
16987690Smarkm
17028693Scharnierint
171123250Sdesmain(int argc, char *argv[])
1721590Srgrimes{
17387690Smarkm	int c, todo;
174123407Sdes	unsigned int interval;
175208389Ssbruno	float f;
1761590Srgrimes	int reps;
1771590Srgrimes	char *memf, *nlistf;
17878474Sschweikh	char errbuf[_POSIX2_LINE_MAX];
1791590Srgrimes
1801590Srgrimes	memf = nlistf = NULL;
1811590Srgrimes	interval = reps = todo = 0;
18243822Sken	maxshowdevs = 2;
183174573Speter	hflag = isatty(1);
184174573Speter	while ((c = getopt(argc, argv, "ac:fhHiM:mN:n:Pp:stw:z")) != -1) {
1851590Srgrimes		switch (c) {
186123250Sdes		case 'a':
187123250Sdes			aflag++;
188123250Sdes			break;
1891590Srgrimes		case 'c':
1901590Srgrimes			reps = atoi(optarg);
1911590Srgrimes			break;
192174573Speter		case 'P':
193174573Speter			Pflag++;
194174573Speter			break;
1951590Srgrimes		case 'f':
196113460Stjr			todo |= FORKSTAT;
1971590Srgrimes			break;
198174573Speter		case 'h':
199174573Speter			hflag = 1;
200174573Speter			break;
201174573Speter		case 'H':
202174573Speter			hflag = 0;
203174573Speter			break;
2041590Srgrimes		case 'i':
2051590Srgrimes			todo |= INTRSTAT;
2061590Srgrimes			break;
2071590Srgrimes		case 'M':
2081590Srgrimes			memf = optarg;
2091590Srgrimes			break;
2101590Srgrimes		case 'm':
2111590Srgrimes			todo |= MEMSTAT;
2121590Srgrimes			break;
2131590Srgrimes		case 'N':
2141590Srgrimes			nlistf = optarg;
2151590Srgrimes			break;
21639230Sgibbs		case 'n':
21739372Sdillon			nflag = 1;
21839230Sgibbs			maxshowdevs = atoi(optarg);
21939230Sgibbs			if (maxshowdevs < 0)
22039230Sgibbs				errx(1, "number of devices %d is < 0",
22139230Sgibbs				     maxshowdevs);
22239230Sgibbs			break;
22339230Sgibbs		case 'p':
224112284Sphk			if (devstat_buildmatch(optarg, &matches, &num_matches) != 0)
22539230Sgibbs				errx(1, "%s", devstat_errbuf);
22639230Sgibbs			break;
2271590Srgrimes		case 's':
2281590Srgrimes			todo |= SUMSTAT;
2291590Srgrimes			break;
2301590Srgrimes		case 't':
23130180Sdima#ifdef notyet
2321590Srgrimes			todo |= TIMESTAT;
23330180Sdima#else
23430180Sdima			errx(EX_USAGE, "sorry, -t is not (re)implemented yet");
23530180Sdima#endif
2361590Srgrimes			break;
2371590Srgrimes		case 'w':
238208389Ssbruno			/* Convert to milliseconds. */
239208389Ssbruno			f = atof(optarg);
240208389Ssbruno			interval = f * 1000;
2411590Srgrimes			break;
24244067Sbde		case 'z':
24344067Sbde			todo |= ZMEMSTAT;
24444067Sbde			break;
2451590Srgrimes		case '?':
2461590Srgrimes		default:
2471590Srgrimes			usage();
2481590Srgrimes		}
2491590Srgrimes	}
2501590Srgrimes	argc -= optind;
2511590Srgrimes	argv += optind;
2521590Srgrimes
2531590Srgrimes	if (todo == 0)
2541590Srgrimes		todo = VMSTAT;
2551590Srgrimes
256123250Sdes	if (memf != NULL) {
257123250Sdes		kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
258123250Sdes		if (kd == NULL)
259123250Sdes			errx(1, "kvm_openfiles: %s", errbuf);
260123250Sdes	}
2611590Srgrimes
262123250Sdes	if (kd != NULL && (c = kvm_nlist(kd, namelist)) != 0) {
2631590Srgrimes		if (c > 0) {
26428693Scharnier			warnx("undefined symbols:");
2651590Srgrimes			for (c = 0;
266123250Sdes			     c < (int)(sizeof(namelist)/sizeof(namelist[0]));
267123250Sdes			     c++)
2681590Srgrimes				if (namelist[c].n_type == 0)
26981537Sken					(void)fprintf(stderr, " %s",
2701590Srgrimes					    namelist[c].n_name);
2711590Srgrimes			(void)fputc('\n', stderr);
2721590Srgrimes		} else
27328693Scharnier			warnx("kvm_nlist: %s", kvm_geterr(kd));
2741590Srgrimes		exit(1);
2751590Srgrimes	}
276174573Speter	if (kd && Pflag)
277174573Speter		errx(1, "Cannot use -P with crash dumps");
2781590Srgrimes
2791590Srgrimes	if (todo & VMSTAT) {
28043819Sken		/*
28143819Sken		 * Make sure that the userland devstat version matches the
28243819Sken		 * kernel devstat version.  If not, exit and print a
28343819Sken		 * message informing the user of his mistake.
28443819Sken		 */
285112284Sphk		if (devstat_checkversion(NULL) < 0)
28643819Sken			errx(1, "%s", devstat_errbuf);
28743819Sken
28843819Sken
2891590Srgrimes		argv = getdrivedata(argv);
2901590Srgrimes	}
2911590Srgrimes
2921590Srgrimes#define	BACKWARD_COMPATIBILITY
2931590Srgrimes#ifdef	BACKWARD_COMPATIBILITY
2941590Srgrimes	if (*argv) {
295208389Ssbruno		f = atof(*argv);
296208389Ssbruno		interval = f * 1000;
2971590Srgrimes		if (*++argv)
2981590Srgrimes			reps = atoi(*argv);
2991590Srgrimes	}
3001590Srgrimes#endif
3011590Srgrimes
3021590Srgrimes	if (interval) {
3031590Srgrimes		if (!reps)
3041590Srgrimes			reps = -1;
3051590Srgrimes	} else if (reps)
306208389Ssbruno		interval = 1 * 1000;
3071590Srgrimes
3081590Srgrimes	if (todo & FORKSTAT)
3091590Srgrimes		doforkst();
3101590Srgrimes	if (todo & MEMSTAT)
311148790Srwatson		domemstat_malloc();
31243962Sdillon	if (todo & ZMEMSTAT)
313148630Srwatson		domemstat_zone();
3141590Srgrimes	if (todo & SUMSTAT)
3151590Srgrimes		dosum();
31630180Sdima#ifdef notyet
3171590Srgrimes	if (todo & TIMESTAT)
3181590Srgrimes		dotimes();
3191590Srgrimes#endif
3201590Srgrimes	if (todo & INTRSTAT)
3211590Srgrimes		dointr();
3221590Srgrimes	if (todo & VMSTAT)
3231590Srgrimes		dovmstat(interval, reps);
3241590Srgrimes	exit(0);
3251590Srgrimes}
3261590Srgrimes
327123250Sdesstatic int
328123250Sdesmysysctl(const char *name, void *oldp, size_t *oldlenp,
329123250Sdes    void *newp, size_t newlen)
3301590Srgrimes{
331123250Sdes	int error;
332123250Sdes
333123250Sdes	error = sysctlbyname(name, oldp, oldlenp, newp, newlen);
334123250Sdes	if (error != 0 && errno != ENOMEM)
335123250Sdes		err(1, "sysctl(%s)", name);
336123250Sdes	return (error);
337123250Sdes}
338123250Sdes
339123250Sdesstatic char **
340123250Sdesgetdrivedata(char **argv)
341123250Sdes{
342112284Sphk	if ((num_devices = devstat_getnumdevs(NULL)) < 0)
34339230Sgibbs		errx(1, "%s", devstat_errbuf);
3441590Srgrimes
345188888Sdelphij	cur.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo));
346188888Sdelphij	last.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo));
34739230Sgibbs
348112284Sphk	if (devstat_getdevs(NULL, &cur) == -1)
34939230Sgibbs		errx(1, "%s", devstat_errbuf);
35039230Sgibbs
35139230Sgibbs	num_devices = cur.dinfo->numdevs;
35239230Sgibbs	generation = cur.dinfo->generation;
35339230Sgibbs
35439230Sgibbs	specified_devices = (char **)malloc(sizeof(char *));
35539230Sgibbs	for (num_devices_specified = 0; *argv; ++argv) {
3561590Srgrimes		if (isdigit(**argv))
3571590Srgrimes			break;
35839230Sgibbs		num_devices_specified++;
35939230Sgibbs		specified_devices = (char **)realloc(specified_devices,
36039230Sgibbs						     sizeof(char *) *
36139230Sgibbs						     num_devices_specified);
36239230Sgibbs		specified_devices[num_devices_specified - 1] = *argv;
3631590Srgrimes	}
36439230Sgibbs	dev_select = NULL;
36539230Sgibbs
36639372Sdillon	if (nflag == 0 && maxshowdevs < num_devices_specified)
36739372Sdillon			maxshowdevs = num_devices_specified;
36839372Sdillon
36939230Sgibbs	/*
37039230Sgibbs	 * People are generally only interested in disk statistics when
37139230Sgibbs	 * they're running vmstat.  So, that's what we're going to give
37239230Sgibbs	 * them if they don't specify anything by default.  We'll also give
37339230Sgibbs	 * them any other random devices in the system so that we get to
37439230Sgibbs	 * maxshowdevs devices, if that many devices exist.  If the user
37539230Sgibbs	 * specifies devices on the command line, either through a pattern
37639230Sgibbs	 * match or by naming them explicitly, we will give the user only
37739230Sgibbs	 * those devices.
37839230Sgibbs	 */
37939230Sgibbs	if ((num_devices_specified == 0) && (num_matches == 0)) {
380112284Sphk		if (devstat_buildmatch(da, &matches, &num_matches) != 0)
38139230Sgibbs			errx(1, "%s", devstat_errbuf);
38239230Sgibbs
38339230Sgibbs		select_mode = DS_SELECT_ADD;
38439230Sgibbs	} else
38539230Sgibbs		select_mode = DS_SELECT_ONLY;
38639230Sgibbs
38739230Sgibbs	/*
38839230Sgibbs	 * At this point, selectdevs will almost surely indicate that the
38939230Sgibbs	 * device list has changed, so we don't look for return values of 0
39039230Sgibbs	 * or 1.  If we get back -1, though, there is an error.
39139230Sgibbs	 */
392112284Sphk	if (devstat_selectdevs(&dev_select, &num_selected, &num_selections,
39339230Sgibbs		       &select_generation, generation, cur.dinfo->devices,
39439230Sgibbs		       num_devices, matches, num_matches, specified_devices,
39539230Sgibbs		       num_devices_specified, select_mode,
39639230Sgibbs		       maxshowdevs, 0) == -1)
39739230Sgibbs		errx(1, "%s", devstat_errbuf);
39839230Sgibbs
3991590Srgrimes	return(argv);
4001590Srgrimes}
4011590Srgrimes
402123250Sdesstatic long
403123250Sdesgetuptime(void)
4041590Srgrimes{
405151417Sandre	struct timespec sp;
4061590Srgrimes
407151417Sandre	(void)clock_gettime(CLOCK_MONOTONIC, &sp);
408151417Sandre
409219708Semaste	return(sp.tv_sec);
4101590Srgrimes}
4111590Srgrimes
412123250Sdesstatic void
413198620Sjhbfill_pcpu(struct pcpu ***pcpup, int* maxcpup)
414198620Sjhb{
415198620Sjhb	struct pcpu **pcpu;
416198620Sjhb
417215569Skevlo	int maxcpu, i;
418198620Sjhb
419198620Sjhb	*pcpup = NULL;
420198620Sjhb
421198620Sjhb	if (kd == NULL)
422198620Sjhb		return;
423198620Sjhb
424198620Sjhb	maxcpu = kvm_getmaxcpu(kd);
425198620Sjhb	if (maxcpu < 0)
426198620Sjhb		errx(1, "kvm_getmaxcpu: %s", kvm_geterr(kd));
427198620Sjhb
428198620Sjhb	pcpu = calloc(maxcpu, sizeof(struct pcpu *));
429198620Sjhb	if (pcpu == NULL)
430198620Sjhb		err(1, "calloc");
431198620Sjhb
432198620Sjhb	for (i = 0; i < maxcpu; i++) {
433198620Sjhb		pcpu[i] = kvm_getpcpu(kd, i);
434198620Sjhb		if (pcpu[i] == (struct pcpu *)-1)
435198620Sjhb			errx(1, "kvm_getpcpu: %s", kvm_geterr(kd));
436198620Sjhb	}
437198620Sjhb
438198620Sjhb	*maxcpup = maxcpu;
439198620Sjhb	*pcpup = pcpu;
440198620Sjhb}
441198620Sjhb
442198620Sjhbstatic void
443198620Sjhbfree_pcpu(struct pcpu **pcpu, int maxcpu)
444198620Sjhb{
445198620Sjhb	int i;
446198620Sjhb
447198620Sjhb	for (i = 0; i < maxcpu; i++)
448198620Sjhb		free(pcpu[i]);
449198620Sjhb	free(pcpu);
450198620Sjhb}
451198620Sjhb
452198620Sjhbstatic void
453123250Sdesfill_vmmeter(struct vmmeter *vmmp)
454123250Sdes{
455198620Sjhb	struct pcpu **pcpu;
456198620Sjhb	int maxcpu, i;
457198620Sjhb
458123250Sdes	if (kd != NULL) {
459123250Sdes		kread(X_SUM, vmmp, sizeof(*vmmp));
460198620Sjhb		fill_pcpu(&pcpu, &maxcpu);
461198620Sjhb		for (i = 0; i < maxcpu; i++) {
462198620Sjhb			if (pcpu[i] == NULL)
463198620Sjhb				continue;
464198620Sjhb#define ADD_FROM_PCPU(i, name) \
465198620Sjhb			vmmp->name += pcpu[i]->pc_cnt.name
466198620Sjhb			ADD_FROM_PCPU(i, v_swtch);
467198620Sjhb			ADD_FROM_PCPU(i, v_trap);
468198620Sjhb			ADD_FROM_PCPU(i, v_syscall);
469198620Sjhb			ADD_FROM_PCPU(i, v_intr);
470198620Sjhb			ADD_FROM_PCPU(i, v_soft);
471198620Sjhb			ADD_FROM_PCPU(i, v_vm_faults);
472246034Szont			ADD_FROM_PCPU(i, v_io_faults);
473198620Sjhb			ADD_FROM_PCPU(i, v_cow_faults);
474198620Sjhb			ADD_FROM_PCPU(i, v_cow_optim);
475198620Sjhb			ADD_FROM_PCPU(i, v_zfod);
476198620Sjhb			ADD_FROM_PCPU(i, v_ozfod);
477198620Sjhb			ADD_FROM_PCPU(i, v_swapin);
478198620Sjhb			ADD_FROM_PCPU(i, v_swapout);
479198620Sjhb			ADD_FROM_PCPU(i, v_swappgsin);
480198620Sjhb			ADD_FROM_PCPU(i, v_swappgsout);
481198620Sjhb			ADD_FROM_PCPU(i, v_vnodein);
482198620Sjhb			ADD_FROM_PCPU(i, v_vnodeout);
483198620Sjhb			ADD_FROM_PCPU(i, v_vnodepgsin);
484198620Sjhb			ADD_FROM_PCPU(i, v_vnodepgsout);
485198620Sjhb			ADD_FROM_PCPU(i, v_intrans);
486198620Sjhb			ADD_FROM_PCPU(i, v_tfree);
487198620Sjhb			ADD_FROM_PCPU(i, v_forks);
488198620Sjhb			ADD_FROM_PCPU(i, v_vforks);
489198620Sjhb			ADD_FROM_PCPU(i, v_rforks);
490198620Sjhb			ADD_FROM_PCPU(i, v_kthreads);
491198620Sjhb			ADD_FROM_PCPU(i, v_forkpages);
492198620Sjhb			ADD_FROM_PCPU(i, v_vforkpages);
493198620Sjhb			ADD_FROM_PCPU(i, v_rforkpages);
494198620Sjhb			ADD_FROM_PCPU(i, v_kthreadpages);
495198620Sjhb#undef ADD_FROM_PCPU
496198620Sjhb		}
497198620Sjhb		free_pcpu(pcpu, maxcpu);
498123250Sdes	} else {
499123250Sdes		size_t size = sizeof(unsigned int);
500123250Sdes#define GET_VM_STATS(cat, name) \
501123250Sdes	mysysctl("vm.stats." #cat "." #name, &vmmp->name, &size, NULL, 0)
502123250Sdes		/* sys */
503123250Sdes		GET_VM_STATS(sys, v_swtch);
504123250Sdes		GET_VM_STATS(sys, v_trap);
505123250Sdes		GET_VM_STATS(sys, v_syscall);
506123250Sdes		GET_VM_STATS(sys, v_intr);
507123250Sdes		GET_VM_STATS(sys, v_soft);
5081590Srgrimes
509123250Sdes		/* vm */
510123414Sdes		GET_VM_STATS(vm, v_vm_faults);
511246034Szont		GET_VM_STATS(vm, v_io_faults);
512123414Sdes		GET_VM_STATS(vm, v_cow_faults);
513123414Sdes		GET_VM_STATS(vm, v_cow_optim);
514123414Sdes		GET_VM_STATS(vm, v_zfod);
515123414Sdes		GET_VM_STATS(vm, v_ozfod);
516123414Sdes		GET_VM_STATS(vm, v_swapin);
517123414Sdes		GET_VM_STATS(vm, v_swapout);
518123414Sdes		GET_VM_STATS(vm, v_swappgsin);
519123414Sdes		GET_VM_STATS(vm, v_swappgsout);
520123414Sdes		GET_VM_STATS(vm, v_vnodein);
521123414Sdes		GET_VM_STATS(vm, v_vnodeout);
522123414Sdes		GET_VM_STATS(vm, v_vnodepgsin);
523123414Sdes		GET_VM_STATS(vm, v_vnodepgsout);
524123414Sdes		GET_VM_STATS(vm, v_intrans);
525123414Sdes		GET_VM_STATS(vm, v_reactivated);
526123414Sdes		GET_VM_STATS(vm, v_pdwakeups);
527123414Sdes		GET_VM_STATS(vm, v_pdpages);
528171633Salc		GET_VM_STATS(vm, v_tcached);
529123414Sdes		GET_VM_STATS(vm, v_dfree);
530123414Sdes		GET_VM_STATS(vm, v_pfree);
531123414Sdes		GET_VM_STATS(vm, v_tfree);
532123414Sdes		GET_VM_STATS(vm, v_page_size);
533123414Sdes		GET_VM_STATS(vm, v_page_count);
534123414Sdes		GET_VM_STATS(vm, v_free_reserved);
535123414Sdes		GET_VM_STATS(vm, v_free_target);
536123414Sdes		GET_VM_STATS(vm, v_free_min);
537123414Sdes		GET_VM_STATS(vm, v_free_count);
538123414Sdes		GET_VM_STATS(vm, v_wire_count);
539123414Sdes		GET_VM_STATS(vm, v_active_count);
540123414Sdes		GET_VM_STATS(vm, v_inactive_target);
541123414Sdes		GET_VM_STATS(vm, v_inactive_count);
542123414Sdes		GET_VM_STATS(vm, v_cache_count);
543123414Sdes		GET_VM_STATS(vm, v_cache_min);
544123414Sdes		GET_VM_STATS(vm, v_cache_max);
545123414Sdes		GET_VM_STATS(vm, v_pageout_free_min);
546123414Sdes		GET_VM_STATS(vm, v_interrupt_free_min);
547123414Sdes		/*GET_VM_STATS(vm, v_free_severe);*/
548123250Sdes		GET_VM_STATS(vm, v_forks);
549123250Sdes		GET_VM_STATS(vm, v_vforks);
550123250Sdes		GET_VM_STATS(vm, v_rforks);
551123250Sdes		GET_VM_STATS(vm, v_kthreads);
552123250Sdes		GET_VM_STATS(vm, v_forkpages);
553123250Sdes		GET_VM_STATS(vm, v_vforkpages);
554123250Sdes		GET_VM_STATS(vm, v_rforkpages);
555123250Sdes		GET_VM_STATS(vm, v_kthreadpages);
556123250Sdes#undef GET_VM_STATS
557123250Sdes	}
558123250Sdes}
559123250Sdes
560123250Sdesstatic void
561123250Sdesfill_vmtotal(struct vmtotal *vmtp)
5621590Srgrimes{
563123250Sdes	if (kd != NULL) {
564123250Sdes		/* XXX fill vmtp */
565123250Sdes		errx(1, "not implemented");
566123250Sdes	} else {
567123250Sdes		size_t size = sizeof(*vmtp);
568123250Sdes		mysysctl("vm.vmtotal", vmtp, &size, NULL, 0);
569123250Sdes		if (size != sizeof(*vmtp))
570123250Sdes			errx(1, "vm.total size mismatch");
571123250Sdes	}
572123250Sdes}
573123250Sdes
574174573Speter/* Determine how many cpu columns, and what index they are in kern.cp_times */
575174573Speterstatic int
576174573Spetergetcpuinfo(u_long *maskp, int *maxidp)
577174573Speter{
578174573Speter	int maxcpu;
579174573Speter	int maxid;
580174573Speter	int ncpus;
581174573Speter	int i, j;
582174573Speter	int empty;
583174573Speter	size_t size;
584174573Speter	long *times;
585174573Speter	u_long mask;
586174573Speter
587174573Speter	if (kd != NULL)
588174573Speter		errx(1, "not implemented");
589174573Speter	mask = 0;
590174573Speter	ncpus = 0;
591174573Speter	size = sizeof(maxcpu);
592174573Speter	mysysctl("kern.smp.maxcpus", &maxcpu, &size, NULL, 0);
593174573Speter	if (size != sizeof(maxcpu))
594174573Speter		errx(1, "sysctl kern.smp.maxcpus");
595174573Speter	size = sizeof(long) * maxcpu * CPUSTATES;
596174573Speter	times = malloc(size);
597174573Speter	if (times == NULL)
598174573Speter		err(1, "malloc %zd bytes", size);
599174573Speter	mysysctl("kern.cp_times", times, &size, NULL, 0);
600174573Speter	maxid = (size / CPUSTATES / sizeof(long)) - 1;
601174573Speter	for (i = 0; i <= maxid; i++) {
602174573Speter		empty = 1;
603174573Speter		for (j = 0; empty && j < CPUSTATES; j++) {
604174573Speter			if (times[i * CPUSTATES + j] != 0)
605174573Speter				empty = 0;
606174573Speter		}
607174573Speter		if (!empty) {
608174573Speter			mask |= (1ul << i);
609174573Speter			ncpus++;
610174573Speter		}
611174573Speter	}
612174573Speter	if (maskp)
613174573Speter		*maskp = mask;
614174573Speter	if (maxidp)
615174573Speter		*maxidp = maxid;
616174573Speter	return (ncpus);
617174573Speter}
618174573Speter
619174573Speter
620174573Speterstatic void
621174573Speterprthuman(u_int64_t val, int size)
622174573Speter{
623174573Speter	char buf[10];
624174573Speter	int flags;
625174573Speter
626174573Speter	if (size < 5 || size > 9)
627174573Speter		errx(1, "doofus");
628174573Speter	flags = HN_B | HN_NOSPACE | HN_DECIMAL;
629174573Speter	humanize_number(buf, size, val, "", HN_AUTOSCALE, flags);
630174573Speter	printf("%*s", size, buf);
631174573Speter}
632174573Speter
633123250Sdesstatic int hz, hdrcnt;
634123250Sdes
635174573Speterstatic long *cur_cp_times;
636174573Speterstatic long *last_cp_times;
637174573Speterstatic size_t size_cp_times;
638174573Speter
639123250Sdesstatic void
640123407Sdesdovmstat(unsigned int interval, int reps)
641123250Sdes{
6421590Srgrimes	struct vmtotal total;
6431590Srgrimes	time_t uptime, halfuptime;
64439230Sgibbs	struct devinfo *tmp_dinfo;
64580551Stmm	size_t size;
646174573Speter	int ncpus, maxid;
647174573Speter	u_long cpumask;
648208389Ssbruno	int rate_adj;
6491590Srgrimes
6501590Srgrimes	uptime = getuptime();
6511590Srgrimes	halfuptime = uptime / 2;
652208389Ssbruno	rate_adj = 1;
653184645Skeramida
654184645Skeramida	/*
655184645Skeramida	 * If the user stops the program (control-Z) and then resumes it,
656184645Skeramida	 * print out the header again.
657184645Skeramida	 */
6581590Srgrimes	(void)signal(SIGCONT, needhdr);
6591590Srgrimes
660184645Skeramida	/*
661184645Skeramida	 * If our standard output is a tty, then install a SIGWINCH handler
662184645Skeramida	 * and set wresized so that our first iteration through the main
663184646Skeramida	 * vmstat loop will peek at the terminal's current rows to find out
664184645Skeramida	 * how many lines can fit in a screenful of output.
665184645Skeramida	 */
666184645Skeramida	if (isatty(fileno(stdout)) != 0) {
667184645Skeramida		wresized = 1;
668184645Skeramida		(void)signal(SIGWINCH, needresize);
669184645Skeramida	} else {
670184645Skeramida		wresized = 0;
671184645Skeramida		winlines = VMSTAT_DEFAULT_LINES;
672184645Skeramida	}
673184645Skeramida
674123250Sdes	if (kd != NULL) {
675123250Sdes		if (namelist[X_STATHZ].n_type != 0 &&
676123250Sdes		    namelist[X_STATHZ].n_value != 0)
677123250Sdes			kread(X_STATHZ, &hz, sizeof(hz));
678123250Sdes		if (!hz)
679123250Sdes			kread(X_HZ, &hz, sizeof(hz));
680123250Sdes	} else {
681123250Sdes		struct clockinfo clockrate;
6821590Srgrimes
683123250Sdes		size = sizeof(clockrate);
684123250Sdes		mysysctl("kern.clockrate", &clockrate, &size, NULL, 0);
685123250Sdes		if (size != sizeof(clockrate))
686123250Sdes			errx(1, "clockrate size mismatch");
687123250Sdes		hz = clockrate.hz;
688123250Sdes	}
689123250Sdes
690174573Speter	if (Pflag) {
691174573Speter		ncpus = getcpuinfo(&cpumask, &maxid);
692174573Speter		size_cp_times = sizeof(long) * (maxid + 1) * CPUSTATES;
693188888Sdelphij		cur_cp_times = calloc(1, size_cp_times);
694188888Sdelphij		last_cp_times = calloc(1, size_cp_times);
695174573Speter	}
6961590Srgrimes	for (hdrcnt = 1;;) {
6971590Srgrimes		if (!--hdrcnt)
698174573Speter			printhdr(ncpus, cpumask);
699123250Sdes		if (kd != NULL) {
700181881Sjhb			if (kvm_getcptime(kd, cur.cp_time) < 0)
701181881Sjhb				errx(1, "kvm_getcptime: %s", kvm_geterr(kd));
702123250Sdes		} else {
703123250Sdes			size = sizeof(cur.cp_time);
704123250Sdes			mysysctl("kern.cp_time", &cur.cp_time, &size, NULL, 0);
705123250Sdes			if (size != sizeof(cur.cp_time))
706123250Sdes				errx(1, "cp_time size mismatch");
707123250Sdes		}
708174573Speter		if (Pflag) {
709174573Speter			size = size_cp_times;
710174573Speter			mysysctl("kern.cp_times", cur_cp_times, &size, NULL, 0);
711174573Speter			if (size != size_cp_times)
712174573Speter				errx(1, "cp_times mismatch");
713174573Speter		}
71439230Sgibbs
71539230Sgibbs		tmp_dinfo = last.dinfo;
71639230Sgibbs		last.dinfo = cur.dinfo;
71739230Sgibbs		cur.dinfo = tmp_dinfo;
718112288Sphk		last.snap_time = cur.snap_time;
71939230Sgibbs
72039230Sgibbs		/*
72139230Sgibbs		 * Here what we want to do is refresh our device stats.
72239230Sgibbs		 * getdevs() returns 1 when the device list has changed.
72339230Sgibbs		 * If the device list has changed, we want to go through
72439230Sgibbs		 * the selection process again, in case a device that we
72539230Sgibbs		 * were previously displaying has gone away.
72639230Sgibbs		 */
727112284Sphk		switch (devstat_getdevs(NULL, &cur)) {
72839230Sgibbs		case -1:
72939230Sgibbs			errx(1, "%s", devstat_errbuf);
73039230Sgibbs			break;
73139230Sgibbs		case 1: {
73239230Sgibbs			int retval;
73339230Sgibbs
73439230Sgibbs			num_devices = cur.dinfo->numdevs;
73539230Sgibbs			generation = cur.dinfo->generation;
73639230Sgibbs
737112284Sphk			retval = devstat_selectdevs(&dev_select, &num_selected,
73839230Sgibbs					    &num_selections, &select_generation,
73939230Sgibbs					    generation, cur.dinfo->devices,
74039230Sgibbs					    num_devices, matches, num_matches,
74139230Sgibbs					    specified_devices,
74239230Sgibbs					    num_devices_specified, select_mode,
74339230Sgibbs					    maxshowdevs, 0);
74439230Sgibbs			switch (retval) {
74539230Sgibbs			case -1:
74639230Sgibbs				errx(1, "%s", devstat_errbuf);
74739230Sgibbs				break;
74839230Sgibbs			case 1:
749174573Speter				printhdr(ncpus, cpumask);
75039230Sgibbs				break;
75139230Sgibbs			default:
75239230Sgibbs				break;
75339230Sgibbs			}
75439230Sgibbs		}
75539230Sgibbs		default:
75639230Sgibbs			break;
75739230Sgibbs		}
75839230Sgibbs
759123250Sdes		fill_vmmeter(&sum);
760123250Sdes		fill_vmtotal(&total);
761164718Sru		(void)printf("%2d %1d %1d",
7621590Srgrimes		    total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
763164718Sru#define vmstat_pgtok(a) ((a) * (sum.v_page_size >> 10))
764208389Ssbruno#define	rate(x)	(((x) * rate_adj + halfuptime) / uptime)	/* round */
765174573Speter		if (hflag) {
766174573Speter			printf(" ");
767174573Speter			prthuman(total.t_avm * (u_int64_t)sum.v_page_size, 7);
768174573Speter			printf(" ");
769174573Speter			prthuman(total.t_free * (u_int64_t)sum.v_page_size, 6);
770174573Speter			printf(" ");
771174573Speter		} else {
772174573Speter			printf(" %7d ", vmstat_pgtok(total.t_avm));
773174573Speter			printf(" %6d ", vmstat_pgtok(total.t_free));
774174573Speter		}
775159200Sobrien		(void)printf("%5lu ",
776123407Sdes		    (unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults));
7771590Srgrimes		(void)printf("%3lu ",
778123407Sdes		    (unsigned long)rate(sum.v_reactivated - osum.v_reactivated));
77937453Sbde		(void)printf("%3lu ",
780123407Sdes		    (unsigned long)rate(sum.v_swapin + sum.v_vnodein -
7813659Sdg		    (osum.v_swapin + osum.v_vnodein)));
78237453Sbde		(void)printf("%3lu ",
783123407Sdes		    (unsigned long)rate(sum.v_swapout + sum.v_vnodeout -
7843693Sdg		    (osum.v_swapout + osum.v_vnodeout)));
785159200Sobrien		(void)printf("%5lu ",
786123407Sdes		    (unsigned long)rate(sum.v_tfree - osum.v_tfree));
78737453Sbde		(void)printf("%3lu ",
788123407Sdes		    (unsigned long)rate(sum.v_pdpages - osum.v_pdpages));
78939230Sgibbs		devstats();
790174573Speter		(void)printf("%4lu %4lu %4lu",
791123407Sdes		    (unsigned long)rate(sum.v_intr - osum.v_intr),
792123407Sdes		    (unsigned long)rate(sum.v_syscall - osum.v_syscall),
793123407Sdes		    (unsigned long)rate(sum.v_swtch - osum.v_swtch));
794174573Speter		if (Pflag)
795174573Speter			pcpustats(ncpus, cpumask, maxid);
796174573Speter		else
797174573Speter			cpustats();
7981590Srgrimes		(void)printf("\n");
7991590Srgrimes		(void)fflush(stdout);
8001590Srgrimes		if (reps >= 0 && --reps <= 0)
8011590Srgrimes			break;
8021590Srgrimes		osum = sum;
8031590Srgrimes		uptime = interval;
804208389Ssbruno		rate_adj = 1000;
8051590Srgrimes		/*
8061590Srgrimes		 * We round upward to avoid losing low-frequency events
807208389Ssbruno		 * (i.e., >= 1 per interval but < 1 per millisecond).
8081590Srgrimes		 */
8093659Sdg		if (interval != 1)
8103659Sdg			halfuptime = (uptime + 1) / 2;
8113659Sdg		else
8123659Sdg			halfuptime = 0;
813208389Ssbruno		(void)usleep(interval * 1000);
8141590Srgrimes	}
8151590Srgrimes}
8161590Srgrimes
817123250Sdesstatic void
818174573Speterprinthdr(int ncpus, u_long cpumask)
8191590Srgrimes{
82043822Sken	int i, num_shown;
8211590Srgrimes
82243822Sken	num_shown = (num_selected < maxshowdevs) ? num_selected : maxshowdevs;
82378672Sschweikh	(void)printf(" procs      memory      page%*s", 19, "");
82443822Sken	if (num_shown > 1)
82543822Sken		(void)printf(" disks %*s", num_shown * 4 - 7, "");
82643822Sken	else if (num_shown == 1)
82743822Sken		(void)printf("disk");
828174573Speter	(void)printf("   faults         ");
829174573Speter	if (Pflag) {
830174573Speter		for (i = 0; i < ncpus; i++) {
831175465Speter			if (cpumask & (1ul << i))
832174573Speter				printf("cpu%-2d    ", i);
833174573Speter		}
834174573Speter		printf("\n");
835174573Speter	} else
836174573Speter		printf("cpu\n");
837159200Sobrien	(void)printf(" r b w     avm    fre   flt  re  pi  po    fr  sr ");
83839230Sgibbs	for (i = 0; i < num_devices; i++)
83939230Sgibbs		if ((dev_select[i].selected)
84039230Sgibbs		 && (dev_select[i].selected <= maxshowdevs))
84139230Sgibbs			(void)printf("%c%c%d ", dev_select[i].device_name[0],
84239230Sgibbs				     dev_select[i].device_name[1],
84339230Sgibbs				     dev_select[i].unit_number);
844174573Speter	(void)printf("  in   sy   cs");
845174573Speter	if (Pflag) {
846174573Speter		for (i = 0; i < ncpus; i++)
847174573Speter			printf(" us sy id");
848174573Speter		printf("\n");
849174573Speter	} else
850174573Speter		printf(" us sy id\n");
851184645Skeramida	if (wresized != 0)
852184645Skeramida		doresize();
853184645Skeramida	hdrcnt = winlines;
8541590Srgrimes}
8551590Srgrimes
8561590Srgrimes/*
8571590Srgrimes * Force a header to be prepended to the next output.
8581590Srgrimes */
859123250Sdesstatic void
860123250Sdesneedhdr(int dummy __unused)
8611590Srgrimes{
8621590Srgrimes
8631590Srgrimes	hdrcnt = 1;
8641590Srgrimes}
8651590Srgrimes
866184645Skeramida/*
867184645Skeramida * When the terminal is resized, force an update of the maximum number of rows
868184645Skeramida * printed between each header repetition.  Then force a new header to be
869184645Skeramida * prepended to the next output.
870184645Skeramida */
871184645Skeramidavoid
872184645Skeramidaneedresize(int signo)
873184645Skeramida{
874184645Skeramida
875184645Skeramida	wresized = 1;
876184645Skeramida	hdrcnt = 1;
877184645Skeramida}
878184645Skeramida
879184645Skeramida/*
880184645Skeramida * Update the global `winlines' count of terminal rows.
881184645Skeramida */
882184645Skeramidavoid
883184645Skeramidadoresize(void)
884184645Skeramida{
885184645Skeramida	int status;
886184645Skeramida	struct winsize w;
887184645Skeramida
888184645Skeramida	for (;;) {
889184645Skeramida		status = ioctl(fileno(stdout), TIOCGWINSZ, &w);
890184645Skeramida		if (status == -1 && errno == EINTR)
891184645Skeramida			continue;
892184645Skeramida		else if (status == -1)
893184645Skeramida			err(1, "ioctl");
894184645Skeramida		if (w.ws_row > 3)
895184645Skeramida			winlines = w.ws_row - 3;
896184645Skeramida		else
897184645Skeramida			winlines = VMSTAT_DEFAULT_LINES;
898184645Skeramida		break;
899184645Skeramida	}
900184645Skeramida
901184645Skeramida	/*
902184645Skeramida	 * Inhibit doresize() calls until we are rescheduled by SIGWINCH.
903184645Skeramida	 */
904184645Skeramida	wresized = 0;
905184645Skeramida}
906184645Skeramida
90730180Sdima#ifdef notyet
908123250Sdesstatic void
909123250Sdesdotimes(void)
9101590Srgrimes{
911123407Sdes	unsigned int pgintime, rectime;
9121590Srgrimes
9131590Srgrimes	kread(X_REC, &rectime, sizeof(rectime));
9141590Srgrimes	kread(X_PGIN, &pgintime, sizeof(pgintime));
9151590Srgrimes	kread(X_SUM, &sum, sizeof(sum));
9161590Srgrimes	(void)printf("%u reclaims, %u total time (usec)\n",
9171590Srgrimes	    sum.v_pgrec, rectime);
9181590Srgrimes	(void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec);
9191590Srgrimes	(void)printf("\n");
9201590Srgrimes	(void)printf("%u page ins, %u total time (msec)\n",
9211590Srgrimes	    sum.v_pgin, pgintime / 10);
9221590Srgrimes	(void)printf("average: %8.1f msec / page in\n",
9231590Srgrimes	    pgintime / (sum.v_pgin * 10.0));
9241590Srgrimes}
9251590Srgrimes#endif
9261590Srgrimes
927123250Sdesstatic long
928123250Sdespct(long top, long bot)
9291590Srgrimes{
9301590Srgrimes	long ans;
9311590Srgrimes
9321590Srgrimes	if (bot == 0)
9331590Srgrimes		return(0);
9341590Srgrimes	ans = (quad_t)top * 100 / bot;
9351590Srgrimes	return (ans);
9361590Srgrimes}
9371590Srgrimes
9381590Srgrimes#define	PCT(top, bot) pct((long)(top), (long)(bot))
9391590Srgrimes
940123250Sdesstatic void
941123250Sdesdosum(void)
9421590Srgrimes{
94387690Smarkm	struct nchstats lnchstats;
9441590Srgrimes	long nchtotal;
9451590Srgrimes
946123250Sdes	fill_vmmeter(&sum);
9471590Srgrimes	(void)printf("%9u cpu context switches\n", sum.v_swtch);
9481590Srgrimes	(void)printf("%9u device interrupts\n", sum.v_intr);
9491590Srgrimes	(void)printf("%9u software interrupts\n", sum.v_soft);
9501590Srgrimes	(void)printf("%9u traps\n", sum.v_trap);
9511590Srgrimes	(void)printf("%9u system calls\n", sum.v_syscall);
95271429Sume	(void)printf("%9u kernel threads created\n", sum.v_kthreads);
95371429Sume	(void)printf("%9u  fork() calls\n", sum.v_forks);
95471429Sume	(void)printf("%9u vfork() calls\n", sum.v_vforks);
95571429Sume	(void)printf("%9u rfork() calls\n", sum.v_rforks);
9563659Sdg	(void)printf("%9u swap pager pageins\n", sum.v_swapin);
9573693Sdg	(void)printf("%9u swap pager pages paged in\n", sum.v_swappgsin);
9583659Sdg	(void)printf("%9u swap pager pageouts\n", sum.v_swapout);
9593659Sdg	(void)printf("%9u swap pager pages paged out\n", sum.v_swappgsout);
9603659Sdg	(void)printf("%9u vnode pager pageins\n", sum.v_vnodein);
9613693Sdg	(void)printf("%9u vnode pager pages paged in\n", sum.v_vnodepgsin);
9623659Sdg	(void)printf("%9u vnode pager pageouts\n", sum.v_vnodeout);
9633659Sdg	(void)printf("%9u vnode pager pages paged out\n", sum.v_vnodepgsout);
9643693Sdg	(void)printf("%9u page daemon wakeups\n", sum.v_pdwakeups);
9653693Sdg	(void)printf("%9u pages examined by the page daemon\n", sum.v_pdpages);
9661590Srgrimes	(void)printf("%9u pages reactivated\n", sum.v_reactivated);
9677351Sdg	(void)printf("%9u copy-on-write faults\n", sum.v_cow_faults);
96834214Sdyson	(void)printf("%9u copy-on-write optimized faults\n", sum.v_cow_optim);
9697351Sdg	(void)printf("%9u zero fill pages zeroed\n", sum.v_zfod);
97034214Sdyson	(void)printf("%9u zero fill pages prezeroed\n", sum.v_ozfod);
9711590Srgrimes	(void)printf("%9u intransit blocking page faults\n", sum.v_intrans);
9721590Srgrimes	(void)printf("%9u total VM faults taken\n", sum.v_vm_faults);
973246034Szont	(void)printf("%9u page faults requiring I/O\n", sum.v_io_faults);
97471429Sume	(void)printf("%9u pages affected by kernel thread creation\n", sum.v_kthreadpages);
97571429Sume	(void)printf("%9u pages affected by  fork()\n", sum.v_forkpages);
97671429Sume	(void)printf("%9u pages affected by vfork()\n", sum.v_vforkpages);
97771429Sume	(void)printf("%9u pages affected by rfork()\n", sum.v_rforkpages);
978171633Salc	(void)printf("%9u pages cached\n", sum.v_tcached);
9793693Sdg	(void)printf("%9u pages freed\n", sum.v_tfree);
9801590Srgrimes	(void)printf("%9u pages freed by daemon\n", sum.v_dfree);
9811590Srgrimes	(void)printf("%9u pages freed by exiting processes\n", sum.v_pfree);
9821590Srgrimes	(void)printf("%9u pages active\n", sum.v_active_count);
9831590Srgrimes	(void)printf("%9u pages inactive\n", sum.v_inactive_count);
9845463Sdg	(void)printf("%9u pages in VM cache\n", sum.v_cache_count);
9853693Sdg	(void)printf("%9u pages wired down\n", sum.v_wire_count);
9863693Sdg	(void)printf("%9u pages free\n", sum.v_free_count);
9871590Srgrimes	(void)printf("%9u bytes per page\n", sum.v_page_size);
988123250Sdes	if (kd != NULL) {
989123250Sdes		kread(X_NCHSTATS, &lnchstats, sizeof(lnchstats));
990123250Sdes	} else {
991123250Sdes		size_t size = sizeof(lnchstats);
992123250Sdes		mysysctl("vfs.cache.nchstats", &lnchstats, &size, NULL, 0);
993123250Sdes		if (size != sizeof(lnchstats))
994123250Sdes			errx(1, "vfs.cache.nchstats size mismatch");
995123250Sdes	}
99687690Smarkm	nchtotal = lnchstats.ncs_goodhits + lnchstats.ncs_neghits +
99787690Smarkm	    lnchstats.ncs_badhits + lnchstats.ncs_falsehits +
99887690Smarkm	    lnchstats.ncs_miss + lnchstats.ncs_long;
9991590Srgrimes	(void)printf("%9ld total name lookups\n", nchtotal);
10001590Srgrimes	(void)printf(
100128693Scharnier	    "%9s cache hits (%ld%% pos + %ld%% neg) system %ld%% per-directory\n",
100287690Smarkm	    "", PCT(lnchstats.ncs_goodhits, nchtotal),
100387690Smarkm	    PCT(lnchstats.ncs_neghits, nchtotal),
100487690Smarkm	    PCT(lnchstats.ncs_pass2, nchtotal));
100528693Scharnier	(void)printf("%9s deletions %ld%%, falsehits %ld%%, toolong %ld%%\n", "",
100687690Smarkm	    PCT(lnchstats.ncs_badhits, nchtotal),
100787690Smarkm	    PCT(lnchstats.ncs_falsehits, nchtotal),
100887690Smarkm	    PCT(lnchstats.ncs_long, nchtotal));
10091590Srgrimes}
10101590Srgrimes
1011123250Sdesstatic void
1012123250Sdesdoforkst(void)
10131590Srgrimes{
1014123250Sdes	fill_vmmeter(&sum);
1015128573Stjr	(void)printf("%u forks, %u pages, average %.2f\n",
1016113460Stjr	    sum.v_forks, sum.v_forkpages,
1017113460Stjr	    sum.v_forks == 0 ? 0.0 :
1018113460Stjr	    (double)sum.v_forkpages / sum.v_forks);
1019128573Stjr	(void)printf("%u vforks, %u pages, average %.2f\n",
1020113460Stjr	    sum.v_vforks, sum.v_vforkpages,
1021113460Stjr	    sum.v_vforks == 0 ? 0.0 :
1022113460Stjr	    (double)sum.v_vforkpages / sum.v_vforks);
1023128573Stjr	(void)printf("%u rforks, %u pages, average %.2f\n",
1024113460Stjr	    sum.v_rforks, sum.v_rforkpages,
1025113460Stjr	    sum.v_rforks == 0 ? 0.0 :
1026113460Stjr	    (double)sum.v_rforkpages / sum.v_rforks);
10271590Srgrimes}
10281590Srgrimes
102939230Sgibbsstatic void
1030123250Sdesdevstats(void)
10311590Srgrimes{
103287690Smarkm	int dn, state;
103339230Sgibbs	long double transfers_per_second;
103439230Sgibbs	long double busy_seconds;
10351590Srgrimes	long tmp;
1036123250Sdes
10371590Srgrimes	for (state = 0; state < CPUSTATES; ++state) {
103839230Sgibbs		tmp = cur.cp_time[state];
103939230Sgibbs		cur.cp_time[state] -= last.cp_time[state];
104039230Sgibbs		last.cp_time[state] = tmp;
10411590Srgrimes	}
104239230Sgibbs
1043112288Sphk	busy_seconds = cur.snap_time - last.snap_time;
104439230Sgibbs
104539230Sgibbs	for (dn = 0; dn < num_devices; dn++) {
104639230Sgibbs		int di;
104739230Sgibbs
104839230Sgibbs		if ((dev_select[dn].selected == 0)
104939230Sgibbs		 || (dev_select[dn].selected > maxshowdevs))
10501590Srgrimes			continue;
105139230Sgibbs
105239230Sgibbs		di = dev_select[dn].position;
105339230Sgibbs
105481537Sken		if (devstat_compute_statistics(&cur.dinfo->devices[di],
105581537Sken		    &last.dinfo->devices[di], busy_seconds,
105681537Sken		    DSM_TRANSFERS_PER_SECOND, &transfers_per_second,
105781537Sken		    DSM_NONE) != 0)
105839230Sgibbs			errx(1, "%s", devstat_errbuf);
105939230Sgibbs
106081537Sken		(void)printf("%3.0Lf ", transfers_per_second);
10611590Srgrimes	}
10621590Srgrimes}
10631590Srgrimes
1064123250Sdesstatic void
1065174573Speterpercent(double pct, int *over)
1066174573Speter{
1067174573Speter	char buf[10];
1068174573Speter	int l;
1069174573Speter
1070174573Speter	l = snprintf(buf, sizeof(buf), "%.0f", pct);
1071174573Speter	if (l == 1 && *over) {
1072174573Speter		printf("%s",  buf);
1073174573Speter		(*over)--;
1074174573Speter	} else
1075174573Speter		printf("%2s", buf);
1076174573Speter	if (l > 2)
1077174573Speter		(*over)++;
1078174573Speter}
1079174573Speter
1080174573Speterstatic void
1081123250Sdescpustats(void)
10821590Srgrimes{
1083174573Speter	int state, over;
108487690Smarkm	double lpct, total;
10851590Srgrimes
10861590Srgrimes	total = 0;
10871590Srgrimes	for (state = 0; state < CPUSTATES; ++state)
108839230Sgibbs		total += cur.cp_time[state];
10891590Srgrimes	if (total)
109087690Smarkm		lpct = 100.0 / total;
10911590Srgrimes	else
109287690Smarkm		lpct = 0.0;
1093174573Speter	over = 0;
1094174573Speter	printf(" ");
1095174573Speter	percent((cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * lpct, &over);
1096174573Speter	printf(" ");
1097174573Speter	percent((cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * lpct, &over);
1098174573Speter	printf(" ");
1099174573Speter	percent(cur.cp_time[CP_IDLE] * lpct, &over);
11001590Srgrimes}
11011590Srgrimes
1102123250Sdesstatic void
1103174573Speterpcpustats(int ncpus, u_long cpumask, int maxid)
1104174573Speter{
1105174573Speter	int state, i;
1106174573Speter	double lpct, total;
1107174573Speter	long tmp;
1108174573Speter	int over;
1109174573Speter
1110174573Speter	/* devstats does this for cp_time */
1111174573Speter	for (i = 0; i <= maxid; i++) {
1112175465Speter		if ((cpumask & (1ul << i)) == 0)
1113174573Speter			continue;
1114174573Speter		for (state = 0; state < CPUSTATES; ++state) {
1115174573Speter			tmp = cur_cp_times[i * CPUSTATES + state];
1116174573Speter			cur_cp_times[i * CPUSTATES + state] -= last_cp_times[i * CPUSTATES + state];
1117174573Speter			last_cp_times[i * CPUSTATES + state] = tmp;
1118174573Speter		}
1119174573Speter	}
1120174573Speter
1121174573Speter	over = 0;
1122174573Speter	for (i = 0; i <= maxid; i++) {
1123175465Speter		if ((cpumask & (1ul << i)) == 0)
1124174573Speter			continue;
1125174573Speter		total = 0;
1126174573Speter		for (state = 0; state < CPUSTATES; ++state)
1127174573Speter			total += cur_cp_times[i * CPUSTATES + state];
1128174573Speter		if (total)
1129174573Speter			lpct = 100.0 / total;
1130174573Speter		else
1131174573Speter			lpct = 0.0;
1132174573Speter		printf(" ");
1133174573Speter		percent((cur_cp_times[i * CPUSTATES + CP_USER] +
1134174573Speter			 cur_cp_times[i * CPUSTATES + CP_NICE]) * lpct, &over);
1135174573Speter		printf(" ");
1136174573Speter		percent((cur_cp_times[i * CPUSTATES + CP_SYS] +
1137174573Speter			 cur_cp_times[i * CPUSTATES + CP_INTR]) * lpct, &over);
1138174573Speter		printf(" ");
1139174573Speter		percent(cur_cp_times[i * CPUSTATES + CP_IDLE] * lpct, &over);
1140174573Speter	}
1141174573Speter}
1142174573Speter
1143174573Speterstatic void
1144123250Sdesdointr(void)
11451590Srgrimes{
1146123407Sdes	unsigned long *intrcnt, uptime;
1147123409Sdes	uint64_t inttotal;
1148123409Sdes	size_t clen, inamlen, intrcntlen, istrnamlen;
1149123409Sdes	unsigned int i, nintr;
1150121626Sjmg	char *intrname, *tintrname;
11511590Srgrimes
11521590Srgrimes	uptime = getuptime();
1153123250Sdes	if (kd != NULL) {
1154224198Spluknet		kread(X_SINTRCNT, &intrcntlen, sizeof(intrcntlen));
1155224198Spluknet		kread(X_SINTRNAMES, &inamlen, sizeof(inamlen));
1156123409Sdes		if ((intrcnt = malloc(intrcntlen)) == NULL ||
1157123290Smarcel		    (intrname = malloc(inamlen)) == NULL)
1158123250Sdes			err(1, "malloc()");
1159123409Sdes		kread(X_INTRCNT, intrcnt, intrcntlen);
1160123290Smarcel		kread(X_INTRNAMES, intrname, inamlen);
1161123250Sdes	} else {
1162123438Sdes		for (intrcnt = NULL, intrcntlen = 1024; ; intrcntlen *= 2) {
1163123438Sdes			if ((intrcnt = reallocf(intrcnt, intrcntlen)) == NULL)
1164123438Sdes				err(1, "reallocf()");
1165123438Sdes			if (mysysctl("hw.intrcnt",
1166123438Sdes			    intrcnt, &intrcntlen, NULL, 0) == 0)
1167123438Sdes				break;
1168123438Sdes		}
1169123250Sdes		for (intrname = NULL, inamlen = 1024; ; inamlen *= 2) {
1170123250Sdes			if ((intrname = reallocf(intrname, inamlen)) == NULL)
1171123250Sdes				err(1, "reallocf()");
1172123250Sdes			if (mysysctl("hw.intrnames",
1173123250Sdes			    intrname, &inamlen, NULL, 0) == 0)
1174123250Sdes				break;
1175123250Sdes		}
1176123250Sdes	}
1177123409Sdes	nintr = intrcntlen / sizeof(unsigned long);
1178121626Sjmg	tintrname = intrname;
1179122365Sjmg	istrnamlen = strlen("interrupt");
1180121626Sjmg	for (i = 0; i < nintr; i++) {
1181121626Sjmg		clen = strlen(tintrname);
1182121626Sjmg		if (clen > istrnamlen)
1183121626Sjmg			istrnamlen = clen;
1184121626Sjmg		tintrname += clen + 1;
1185121626Sjmg	}
1186228654Sdim	(void)printf("%-*s %20s %10s\n", (int)istrnamlen, "interrupt", "total",
1187121626Sjmg	    "rate");
11881590Srgrimes	inttotal = 0;
1189123290Smarcel	for (i = 0; i < nintr; i++) {
1190123409Sdes		if (intrname[0] != '\0' && (*intrcnt != 0 || aflag))
1191228654Sdim			(void)printf("%-*s %20lu %10lu\n", (int)istrnamlen,
1192228654Sdim			    intrname, *intrcnt, *intrcnt / uptime);
11931590Srgrimes		intrname += strlen(intrname) + 1;
11941590Srgrimes		inttotal += *intrcnt++;
11951590Srgrimes	}
1196228654Sdim	(void)printf("%-*s %20" PRIu64 " %10" PRIu64 "\n", (int)istrnamlen,
1197228654Sdim	    "Total", inttotal, inttotal / uptime);
11981590Srgrimes}
11991590Srgrimes
1200148413Srwatsonstatic void
1201148413Srwatsondomemstat_malloc(void)
1202148413Srwatson{
1203148413Srwatson	struct memory_type_list *mtlp;
1204148413Srwatson	struct memory_type *mtp;
1205148790Srwatson	int error, first, i;
1206148413Srwatson
1207148413Srwatson	mtlp = memstat_mtl_alloc();
1208148413Srwatson	if (mtlp == NULL) {
1209148413Srwatson		warn("memstat_mtl_alloc");
1210148413Srwatson		return;
1211148413Srwatson	}
1212148790Srwatson	if (kd == NULL) {
1213148790Srwatson		if (memstat_sysctl_malloc(mtlp, 0) < 0) {
1214148790Srwatson			warnx("memstat_sysctl_malloc: %s",
1215148790Srwatson			    memstat_strerror(memstat_mtl_geterror(mtlp)));
1216148790Srwatson			return;
1217148790Srwatson		}
1218148790Srwatson	} else {
1219148790Srwatson		if (memstat_kvm_malloc(mtlp, kd) < 0) {
1220148790Srwatson			error = memstat_mtl_geterror(mtlp);
1221148790Srwatson			if (error == MEMSTAT_ERROR_KVM)
1222148790Srwatson				warnx("memstat_kvm_malloc: %s",
1223148790Srwatson				    kvm_geterr(kd));
1224148790Srwatson			else
1225148790Srwatson				warnx("memstat_kvm_malloc: %s",
1226148790Srwatson				    memstat_strerror(error));
1227148790Srwatson		}
1228148413Srwatson	}
1229148413Srwatson	printf("%13s %5s %6s %7s %8s  Size(s)\n", "Type", "InUse", "MemUse",
1230148413Srwatson	    "HighUse", "Requests");
1231148413Srwatson	for (mtp = memstat_mtl_first(mtlp); mtp != NULL;
1232148413Srwatson	    mtp = memstat_mtl_next(mtp)) {
1233148413Srwatson		if (memstat_get_numallocs(mtp) == 0 &&
1234148413Srwatson		    memstat_get_count(mtp) == 0)
1235148413Srwatson			continue;
1236228654Sdim		printf("%13s %5" PRIu64 " %5" PRIu64 "K %7s %8" PRIu64 "  ",
1237148413Srwatson		    memstat_get_name(mtp), memstat_get_count(mtp),
1238228654Sdim		    (memstat_get_bytes(mtp) + 1023) / 1024, "-",
1239148413Srwatson		    memstat_get_numallocs(mtp));
1240148413Srwatson		first = 1;
1241148413Srwatson		for (i = 0; i < 32; i++) {
1242148413Srwatson			if (memstat_get_sizemask(mtp) & (1 << i)) {
1243148413Srwatson				if (!first)
1244148413Srwatson					printf(",");
1245148413Srwatson				printf("%d", 1 << (i + 4));
1246148413Srwatson				first = 0;
1247148413Srwatson			}
1248148413Srwatson		}
1249148413Srwatson		printf("\n");
1250148413Srwatson	}
1251148413Srwatson	memstat_mtl_free(mtlp);
1252148413Srwatson}
1253148413Srwatson
1254148413Srwatsonstatic void
1255148413Srwatsondomemstat_zone(void)
1256148413Srwatson{
1257148413Srwatson	struct memory_type_list *mtlp;
1258148413Srwatson	struct memory_type *mtp;
1259148413Srwatson	char name[MEMTYPE_MAXNAME + 1];
1260148630Srwatson	int error;
1261148413Srwatson
1262148413Srwatson	mtlp = memstat_mtl_alloc();
1263148413Srwatson	if (mtlp == NULL) {
1264148413Srwatson		warn("memstat_mtl_alloc");
1265148413Srwatson		return;
1266148413Srwatson	}
1267148630Srwatson	if (kd == NULL) {
1268148630Srwatson		if (memstat_sysctl_uma(mtlp, 0) < 0) {
1269148630Srwatson			warnx("memstat_sysctl_uma: %s",
1270148630Srwatson			    memstat_strerror(memstat_mtl_geterror(mtlp)));
1271148630Srwatson			return;
1272148630Srwatson		}
1273148630Srwatson	} else {
1274148630Srwatson		if (memstat_kvm_uma(mtlp, kd) < 0) {
1275148630Srwatson			error = memstat_mtl_geterror(mtlp);
1276148630Srwatson			if (error == MEMSTAT_ERROR_KVM)
1277148630Srwatson				warnx("memstat_kvm_uma: %s",
1278148630Srwatson				    kvm_geterr(kd));
1279148630Srwatson			else
1280148630Srwatson				warnx("memstat_kvm_uma: %s",
1281148630Srwatson				    memstat_strerror(error));
1282148630Srwatson		}
1283148413Srwatson	}
1284209215Ssbruno	printf("%-20s %6s %6s %8s %8s %8s %4s %4s\n\n", "ITEM", "SIZE",
1285209215Ssbruno	    "LIMIT", "USED", "FREE", "REQ", "FAIL", "SLEEP");
1286148413Srwatson	for (mtp = memstat_mtl_first(mtlp); mtp != NULL;
1287148413Srwatson	    mtp = memstat_mtl_next(mtp)) {
1288148413Srwatson		strlcpy(name, memstat_get_name(mtp), MEMTYPE_MAXNAME);
1289148413Srwatson		strcat(name, ":");
1290228654Sdim		printf("%-20s %6" PRIu64 ", %6" PRIu64 ",%8" PRIu64 ",%8" PRIu64
1291228654Sdim		    ",%8" PRIu64 ",%4" PRIu64 ",%4" PRIu64 "\n", name,
1292148413Srwatson		    memstat_get_size(mtp), memstat_get_countlimit(mtp),
1293148413Srwatson		    memstat_get_count(mtp), memstat_get_free(mtp),
1294209215Ssbruno		    memstat_get_numallocs(mtp), memstat_get_failures(mtp),
1295209215Ssbruno		    memstat_get_sleeps(mtp));
1296148413Srwatson	}
1297148413Srwatson	memstat_mtl_free(mtlp);
1298148413Srwatson	printf("\n");
1299148413Srwatson}
1300148413Srwatson
1301148413Srwatson/*
13021590Srgrimes * kread reads something from the kernel, given its nlist index.
13031590Srgrimes */
1304123250Sdesstatic void
1305131300Sgreenkreado(int nlx, void *addr, size_t size, size_t offset)
13061590Srgrimes{
1307123825Sdwmalone	const char *sym;
13081590Srgrimes
130940690Sjdp	if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
13101590Srgrimes		sym = namelist[nlx].n_name;
13111590Srgrimes		if (*sym == '_')
13121590Srgrimes			++sym;
131328693Scharnier		errx(1, "symbol %s not defined", sym);
13141590Srgrimes	}
1315131300Sgreen	if ((size_t)kvm_read(kd, namelist[nlx].n_value + offset, addr,
1316131300Sgreen	    size) != size) {
13171590Srgrimes		sym = namelist[nlx].n_name;
13181590Srgrimes		if (*sym == '_')
13191590Srgrimes			++sym;
132028693Scharnier		errx(1, "%s: %s", sym, kvm_geterr(kd));
13211590Srgrimes	}
13221590Srgrimes}
13231590Srgrimes
1324123250Sdesstatic void
1325131300Sgreenkread(int nlx, void *addr, size_t size)
1326131300Sgreen{
1327131300Sgreen	kreado(nlx, addr, size, 0);
1328131300Sgreen}
1329131300Sgreen
1330131300Sgreenstatic char *
1331131300Sgreenkgetstr(const char *strp)
1332131300Sgreen{
1333131300Sgreen	int n = 0, size = 1;
1334131300Sgreen	char *ret = NULL;
1335131300Sgreen
1336131300Sgreen	do {
1337131300Sgreen		if (size == n + 1) {
1338131300Sgreen			ret = realloc(ret, size);
1339131300Sgreen			if (ret == NULL)
1340131300Sgreen				err(1, "%s: realloc", __func__);
1341131300Sgreen			size *= 2;
1342131300Sgreen		}
1343131300Sgreen		if (kvm_read(kd, (u_long)strp + n, &ret[n], 1) != 1)
1344131300Sgreen			errx(1, "%s: %s", __func__, kvm_geterr(kd));
1345131300Sgreen	} while (ret[n++] != '\0');
1346131300Sgreen	return (ret);
1347131300Sgreen}
1348131300Sgreen
1349131300Sgreenstatic void
1350123250Sdesusage(void)
13511590Srgrimes{
135272887Salfred	(void)fprintf(stderr, "%s%s",
1353178063Sru		"usage: vmstat [-afHhimPsz] [-c count] [-M core [-N system]] [-w wait]\n",
1354146466Sru		"              [-n devs] [-p type,if,pass] [disks]\n");
13551590Srgrimes	exit(1);
13561590Srgrimes}
1357