vmstat.c revision 122300
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 * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
3487690Smarkm#include <sys/cdefs.h>
3587690Smarkm
3687690Smarkm__FBSDID("$FreeBSD: head/usr.bin/vmstat/vmstat.c 122300 2003-11-08 07:24:03Z jmg $");
3787690Smarkm
381590Srgrimes#ifndef lint
3928693Scharnierstatic const char copyright[] =
401590Srgrimes"@(#) Copyright (c) 1980, 1986, 1991, 1993\n\
411590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
4287690Smarkm#endif
431590Srgrimes
441590Srgrimes#ifndef lint
4587690Smarkmstatic const char sccsid[] = "@(#)vmstat.c	8.1 (Berkeley) 6/6/93";
4628693Scharnier#endif
471590Srgrimes
481590Srgrimes#include <sys/param.h>
491590Srgrimes#include <sys/time.h>
501590Srgrimes#include <sys/proc.h>
5112811Sbde#include <sys/uio.h>
521590Srgrimes#include <sys/namei.h>
531590Srgrimes#include <sys/malloc.h>
541590Srgrimes#include <sys/signal.h>
551590Srgrimes#include <sys/fcntl.h>
561590Srgrimes#include <sys/ioctl.h>
57111008Sphk#include <sys/resource.h>
581590Srgrimes#include <sys/sysctl.h>
5912804Speter#include <sys/vmmeter.h>
6012811Sbde
6112811Sbde#include <vm/vm_param.h>
6212811Sbde
6328693Scharnier#include <ctype.h>
6487690Smarkm#include <devstat.h>
6528693Scharnier#include <err.h>
6628693Scharnier#include <errno.h>
6728693Scharnier#include <kvm.h>
6828693Scharnier#include <limits.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>
771590Srgrimes
7887690Smarkmstatic char da[] = "da";
7987690Smarkm
8087690Smarkmstatic struct nlist namelist[] = {
811590Srgrimes#define	X_CPTIME	0
821590Srgrimes	{ "_cp_time" },
8339230Sgibbs#define X_SUM		1
841590Srgrimes	{ "_cnt" },
8539230Sgibbs#define	X_BOOTTIME	2
861590Srgrimes	{ "_boottime" },
8739230Sgibbs#define X_HZ		3
881590Srgrimes	{ "_hz" },
8939230Sgibbs#define X_STATHZ	4
901590Srgrimes	{ "_stathz" },
9139230Sgibbs#define X_NCHSTATS	5
921590Srgrimes	{ "_nchstats" },
9339230Sgibbs#define	X_INTRNAMES	6
941590Srgrimes	{ "_intrnames" },
9539230Sgibbs#define	X_EINTRNAMES	7
961590Srgrimes	{ "_eintrnames" },
9739230Sgibbs#define	X_INTRCNT	8
981590Srgrimes	{ "_intrcnt" },
9939230Sgibbs#define	X_EINTRCNT	9
1001590Srgrimes	{ "_eintrcnt" },
10130180Sdima#ifdef notyet
10294729Sjeff#define	X_DEFICIT	10
1031590Srgrimes	{ "_deficit" },
104113460Stjr#define X_REC		11
1051590Srgrimes	{ "_rectime" },
106113460Stjr#define X_PGIN		12
1071590Srgrimes	{ "_pgintime" },
108113460Stjr#define	X_XSTATS	13
1091590Srgrimes	{ "_xstats" },
110113460Stjr#define X_END		14
11192653Sjeff#else
11294729Sjeff#define X_END		10
1131590Srgrimes#endif
1141590Srgrimes	{ "" },
1151590Srgrimes};
1161590Srgrimes
11739230Sgibbsstruct statinfo cur, last;
11839498Skenint num_devices, maxshowdevs;
11939498Skenlong generation;
12039230Sgibbsstruct device_selection *dev_select;
12139230Sgibbsint num_selected;
12239230Sgibbsstruct devstat_match *matches;
12339230Sgibbsint num_matches = 0;
12439498Skenint num_devices_specified, num_selections;
12539498Skenlong select_generation;
12639230Sgibbschar **specified_devices;
12739230Sgibbsdevstat_select_mode select_mode;
1281590Srgrimes
1291590Srgrimesstruct	vmmeter sum, osum;
1301590Srgrimes
1311590Srgrimesint	winlines = 20;
13239372Sdillonint	nflag = 0;
1331590Srgrimes
1341590Srgrimeskvm_t *kd;
1351590Srgrimes
1361590Srgrimes#define	FORKSTAT	0x01
1371590Srgrimes#define	INTRSTAT	0x02
1381590Srgrimes#define	MEMSTAT		0x04
1391590Srgrimes#define	SUMSTAT		0x08
1401590Srgrimes#define	TIMESTAT	0x10
1411590Srgrimes#define	VMSTAT		0x20
14243962Sdillon#define ZMEMSTAT	0x40
1431590Srgrimes
14492922Simpstatic void	cpustats(void);
14592922Simpstatic void	devstats(void);
146122300Sjmgstatic void	doforkst(void);
14792922Simpstatic void	domem(void);
14892922Simpstatic void	dointr(void);
14992922Simpstatic void	dosum(void);
150122300Sjmgstatic void	dosysctl(char *);
15192922Simpstatic void	dovmstat(u_int, int);
15292922Simpstatic void	dozmem(void);
15392922Simpstatic void	kread(int, void *, size_t);
15492922Simpstatic void	needhdr(int);
15592922Simpstatic void	printhdr(void);
15692922Simpstatic void	usage(void);
1571590Srgrimes
15892922Simpstatic long	pct(long, long);
15992922Simpstatic long	getuptime(void);
16087690Smarkm
16192922Simpchar **getdrivedata(char **);
16287690Smarkm
16328693Scharnierint
1641590Srgrimesmain(argc, argv)
16587690Smarkm	int argc;
16687690Smarkm	char **argv;
1671590Srgrimes{
16887690Smarkm	int c, todo;
1691590Srgrimes	u_int interval;
1701590Srgrimes	int reps;
1711590Srgrimes	char *memf, *nlistf;
17278474Sschweikh	char errbuf[_POSIX2_LINE_MAX];
1731590Srgrimes
1741590Srgrimes	memf = nlistf = NULL;
1751590Srgrimes	interval = reps = todo = 0;
17643822Sken	maxshowdevs = 2;
17744067Sbde	while ((c = getopt(argc, argv, "c:fiM:mN:n:p:stw:z")) != -1) {
1781590Srgrimes		switch (c) {
1791590Srgrimes		case 'c':
1801590Srgrimes			reps = atoi(optarg);
1811590Srgrimes			break;
1821590Srgrimes		case 'f':
183113460Stjr			todo |= FORKSTAT;
1841590Srgrimes			break;
1851590Srgrimes		case 'i':
1861590Srgrimes			todo |= INTRSTAT;
1871590Srgrimes			break;
1881590Srgrimes		case 'M':
1891590Srgrimes			memf = optarg;
1901590Srgrimes			break;
1911590Srgrimes		case 'm':
1921590Srgrimes			todo |= MEMSTAT;
1931590Srgrimes			break;
1941590Srgrimes		case 'N':
1951590Srgrimes			nlistf = optarg;
1961590Srgrimes			break;
19739230Sgibbs		case 'n':
19839372Sdillon			nflag = 1;
19939230Sgibbs			maxshowdevs = atoi(optarg);
20039230Sgibbs			if (maxshowdevs < 0)
20139230Sgibbs				errx(1, "number of devices %d is < 0",
20239230Sgibbs				     maxshowdevs);
20339230Sgibbs			break;
20439230Sgibbs		case 'p':
205112284Sphk			if (devstat_buildmatch(optarg, &matches, &num_matches) != 0)
20639230Sgibbs				errx(1, "%s", devstat_errbuf);
20739230Sgibbs			break;
2081590Srgrimes		case 's':
2091590Srgrimes			todo |= SUMSTAT;
2101590Srgrimes			break;
2111590Srgrimes		case 't':
21230180Sdima#ifdef notyet
2131590Srgrimes			todo |= TIMESTAT;
21430180Sdima#else
21530180Sdima			errx(EX_USAGE, "sorry, -t is not (re)implemented yet");
21630180Sdima#endif
2171590Srgrimes			break;
2181590Srgrimes		case 'w':
2191590Srgrimes			interval = atoi(optarg);
2201590Srgrimes			break;
22144067Sbde		case 'z':
22244067Sbde			todo |= ZMEMSTAT;
22344067Sbde			break;
2241590Srgrimes		case '?':
2251590Srgrimes		default:
2261590Srgrimes			usage();
2271590Srgrimes		}
2281590Srgrimes	}
2291590Srgrimes	argc -= optind;
2301590Srgrimes	argv += optind;
2311590Srgrimes
2321590Srgrimes	if (todo == 0)
2331590Srgrimes		todo = VMSTAT;
2341590Srgrimes
2351590Srgrimes	/*
2361590Srgrimes	 * Discard setgid privileges if not the running kernel so that bad
2371590Srgrimes	 * guys can't print interesting stuff from kernel memory.
2381590Srgrimes	 */
2391590Srgrimes	if (nlistf != NULL || memf != NULL)
2401590Srgrimes		setgid(getgid());
2411590Srgrimes
24228693Scharnier	kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
24328693Scharnier	if (kd == 0)
24428693Scharnier		errx(1, "kvm_openfiles: %s", errbuf);
24582664Sru	setgid(getgid());
2461590Srgrimes
2471590Srgrimes	if ((c = kvm_nlist(kd, namelist)) != 0) {
2481590Srgrimes		if (c > 0) {
24928693Scharnier			warnx("undefined symbols:");
2501590Srgrimes			for (c = 0;
25187690Smarkm			    c < (int)(sizeof(namelist)/sizeof(namelist[0]));
25287690Smarkm			    c++)
2531590Srgrimes				if (namelist[c].n_type == 0)
25481537Sken					(void)fprintf(stderr, " %s",
2551590Srgrimes					    namelist[c].n_name);
2561590Srgrimes			(void)fputc('\n', stderr);
2571590Srgrimes		} else
25828693Scharnier			warnx("kvm_nlist: %s", kvm_geterr(kd));
2591590Srgrimes		exit(1);
2601590Srgrimes	}
2611590Srgrimes
2621590Srgrimes	if (todo & VMSTAT) {
2631590Srgrimes		struct winsize winsize;
2641590Srgrimes
26543819Sken		/*
26643819Sken		 * Make sure that the userland devstat version matches the
26743819Sken		 * kernel devstat version.  If not, exit and print a
26843819Sken		 * message informing the user of his mistake.
26943819Sken		 */
270112284Sphk		if (devstat_checkversion(NULL) < 0)
27143819Sken			errx(1, "%s", devstat_errbuf);
27243819Sken
27343819Sken
2741590Srgrimes		argv = getdrivedata(argv);
2751590Srgrimes		winsize.ws_row = 0;
2761590Srgrimes		(void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize);
2771590Srgrimes		if (winsize.ws_row > 0)
2781590Srgrimes			winlines = winsize.ws_row;
2791590Srgrimes
2801590Srgrimes	}
2811590Srgrimes
2821590Srgrimes#define	BACKWARD_COMPATIBILITY
2831590Srgrimes#ifdef	BACKWARD_COMPATIBILITY
2841590Srgrimes	if (*argv) {
2851590Srgrimes		interval = atoi(*argv);
2861590Srgrimes		if (*++argv)
2871590Srgrimes			reps = atoi(*argv);
2881590Srgrimes	}
2891590Srgrimes#endif
2901590Srgrimes
2911590Srgrimes	if (interval) {
2921590Srgrimes		if (!reps)
2931590Srgrimes			reps = -1;
2941590Srgrimes	} else if (reps)
2951590Srgrimes		interval = 1;
2961590Srgrimes
2971590Srgrimes	if (todo & FORKSTAT)
2981590Srgrimes		doforkst();
2991590Srgrimes	if (todo & MEMSTAT)
3001590Srgrimes		domem();
30143962Sdillon	if (todo & ZMEMSTAT)
30243962Sdillon		dozmem();
3031590Srgrimes	if (todo & SUMSTAT)
3041590Srgrimes		dosum();
30530180Sdima#ifdef notyet
3061590Srgrimes	if (todo & TIMESTAT)
3071590Srgrimes		dotimes();
3081590Srgrimes#endif
3091590Srgrimes	if (todo & INTRSTAT)
3101590Srgrimes		dointr();
3111590Srgrimes	if (todo & VMSTAT)
3121590Srgrimes		dovmstat(interval, reps);
3131590Srgrimes	exit(0);
3141590Srgrimes}
3151590Srgrimes
3161590Srgrimeschar **
3171590Srgrimesgetdrivedata(argv)
3181590Srgrimes	char **argv;
3191590Srgrimes{
320112284Sphk	if ((num_devices = devstat_getnumdevs(NULL)) < 0)
32139230Sgibbs		errx(1, "%s", devstat_errbuf);
3221590Srgrimes
32339230Sgibbs	cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
32439230Sgibbs	last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
32539230Sgibbs	bzero(cur.dinfo, sizeof(struct devinfo));
32639230Sgibbs	bzero(last.dinfo, sizeof(struct devinfo));
32739230Sgibbs
328112284Sphk	if (devstat_getdevs(NULL, &cur) == -1)
32939230Sgibbs		errx(1, "%s", devstat_errbuf);
33039230Sgibbs
33139230Sgibbs	num_devices = cur.dinfo->numdevs;
33239230Sgibbs	generation = cur.dinfo->generation;
33339230Sgibbs
33439230Sgibbs	specified_devices = (char **)malloc(sizeof(char *));
33539230Sgibbs	for (num_devices_specified = 0; *argv; ++argv) {
3361590Srgrimes		if (isdigit(**argv))
3371590Srgrimes			break;
33839230Sgibbs		num_devices_specified++;
33939230Sgibbs		specified_devices = (char **)realloc(specified_devices,
34039230Sgibbs						     sizeof(char *) *
34139230Sgibbs						     num_devices_specified);
34239230Sgibbs		specified_devices[num_devices_specified - 1] = *argv;
3431590Srgrimes	}
34439230Sgibbs	dev_select = NULL;
34539230Sgibbs
34639372Sdillon	if (nflag == 0 && maxshowdevs < num_devices_specified)
34739372Sdillon			maxshowdevs = num_devices_specified;
34839372Sdillon
34939230Sgibbs	/*
35039230Sgibbs	 * People are generally only interested in disk statistics when
35139230Sgibbs	 * they're running vmstat.  So, that's what we're going to give
35239230Sgibbs	 * them if they don't specify anything by default.  We'll also give
35339230Sgibbs	 * them any other random devices in the system so that we get to
35439230Sgibbs	 * maxshowdevs devices, if that many devices exist.  If the user
35539230Sgibbs	 * specifies devices on the command line, either through a pattern
35639230Sgibbs	 * match or by naming them explicitly, we will give the user only
35739230Sgibbs	 * those devices.
35839230Sgibbs	 */
35939230Sgibbs	if ((num_devices_specified == 0) && (num_matches == 0)) {
360112284Sphk		if (devstat_buildmatch(da, &matches, &num_matches) != 0)
36139230Sgibbs			errx(1, "%s", devstat_errbuf);
36239230Sgibbs
36339230Sgibbs		select_mode = DS_SELECT_ADD;
36439230Sgibbs	} else
36539230Sgibbs		select_mode = DS_SELECT_ONLY;
36639230Sgibbs
36739230Sgibbs	/*
36839230Sgibbs	 * At this point, selectdevs will almost surely indicate that the
36939230Sgibbs	 * device list has changed, so we don't look for return values of 0
37039230Sgibbs	 * or 1.  If we get back -1, though, there is an error.
37139230Sgibbs	 */
372112284Sphk	if (devstat_selectdevs(&dev_select, &num_selected, &num_selections,
37339230Sgibbs		       &select_generation, generation, cur.dinfo->devices,
37439230Sgibbs		       num_devices, matches, num_matches, specified_devices,
37539230Sgibbs		       num_devices_specified, select_mode,
37639230Sgibbs		       maxshowdevs, 0) == -1)
37739230Sgibbs		errx(1, "%s", devstat_errbuf);
37839230Sgibbs
3791590Srgrimes	return(argv);
3801590Srgrimes}
3811590Srgrimes
3821590Srgrimeslong
3831590Srgrimesgetuptime()
3841590Srgrimes{
385101590Stmm	static struct timeval boottime;
386101590Stmm	static time_t now;
3871590Srgrimes	time_t uptime;
3881590Srgrimes
389101590Stmm	if (boottime.tv_sec == 0)
3901590Srgrimes		kread(X_BOOTTIME, &boottime, sizeof(boottime));
3911590Srgrimes	(void)time(&now);
392101590Stmm	uptime = now - boottime.tv_sec;
39328693Scharnier	if (uptime <= 0 || uptime > 60*60*24*365*10)
39428693Scharnier		errx(1, "time makes no sense; namelist must be wrong");
3951590Srgrimes	return(uptime);
3961590Srgrimes}
3971590Srgrimes
3981590Srgrimesint	hz, hdrcnt;
3991590Srgrimes
4001590Srgrimesvoid
4011590Srgrimesdovmstat(interval, reps)
4021590Srgrimes	u_int interval;
4031590Srgrimes	int reps;
4041590Srgrimes{
4051590Srgrimes	struct vmtotal total;
4061590Srgrimes	time_t uptime, halfuptime;
40739230Sgibbs	struct devinfo *tmp_dinfo;
40880551Stmm	int mib[2];
40980551Stmm	size_t size;
4101590Srgrimes
4111590Srgrimes	uptime = getuptime();
4121590Srgrimes	halfuptime = uptime / 2;
4131590Srgrimes	(void)signal(SIGCONT, needhdr);
4141590Srgrimes
4151590Srgrimes	if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0)
4161590Srgrimes		kread(X_STATHZ, &hz, sizeof(hz));
4171590Srgrimes	if (!hz)
4181590Srgrimes		kread(X_HZ, &hz, sizeof(hz));
4191590Srgrimes
4201590Srgrimes	for (hdrcnt = 1;;) {
4211590Srgrimes		if (!--hdrcnt)
4221590Srgrimes			printhdr();
42339230Sgibbs		kread(X_CPTIME, cur.cp_time, sizeof(cur.cp_time));
42439230Sgibbs
42539230Sgibbs		tmp_dinfo = last.dinfo;
42639230Sgibbs		last.dinfo = cur.dinfo;
42739230Sgibbs		cur.dinfo = tmp_dinfo;
428112288Sphk		last.snap_time = cur.snap_time;
42939230Sgibbs
43039230Sgibbs		/*
43139230Sgibbs		 * Here what we want to do is refresh our device stats.
43239230Sgibbs		 * getdevs() returns 1 when the device list has changed.
43339230Sgibbs		 * If the device list has changed, we want to go through
43439230Sgibbs		 * the selection process again, in case a device that we
43539230Sgibbs		 * were previously displaying has gone away.
43639230Sgibbs		 */
437112284Sphk		switch (devstat_getdevs(NULL, &cur)) {
43839230Sgibbs		case -1:
43939230Sgibbs			errx(1, "%s", devstat_errbuf);
44039230Sgibbs			break;
44139230Sgibbs		case 1: {
44239230Sgibbs			int retval;
44339230Sgibbs
44439230Sgibbs			num_devices = cur.dinfo->numdevs;
44539230Sgibbs			generation = cur.dinfo->generation;
44639230Sgibbs
447112284Sphk			retval = devstat_selectdevs(&dev_select, &num_selected,
44839230Sgibbs					    &num_selections, &select_generation,
44939230Sgibbs					    generation, cur.dinfo->devices,
45039230Sgibbs					    num_devices, matches, num_matches,
45139230Sgibbs					    specified_devices,
45239230Sgibbs					    num_devices_specified, select_mode,
45339230Sgibbs					    maxshowdevs, 0);
45439230Sgibbs			switch (retval) {
45539230Sgibbs			case -1:
45639230Sgibbs				errx(1, "%s", devstat_errbuf);
45739230Sgibbs				break;
45839230Sgibbs			case 1:
45939230Sgibbs				printhdr();
46039230Sgibbs				break;
46139230Sgibbs			default:
46239230Sgibbs				break;
46339230Sgibbs			}
46439230Sgibbs		}
46539230Sgibbs		default:
46639230Sgibbs			break;
46739230Sgibbs		}
46839230Sgibbs
4691590Srgrimes		kread(X_SUM, &sum, sizeof(sum));
4701590Srgrimes		size = sizeof(total);
4711590Srgrimes		mib[0] = CTL_VM;
472109097Sdillon		mib[1] = VM_TOTAL;
4731590Srgrimes		if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
47481537Sken			(void)printf("Can't get kerninfo: %s\n",
47581537Sken				     strerror(errno));
4761590Srgrimes			bzero(&total, sizeof(total));
4771590Srgrimes		}
47878672Sschweikh		(void)printf("%2d %1d %1d",
4791590Srgrimes		    total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
48072887Salfred#define vmstat_pgtok(a) ((a) * sum.v_page_size >> 10)
4811590Srgrimes#define	rate(x)	(((x) + halfuptime) / uptime)	/* round */
48281537Sken		(void)printf(" %7ld %6ld ", (long)vmstat_pgtok(total.t_avm),
48381537Sken			     (long)vmstat_pgtok(total.t_free));
48437453Sbde		(void)printf("%4lu ",
48537453Sbde		    (u_long)rate(sum.v_vm_faults - osum.v_vm_faults));
4861590Srgrimes		(void)printf("%3lu ",
48737453Sbde		    (u_long)rate(sum.v_reactivated - osum.v_reactivated));
48837453Sbde		(void)printf("%3lu ",
48937453Sbde		    (u_long)rate(sum.v_swapin + sum.v_vnodein -
4903659Sdg		    (osum.v_swapin + osum.v_vnodein)));
49137453Sbde		(void)printf("%3lu ",
49237453Sbde		    (u_long)rate(sum.v_swapout + sum.v_vnodeout -
4933693Sdg		    (osum.v_swapout + osum.v_vnodeout)));
49437453Sbde		(void)printf("%3lu ",
49537453Sbde		    (u_long)rate(sum.v_tfree - osum.v_tfree));
49637453Sbde		(void)printf("%3lu ",
49737453Sbde		    (u_long)rate(sum.v_pdpages - osum.v_pdpages));
49839230Sgibbs		devstats();
4991590Srgrimes		(void)printf("%4lu %4lu %3lu ",
50037453Sbde		    (u_long)rate(sum.v_intr - osum.v_intr),
50137453Sbde		    (u_long)rate(sum.v_syscall - osum.v_syscall),
50237453Sbde		    (u_long)rate(sum.v_swtch - osum.v_swtch));
5031590Srgrimes		cpustats();
5041590Srgrimes		(void)printf("\n");
5051590Srgrimes		(void)fflush(stdout);
5061590Srgrimes		if (reps >= 0 && --reps <= 0)
5071590Srgrimes			break;
5081590Srgrimes		osum = sum;
5091590Srgrimes		uptime = interval;
5101590Srgrimes		/*
5111590Srgrimes		 * We round upward to avoid losing low-frequency events
5121590Srgrimes		 * (i.e., >= 1 per interval but < 1 per second).
5131590Srgrimes		 */
5143659Sdg		if (interval != 1)
5153659Sdg			halfuptime = (uptime + 1) / 2;
5163659Sdg		else
5173659Sdg			halfuptime = 0;
5181590Srgrimes		(void)sleep(interval);
5191590Srgrimes	}
5201590Srgrimes}
5211590Srgrimes
52228693Scharniervoid
5231590Srgrimesprinthdr()
5241590Srgrimes{
52543822Sken	int i, num_shown;
5261590Srgrimes
52743822Sken	num_shown = (num_selected < maxshowdevs) ? num_selected : maxshowdevs;
52878672Sschweikh	(void)printf(" procs      memory      page%*s", 19, "");
52943822Sken	if (num_shown > 1)
53043822Sken		(void)printf(" disks %*s", num_shown * 4 - 7, "");
53143822Sken	else if (num_shown == 1)
53243822Sken		(void)printf("disk");
53343822Sken	(void)printf("   faults      cpu\n");
53478672Sschweikh	(void)printf(" r b w     avm    fre  flt  re  pi  po  fr  sr ");
53539230Sgibbs	for (i = 0; i < num_devices; i++)
53639230Sgibbs		if ((dev_select[i].selected)
53739230Sgibbs		 && (dev_select[i].selected <= maxshowdevs))
53839230Sgibbs			(void)printf("%c%c%d ", dev_select[i].device_name[0],
53939230Sgibbs				     dev_select[i].device_name[1],
54039230Sgibbs				     dev_select[i].unit_number);
5411590Srgrimes	(void)printf("  in   sy  cs us sy id\n");
5421590Srgrimes	hdrcnt = winlines - 2;
5431590Srgrimes}
5441590Srgrimes
5451590Srgrimes/*
5461590Srgrimes * Force a header to be prepended to the next output.
5471590Srgrimes */
5481590Srgrimesvoid
54987690Smarkmneedhdr(dummy)
55087690Smarkm	int dummy __unused;
5511590Srgrimes{
5521590Srgrimes
5531590Srgrimes	hdrcnt = 1;
5541590Srgrimes}
5551590Srgrimes
55630180Sdima#ifdef notyet
5571590Srgrimesvoid
5581590Srgrimesdotimes()
5591590Srgrimes{
5601590Srgrimes	u_int pgintime, rectime;
5611590Srgrimes
5621590Srgrimes	kread(X_REC, &rectime, sizeof(rectime));
5631590Srgrimes	kread(X_PGIN, &pgintime, sizeof(pgintime));
5641590Srgrimes	kread(X_SUM, &sum, sizeof(sum));
5651590Srgrimes	(void)printf("%u reclaims, %u total time (usec)\n",
5661590Srgrimes	    sum.v_pgrec, rectime);
5671590Srgrimes	(void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec);
5681590Srgrimes	(void)printf("\n");
5691590Srgrimes	(void)printf("%u page ins, %u total time (msec)\n",
5701590Srgrimes	    sum.v_pgin, pgintime / 10);
5711590Srgrimes	(void)printf("average: %8.1f msec / page in\n",
5721590Srgrimes	    pgintime / (sum.v_pgin * 10.0));
5731590Srgrimes}
5741590Srgrimes#endif
5751590Srgrimes
57628693Scharnierlong
5771590Srgrimespct(top, bot)
5781590Srgrimes	long top, bot;
5791590Srgrimes{
5801590Srgrimes	long ans;
5811590Srgrimes
5821590Srgrimes	if (bot == 0)
5831590Srgrimes		return(0);
5841590Srgrimes	ans = (quad_t)top * 100 / bot;
5851590Srgrimes	return (ans);
5861590Srgrimes}
5871590Srgrimes
5881590Srgrimes#define	PCT(top, bot) pct((long)(top), (long)(bot))
5891590Srgrimes
5901590Srgrimesvoid
5911590Srgrimesdosum()
5921590Srgrimes{
59387690Smarkm	struct nchstats lnchstats;
5941590Srgrimes	long nchtotal;
5951590Srgrimes
5961590Srgrimes	kread(X_SUM, &sum, sizeof(sum));
5971590Srgrimes	(void)printf("%9u cpu context switches\n", sum.v_swtch);
5981590Srgrimes	(void)printf("%9u device interrupts\n", sum.v_intr);
5991590Srgrimes	(void)printf("%9u software interrupts\n", sum.v_soft);
6001590Srgrimes	(void)printf("%9u traps\n", sum.v_trap);
6011590Srgrimes	(void)printf("%9u system calls\n", sum.v_syscall);
60271429Sume	(void)printf("%9u kernel threads created\n", sum.v_kthreads);
60371429Sume	(void)printf("%9u  fork() calls\n", sum.v_forks);
60471429Sume	(void)printf("%9u vfork() calls\n", sum.v_vforks);
60571429Sume	(void)printf("%9u rfork() calls\n", sum.v_rforks);
6063659Sdg	(void)printf("%9u swap pager pageins\n", sum.v_swapin);
6073693Sdg	(void)printf("%9u swap pager pages paged in\n", sum.v_swappgsin);
6083659Sdg	(void)printf("%9u swap pager pageouts\n", sum.v_swapout);
6093659Sdg	(void)printf("%9u swap pager pages paged out\n", sum.v_swappgsout);
6103659Sdg	(void)printf("%9u vnode pager pageins\n", sum.v_vnodein);
6113693Sdg	(void)printf("%9u vnode pager pages paged in\n", sum.v_vnodepgsin);
6123659Sdg	(void)printf("%9u vnode pager pageouts\n", sum.v_vnodeout);
6133659Sdg	(void)printf("%9u vnode pager pages paged out\n", sum.v_vnodepgsout);
6143693Sdg	(void)printf("%9u page daemon wakeups\n", sum.v_pdwakeups);
6153693Sdg	(void)printf("%9u pages examined by the page daemon\n", sum.v_pdpages);
6161590Srgrimes	(void)printf("%9u pages reactivated\n", sum.v_reactivated);
6177351Sdg	(void)printf("%9u copy-on-write faults\n", sum.v_cow_faults);
61834214Sdyson	(void)printf("%9u copy-on-write optimized faults\n", sum.v_cow_optim);
6197351Sdg	(void)printf("%9u zero fill pages zeroed\n", sum.v_zfod);
62034214Sdyson	(void)printf("%9u zero fill pages prezeroed\n", sum.v_ozfod);
6211590Srgrimes	(void)printf("%9u intransit blocking page faults\n", sum.v_intrans);
6221590Srgrimes	(void)printf("%9u total VM faults taken\n", sum.v_vm_faults);
62371429Sume	(void)printf("%9u pages affected by kernel thread creation\n", sum.v_kthreadpages);
62471429Sume	(void)printf("%9u pages affected by  fork()\n", sum.v_forkpages);
62571429Sume	(void)printf("%9u pages affected by vfork()\n", sum.v_vforkpages);
62671429Sume	(void)printf("%9u pages affected by rfork()\n", sum.v_rforkpages);
6273693Sdg	(void)printf("%9u pages freed\n", sum.v_tfree);
6281590Srgrimes	(void)printf("%9u pages freed by daemon\n", sum.v_dfree);
6291590Srgrimes	(void)printf("%9u pages freed by exiting processes\n", sum.v_pfree);
6301590Srgrimes	(void)printf("%9u pages active\n", sum.v_active_count);
6311590Srgrimes	(void)printf("%9u pages inactive\n", sum.v_inactive_count);
6325463Sdg	(void)printf("%9u pages in VM cache\n", sum.v_cache_count);
6333693Sdg	(void)printf("%9u pages wired down\n", sum.v_wire_count);
6343693Sdg	(void)printf("%9u pages free\n", sum.v_free_count);
6351590Srgrimes	(void)printf("%9u bytes per page\n", sum.v_page_size);
63687690Smarkm	kread(X_NCHSTATS, &lnchstats, sizeof(lnchstats));
63787690Smarkm	nchtotal = lnchstats.ncs_goodhits + lnchstats.ncs_neghits +
63887690Smarkm	    lnchstats.ncs_badhits + lnchstats.ncs_falsehits +
63987690Smarkm	    lnchstats.ncs_miss + lnchstats.ncs_long;
6401590Srgrimes	(void)printf("%9ld total name lookups\n", nchtotal);
6411590Srgrimes	(void)printf(
64228693Scharnier	    "%9s cache hits (%ld%% pos + %ld%% neg) system %ld%% per-directory\n",
64387690Smarkm	    "", PCT(lnchstats.ncs_goodhits, nchtotal),
64487690Smarkm	    PCT(lnchstats.ncs_neghits, nchtotal),
64587690Smarkm	    PCT(lnchstats.ncs_pass2, nchtotal));
64628693Scharnier	(void)printf("%9s deletions %ld%%, falsehits %ld%%, toolong %ld%%\n", "",
64787690Smarkm	    PCT(lnchstats.ncs_badhits, nchtotal),
64887690Smarkm	    PCT(lnchstats.ncs_falsehits, nchtotal),
64987690Smarkm	    PCT(lnchstats.ncs_long, nchtotal));
6501590Srgrimes}
6511590Srgrimes
6521590Srgrimesvoid
6531590Srgrimesdoforkst()
6541590Srgrimes{
6551590Srgrimes
656113460Stjr	kread(X_SUM, &sum, sizeof(sum));
6571590Srgrimes	(void)printf("%d forks, %d pages, average %.2f\n",
658113460Stjr	    sum.v_forks, sum.v_forkpages,
659113460Stjr	    sum.v_forks == 0 ? 0.0 :
660113460Stjr	    (double)sum.v_forkpages / sum.v_forks);
6611590Srgrimes	(void)printf("%d vforks, %d pages, average %.2f\n",
662113460Stjr	    sum.v_vforks, sum.v_vforkpages,
663113460Stjr	    sum.v_vforks == 0 ? 0.0 :
664113460Stjr	    (double)sum.v_vforkpages / sum.v_vforks);
665113460Stjr	(void)printf("%d rforks, %d pages, average %.2f\n",
666113460Stjr	    sum.v_rforks, sum.v_rforkpages,
667113460Stjr	    sum.v_rforks == 0 ? 0.0 :
668113460Stjr	    (double)sum.v_rforkpages / sum.v_rforks);
6691590Srgrimes}
6701590Srgrimes
67139230Sgibbsstatic void
67239230Sgibbsdevstats()
6731590Srgrimes{
67487690Smarkm	int dn, state;
67539230Sgibbs	long double transfers_per_second;
67639230Sgibbs	long double busy_seconds;
6771590Srgrimes	long tmp;
67839230Sgibbs
6791590Srgrimes	for (state = 0; state < CPUSTATES; ++state) {
68039230Sgibbs		tmp = cur.cp_time[state];
68139230Sgibbs		cur.cp_time[state] -= last.cp_time[state];
68239230Sgibbs		last.cp_time[state] = tmp;
6831590Srgrimes	}
68439230Sgibbs
685112288Sphk	busy_seconds = cur.snap_time - last.snap_time;
68639230Sgibbs
68739230Sgibbs	for (dn = 0; dn < num_devices; dn++) {
68839230Sgibbs		int di;
68939230Sgibbs
69039230Sgibbs		if ((dev_select[dn].selected == 0)
69139230Sgibbs		 || (dev_select[dn].selected > maxshowdevs))
6921590Srgrimes			continue;
69339230Sgibbs
69439230Sgibbs		di = dev_select[dn].position;
69539230Sgibbs
69681537Sken		if (devstat_compute_statistics(&cur.dinfo->devices[di],
69781537Sken		    &last.dinfo->devices[di], busy_seconds,
69881537Sken		    DSM_TRANSFERS_PER_SECOND, &transfers_per_second,
69981537Sken		    DSM_NONE) != 0)
70039230Sgibbs			errx(1, "%s", devstat_errbuf);
70139230Sgibbs
70281537Sken		(void)printf("%3.0Lf ", transfers_per_second);
7031590Srgrimes	}
7041590Srgrimes}
7051590Srgrimes
7061590Srgrimesvoid
7071590Srgrimescpustats()
7081590Srgrimes{
70987690Smarkm	int state;
71087690Smarkm	double lpct, total;
7111590Srgrimes
7121590Srgrimes	total = 0;
7131590Srgrimes	for (state = 0; state < CPUSTATES; ++state)
71439230Sgibbs		total += cur.cp_time[state];
7151590Srgrimes	if (total)
71687690Smarkm		lpct = 100.0 / total;
7171590Srgrimes	else
71887690Smarkm		lpct = 0.0;
71939230Sgibbs	(void)printf("%2.0f ", (cur.cp_time[CP_USER] +
72087690Smarkm				cur.cp_time[CP_NICE]) * lpct);
72139230Sgibbs	(void)printf("%2.0f ", (cur.cp_time[CP_SYS] +
72287690Smarkm				cur.cp_time[CP_INTR]) * lpct);
72387690Smarkm	(void)printf("%2.0f", cur.cp_time[CP_IDLE] * lpct);
7241590Srgrimes}
7251590Srgrimes
7261590Srgrimesvoid
7271590Srgrimesdointr()
7281590Srgrimes{
72987690Smarkm	u_long *intrcnt, uptime;
73087690Smarkm	u_int64_t inttotal;
73187690Smarkm	int nintr, inamlen;
732121626Sjmg	int i, istrnamlen;
733121626Sjmg	size_t clen;
734121626Sjmg	char *intrname, *tintrname;
7351590Srgrimes
7361590Srgrimes	uptime = getuptime();
7371590Srgrimes	nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value;
7381590Srgrimes	inamlen =
7391590Srgrimes	    namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value;
7401590Srgrimes	intrcnt = malloc((size_t)nintr);
7411590Srgrimes	intrname = malloc((size_t)inamlen);
74228693Scharnier	if (intrcnt == NULL || intrname == NULL)
74328693Scharnier		errx(1, "malloc");
7441590Srgrimes	kread(X_INTRCNT, intrcnt, (size_t)nintr);
7451590Srgrimes	kread(X_INTRNAMES, intrname, (size_t)inamlen);
746122300Sjmg	nintr /= sizeof(u_long);
747121626Sjmg	tintrname = intrname;
748122300Sjmg	istrnamlen = 12;
749121626Sjmg	for (i = 0; i < nintr; i++) {
750121626Sjmg		clen = strlen(tintrname);
751121626Sjmg		if (clen > istrnamlen)
752121626Sjmg			istrnamlen = clen;
753121626Sjmg		tintrname += clen + 1;
754121626Sjmg	}
755121626Sjmg	(void)printf("%-*s %20s %10s\n", istrnamlen, "interrupt", "total",
756121626Sjmg	    "rate");
7571590Srgrimes	inttotal = 0;
7581590Srgrimes	while (--nintr >= 0) {
7591590Srgrimes		if (*intrcnt)
760121626Sjmg			(void)printf("%-*s %20lu %10lu\n", istrnamlen, intrname,
7611590Srgrimes			    *intrcnt, *intrcnt / uptime);
7621590Srgrimes		intrname += strlen(intrname) + 1;
7631590Srgrimes		inttotal += *intrcnt++;
7641590Srgrimes	}
765121626Sjmg	(void)printf("%-*s %20llu %10llu\n", istrnamlen, "Total", inttotal,
76649107Sn_hibma			inttotal / (u_int64_t) uptime);
7671590Srgrimes}
7681590Srgrimes
76994729Sjeffvoid
77094729Sjeffdomem(void)
77194729Sjeff{
77294729Sjeff	dosysctl("kern.malloc");
77394729Sjeff}
77446852Simp
7751590Srgrimesvoid
77694729Sjeffdozmem(void)
7771590Srgrimes{
77894729Sjeff	dosysctl("vm.zone");
7791590Srgrimes}
7801590Srgrimes
78143962Sdillonvoid
78294729Sjeffdosysctl(char *name)
78343962Sdillon{
78471404Sdes	char *buf;
78571404Sdes	size_t bufsize;
78643962Sdillon
78771404Sdes	buf = NULL;
78871404Sdes	bufsize = 1024;
78971404Sdes	for (;;) {
79071404Sdes		if ((buf = realloc(buf, bufsize)) == NULL)
79171404Sdes			err(1, "realloc()");
79294729Sjeff		if (sysctlbyname(name, buf, &bufsize, 0, NULL) == 0)
79343962Sdillon			break;
79471404Sdes		if (errno != ENOMEM)
795122300Sjmg			err(1, "sysctlbyname()");
79671404Sdes		bufsize *= 2;
79743962Sdillon	}
79871404Sdes	buf[bufsize] = '\0'; /* play it safe */
79971404Sdes	(void)printf("%s\n\n", buf);
80071404Sdes	free(buf);
80143962Sdillon}
80243962Sdillon
8031590Srgrimes/*
8041590Srgrimes * kread reads something from the kernel, given its nlist index.
8051590Srgrimes */
8061590Srgrimesvoid
8071590Srgrimeskread(nlx, addr, size)
8081590Srgrimes	int nlx;
8091590Srgrimes	void *addr;
8101590Srgrimes	size_t size;
8111590Srgrimes{
8121590Srgrimes	char *sym;
8131590Srgrimes
81440690Sjdp	if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
8151590Srgrimes		sym = namelist[nlx].n_name;
8161590Srgrimes		if (*sym == '_')
8171590Srgrimes			++sym;
81828693Scharnier		errx(1, "symbol %s not defined", sym);
8191590Srgrimes	}
820122300Sjmg	if ((size_t)kvm_read(kd, namelist[nlx].n_value, addr, size) != size) {
8211590Srgrimes		sym = namelist[nlx].n_name;
8221590Srgrimes		if (*sym == '_')
8231590Srgrimes			++sym;
82428693Scharnier		errx(1, "%s: %s", sym, kvm_geterr(kd));
8251590Srgrimes	}
8261590Srgrimes}
8271590Srgrimes
8281590Srgrimesvoid
8291590Srgrimesusage()
8301590Srgrimes{
83172887Salfred	(void)fprintf(stderr, "%s%s",
83272887Salfred		"usage: vmstat [-imsz] [-c count] [-M core] [-N system] [-w wait]\n",
83372887Salfred		"              [-n devs] [disks]\n");
8341590Srgrimes	exit(1);
8351590Srgrimes}
836