vmstat.c revision 34214
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
341590Srgrimes#ifndef lint
3528693Scharnierstatic const char copyright[] =
361590Srgrimes"@(#) Copyright (c) 1980, 1986, 1991, 1993\n\
371590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381590Srgrimes#endif /* not lint */
391590Srgrimes
401590Srgrimes#ifndef lint
4128693Scharnier#if 0
421590Srgrimesstatic char sccsid[] = "@(#)vmstat.c	8.1 (Berkeley) 6/6/93";
4328693Scharnier#endif
4428693Scharnierstatic const char rcsid[] =
4534214Sdyson	"$Id: vmstat.c,v 1.22 1997/12/05 19:28:28 bde Exp $";
461590Srgrimes#endif /* not lint */
471590Srgrimes
481590Srgrimes#include <sys/param.h>
491590Srgrimes#include <sys/time.h>
501590Srgrimes#include <sys/proc.h>
511590Srgrimes#include <sys/dkstat.h>
521590Srgrimes#include <sys/buf.h>
5312811Sbde#include <sys/uio.h>
541590Srgrimes#include <sys/namei.h>
551590Srgrimes#include <sys/malloc.h>
561590Srgrimes#include <sys/signal.h>
571590Srgrimes#include <sys/fcntl.h>
581590Srgrimes#include <sys/ioctl.h>
591590Srgrimes#include <sys/sysctl.h>
6012804Speter#include <sys/vmmeter.h>
6112811Sbde
6212811Sbde#include <vm/vm_param.h>
6312811Sbde
6428693Scharnier#include <ctype.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
781590Srgrimesstruct nlist namelist[] = {
791590Srgrimes#define	X_CPTIME	0
801590Srgrimes	{ "_cp_time" },
811590Srgrimes#define	X_DK_NDRIVE	1
821590Srgrimes	{ "_dk_ndrive" },
831590Srgrimes#define X_SUM		2
841590Srgrimes	{ "_cnt" },
851590Srgrimes#define	X_BOOTTIME	3
861590Srgrimes	{ "_boottime" },
871590Srgrimes#define	X_DKXFER	4
881590Srgrimes	{ "_dk_xfer" },
891590Srgrimes#define X_HZ		5
901590Srgrimes	{ "_hz" },
911590Srgrimes#define X_STATHZ	6
921590Srgrimes	{ "_stathz" },
931590Srgrimes#define X_NCHSTATS	7
941590Srgrimes	{ "_nchstats" },
951590Srgrimes#define	X_INTRNAMES	8
961590Srgrimes	{ "_intrnames" },
971590Srgrimes#define	X_EINTRNAMES	9
981590Srgrimes	{ "_eintrnames" },
991590Srgrimes#define	X_INTRCNT	10
1001590Srgrimes	{ "_intrcnt" },
1011590Srgrimes#define	X_EINTRCNT	11
1021590Srgrimes	{ "_eintrcnt" },
10330279Sphk#define	X_KMEMSTATISTICS	12
10430279Sphk	{ "_kmemstatistics" },
1051590Srgrimes#define	X_KMEMBUCKETS	13
1061590Srgrimes	{ "_bucket" },
10730180Sdima#ifdef notyet
1081590Srgrimes#define	X_DEFICIT	14
1091590Srgrimes	{ "_deficit" },
1101590Srgrimes#define	X_FORKSTAT	15
1111590Srgrimes	{ "_forkstat" },
1121590Srgrimes#define X_REC		16
1131590Srgrimes	{ "_rectime" },
1141590Srgrimes#define X_PGIN		17
1151590Srgrimes	{ "_pgintime" },
1161590Srgrimes#define	X_XSTATS	18
1171590Srgrimes	{ "_xstats" },
1181620Srgrimes#define X_END		19
1191590Srgrimes#else
1201590Srgrimes#define X_END		14
1211590Srgrimes#endif
1221590Srgrimes#if defined(hp300) || defined(luna68k)
1231590Srgrimes#define	X_HPDINIT	(X_END)
1241590Srgrimes	{ "_hp_dinit" },
1251590Srgrimes#endif
1261620Srgrimes#if defined(i386)
1273642Swollman#define X_DK_NAMES	(X_END)
1283642Swollman	{ "_dk_names" },
1291620Srgrimes#endif
1301590Srgrimes#ifdef mips
1311590Srgrimes#define	X_SCSI_DINIT	(X_END)
1321590Srgrimes	{ "_scsi_dinit" },
1331590Srgrimes#endif
1341590Srgrimes#ifdef tahoe
1351590Srgrimes#define	X_VBDINIT	(X_END)
1361590Srgrimes	{ "_vbdinit" },
1371590Srgrimes#define	X_CKEYSTATS	(X_END+1)
1381590Srgrimes	{ "_ckeystats" },
1391590Srgrimes#define	X_DKEYSTATS	(X_END+2)
1401590Srgrimes	{ "_dkeystats" },
1411590Srgrimes#endif
1421590Srgrimes#ifdef vax
1431590Srgrimes#define X_MBDINIT	(X_END)
1441590Srgrimes	{ "_mbdinit" },
1451590Srgrimes#define X_UBDINIT	(X_END+1)
1461590Srgrimes	{ "_ubdinit" },
1471590Srgrimes#endif
1481590Srgrimes	{ "" },
1491590Srgrimes};
1501590Srgrimes
1511590Srgrimesstruct _disk {
1521590Srgrimes	long time[CPUSTATES];
1531590Srgrimes	long *xfer;
1541590Srgrimes} cur, last;
1551590Srgrimes
1561590Srgrimesstruct	vmmeter sum, osum;
1571590Srgrimeschar	**dr_name;
1581590Srgrimesint	*dr_select, dk_ndrive, ndrives;
1591590Srgrimes
1601590Srgrimesint	winlines = 20;
1611590Srgrimes
1621590Srgrimeskvm_t *kd;
1631590Srgrimes
1641590Srgrimes#define	FORKSTAT	0x01
1651590Srgrimes#define	INTRSTAT	0x02
1661590Srgrimes#define	MEMSTAT		0x04
1671590Srgrimes#define	SUMSTAT		0x08
1681590Srgrimes#define	TIMESTAT	0x10
1691590Srgrimes#define	VMSTAT		0x20
1701590Srgrimes
1711590Srgrimes#include "names.c"			/* disk names -- machine dependent */
1721590Srgrimes
1731590Srgrimesvoid	cpustats(), dkstats(), dointr(), domem(), dosum();
1741590Srgrimesvoid	dovmstat(), kread(), usage();
17530180Sdima#ifdef notyet
1761590Srgrimesvoid	dotimes(), doforkst();
1771590Srgrimes#endif
17828693Scharniervoid printhdr __P((void));
1791590Srgrimes
18028693Scharnierint
1811590Srgrimesmain(argc, argv)
1821590Srgrimes	register int argc;
1831590Srgrimes	register char **argv;
1841590Srgrimes{
1851590Srgrimes	register int c, todo;
1861590Srgrimes	u_int interval;
1871590Srgrimes	int reps;
1881590Srgrimes	char *memf, *nlistf;
1891590Srgrimes        char errbuf[_POSIX2_LINE_MAX];
1901590Srgrimes
1911590Srgrimes	memf = nlistf = NULL;
1921590Srgrimes	interval = reps = todo = 0;
19324360Simp	while ((c = getopt(argc, argv, "c:fiM:mN:stw:")) != -1) {
1941590Srgrimes		switch (c) {
1951590Srgrimes		case 'c':
1961590Srgrimes			reps = atoi(optarg);
1971590Srgrimes			break;
1981590Srgrimes		case 'f':
19930180Sdima#ifdef notyet
2001590Srgrimes			todo |= FORKSTAT;
20130180Sdima#else
20230180Sdima			errx(EX_USAGE, "sorry, -f is not (re)implemented yet");
20330180Sdima#endif
2041590Srgrimes			break;
2051590Srgrimes		case 'i':
2061590Srgrimes			todo |= INTRSTAT;
2071590Srgrimes			break;
2081590Srgrimes		case 'M':
2091590Srgrimes			memf = optarg;
2101590Srgrimes			break;
2111590Srgrimes		case 'm':
2121590Srgrimes			todo |= MEMSTAT;
2131590Srgrimes			break;
2141590Srgrimes		case 'N':
2151590Srgrimes			nlistf = optarg;
2161590Srgrimes			break;
2171590Srgrimes		case 's':
2181590Srgrimes			todo |= SUMSTAT;
2191590Srgrimes			break;
2201590Srgrimes		case 't':
22130180Sdima#ifdef notyet
2221590Srgrimes			todo |= TIMESTAT;
22330180Sdima#else
22430180Sdima			errx(EX_USAGE, "sorry, -t is not (re)implemented yet");
22530180Sdima#endif
2261590Srgrimes			break;
2271590Srgrimes		case 'w':
2281590Srgrimes			interval = atoi(optarg);
2291590Srgrimes			break;
2301590Srgrimes		case '?':
2311590Srgrimes		default:
2321590Srgrimes			usage();
2331590Srgrimes		}
2341590Srgrimes	}
2351590Srgrimes	argc -= optind;
2361590Srgrimes	argv += optind;
2371590Srgrimes
2381590Srgrimes	if (todo == 0)
2391590Srgrimes		todo = VMSTAT;
2401590Srgrimes
2411590Srgrimes	/*
2421590Srgrimes	 * Discard setgid privileges if not the running kernel so that bad
2431590Srgrimes	 * guys can't print interesting stuff from kernel memory.
2441590Srgrimes	 */
2451590Srgrimes	if (nlistf != NULL || memf != NULL)
2461590Srgrimes		setgid(getgid());
2471590Srgrimes
24828693Scharnier	kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
24928693Scharnier	if (kd == 0)
25028693Scharnier		errx(1, "kvm_openfiles: %s", errbuf);
2511590Srgrimes
2521590Srgrimes	if ((c = kvm_nlist(kd, namelist)) != 0) {
2531590Srgrimes		if (c > 0) {
25428693Scharnier			warnx("undefined symbols:");
2551590Srgrimes			for (c = 0;
2561590Srgrimes			    c < sizeof(namelist)/sizeof(namelist[0]); c++)
2571590Srgrimes				if (namelist[c].n_type == 0)
2581590Srgrimes					fprintf(stderr, " %s",
2591590Srgrimes					    namelist[c].n_name);
2601590Srgrimes			(void)fputc('\n', stderr);
2611590Srgrimes		} else
26228693Scharnier			warnx("kvm_nlist: %s", kvm_geterr(kd));
2631590Srgrimes		exit(1);
2641590Srgrimes	}
2651590Srgrimes
2661590Srgrimes	if (todo & VMSTAT) {
2671590Srgrimes		char **getdrivedata();
2681590Srgrimes		struct winsize winsize;
2691590Srgrimes
2701590Srgrimes		argv = getdrivedata(argv);
2711590Srgrimes		winsize.ws_row = 0;
2721590Srgrimes		(void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize);
2731590Srgrimes		if (winsize.ws_row > 0)
2741590Srgrimes			winlines = winsize.ws_row;
2751590Srgrimes
2761590Srgrimes	}
2771590Srgrimes
2781590Srgrimes#define	BACKWARD_COMPATIBILITY
2791590Srgrimes#ifdef	BACKWARD_COMPATIBILITY
2801590Srgrimes	if (*argv) {
2811590Srgrimes		interval = atoi(*argv);
2821590Srgrimes		if (*++argv)
2831590Srgrimes			reps = atoi(*argv);
2841590Srgrimes	}
2851590Srgrimes#endif
2861590Srgrimes
2871590Srgrimes	if (interval) {
2881590Srgrimes		if (!reps)
2891590Srgrimes			reps = -1;
2901590Srgrimes	} else if (reps)
2911590Srgrimes		interval = 1;
2921590Srgrimes
29330180Sdima#ifdef notyet
2941590Srgrimes	if (todo & FORKSTAT)
2951590Srgrimes		doforkst();
2961590Srgrimes#endif
2971590Srgrimes	if (todo & MEMSTAT)
2981590Srgrimes		domem();
2991590Srgrimes	if (todo & SUMSTAT)
3001590Srgrimes		dosum();
30130180Sdima#ifdef notyet
3021590Srgrimes	if (todo & TIMESTAT)
3031590Srgrimes		dotimes();
3041590Srgrimes#endif
3051590Srgrimes	if (todo & INTRSTAT)
3061590Srgrimes		dointr();
3071590Srgrimes	if (todo & VMSTAT)
3081590Srgrimes		dovmstat(interval, reps);
3091590Srgrimes	exit(0);
3101590Srgrimes}
3111590Srgrimes
3121590Srgrimeschar **
3131590Srgrimesgetdrivedata(argv)
3141590Srgrimes	char **argv;
3151590Srgrimes{
3161590Srgrimes	register int i;
3171590Srgrimes	register char **cp;
3181590Srgrimes	char buf[30];
3191590Srgrimes
3201590Srgrimes	kread(X_DK_NDRIVE, &dk_ndrive, sizeof(dk_ndrive));
32128693Scharnier	if (dk_ndrive < 0)
32228693Scharnier		errx(1, "dk_ndrive %d", dk_ndrive);
3231590Srgrimes	dr_select = calloc((size_t)dk_ndrive, sizeof(int));
3241590Srgrimes	dr_name = calloc((size_t)dk_ndrive, sizeof(char *));
3251590Srgrimes	for (i = 0; i < dk_ndrive; i++)
3261590Srgrimes		dr_name[i] = NULL;
3271590Srgrimes	cur.xfer = calloc((size_t)dk_ndrive, sizeof(long));
3281590Srgrimes	last.xfer = calloc((size_t)dk_ndrive, sizeof(long));
3291590Srgrimes	if (!read_names())
3301590Srgrimes		exit (1);
3311590Srgrimes	for (i = 0; i < dk_ndrive; i++)
3321590Srgrimes		if (dr_name[i] == NULL) {
3331590Srgrimes			(void)sprintf(buf, "??%d", i);
3341590Srgrimes			dr_name[i] = strdup(buf);
3351590Srgrimes		}
3361590Srgrimes
3371590Srgrimes	/*
3381590Srgrimes	 * Choose drives to be displayed.  Priority goes to (in order) drives
3391590Srgrimes	 * supplied as arguments, default drives.  If everything isn't filled
3401590Srgrimes	 * in and there are drives not taken care of, display the first few
3411590Srgrimes	 * that fit.
3421590Srgrimes	 */
3431590Srgrimes#define BACKWARD_COMPATIBILITY
3441590Srgrimes	for (ndrives = 0; *argv; ++argv) {
3451590Srgrimes#ifdef	BACKWARD_COMPATIBILITY
3461590Srgrimes		if (isdigit(**argv))
3471590Srgrimes			break;
3481590Srgrimes#endif
3491590Srgrimes		for (i = 0; i < dk_ndrive; i++) {
3501590Srgrimes			if (strcmp(dr_name[i], *argv))
3511590Srgrimes				continue;
3521590Srgrimes			dr_select[i] = 1;
3531590Srgrimes			++ndrives;
3541590Srgrimes			break;
3551590Srgrimes		}
3561590Srgrimes	}
3571590Srgrimes	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
3581590Srgrimes		if (dr_select[i])
3591590Srgrimes			continue;
3601590Srgrimes		for (cp = defdrives; *cp; cp++)
3611590Srgrimes			if (strcmp(dr_name[i], *cp) == 0) {
3621590Srgrimes				dr_select[i] = 1;
3631590Srgrimes				++ndrives;
3641590Srgrimes				break;
3651590Srgrimes			}
3661590Srgrimes	}
3671590Srgrimes	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
3681590Srgrimes		if (dr_select[i])
3691590Srgrimes			continue;
3701590Srgrimes		dr_select[i] = 1;
3711590Srgrimes		++ndrives;
3721590Srgrimes	}
3731590Srgrimes	return(argv);
3741590Srgrimes}
3751590Srgrimes
3761590Srgrimeslong
3771590Srgrimesgetuptime()
3781590Srgrimes{
3791590Srgrimes	static time_t now, boottime;
3801590Srgrimes	time_t uptime;
3811590Srgrimes
3821590Srgrimes	if (boottime == 0)
3831590Srgrimes		kread(X_BOOTTIME, &boottime, sizeof(boottime));
3841590Srgrimes	(void)time(&now);
3851590Srgrimes	uptime = now - boottime;
38628693Scharnier	if (uptime <= 0 || uptime > 60*60*24*365*10)
38728693Scharnier		errx(1, "time makes no sense; namelist must be wrong");
3881590Srgrimes	return(uptime);
3891590Srgrimes}
3901590Srgrimes
3911590Srgrimesint	hz, hdrcnt;
3921590Srgrimes
3931590Srgrimesvoid
3941590Srgrimesdovmstat(interval, reps)
3951590Srgrimes	u_int interval;
3961590Srgrimes	int reps;
3971590Srgrimes{
3981590Srgrimes	struct vmtotal total;
3991590Srgrimes	time_t uptime, halfuptime;
4001590Srgrimes	void needhdr();
4011590Srgrimes	int mib[2], size;
4021590Srgrimes
4031590Srgrimes	uptime = getuptime();
4041590Srgrimes	halfuptime = uptime / 2;
4051590Srgrimes	(void)signal(SIGCONT, needhdr);
4061590Srgrimes
4071590Srgrimes	if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0)
4081590Srgrimes		kread(X_STATHZ, &hz, sizeof(hz));
4091590Srgrimes	if (!hz)
4101590Srgrimes		kread(X_HZ, &hz, sizeof(hz));
4111590Srgrimes
4121590Srgrimes	for (hdrcnt = 1;;) {
4131590Srgrimes		if (!--hdrcnt)
4141590Srgrimes			printhdr();
4151590Srgrimes		kread(X_CPTIME, cur.time, sizeof(cur.time));
4161590Srgrimes		kread(X_DKXFER, cur.xfer, sizeof(*cur.xfer) * dk_ndrive);
4171590Srgrimes		kread(X_SUM, &sum, sizeof(sum));
4181590Srgrimes		size = sizeof(total);
4191590Srgrimes		mib[0] = CTL_VM;
4201590Srgrimes		mib[1] = VM_METER;
4211590Srgrimes		if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
4221590Srgrimes			printf("Can't get kerninfo: %s\n", strerror(errno));
4231590Srgrimes			bzero(&total, sizeof(total));
4241590Srgrimes		}
4251590Srgrimes		(void)printf("%2d%2d%2d",
4261590Srgrimes		    total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
4271590Srgrimes#define pgtok(a) ((a) * sum.v_page_size >> 10)
4281590Srgrimes#define	rate(x)	(((x) + halfuptime) / uptime)	/* round */
42923952Sscrappy		(void)printf("%8ld%6ld ",
43028693Scharnier		    (long)pgtok(total.t_avm), (long)pgtok(total.t_free));
4313659Sdg		(void)printf("%4lu ", rate(sum.v_vm_faults - osum.v_vm_faults));
4321590Srgrimes		(void)printf("%3lu ",
4331590Srgrimes		    rate(sum.v_reactivated - osum.v_reactivated));
4343659Sdg		(void)printf("%3lu ", rate(sum.v_swapin + sum.v_vnodein -
4353659Sdg		    (osum.v_swapin + osum.v_vnodein)));
4363693Sdg		(void)printf("%3lu ", rate(sum.v_swapout + sum.v_vnodeout -
4373693Sdg		    (osum.v_swapout + osum.v_vnodeout)));
4383693Sdg		(void)printf("%3lu ", rate(sum.v_tfree - osum.v_tfree));
4393693Sdg		(void)printf("%3lu ", rate(sum.v_pdpages - osum.v_pdpages));
4401590Srgrimes		dkstats();
4411590Srgrimes		(void)printf("%4lu %4lu %3lu ",
4421590Srgrimes		    rate(sum.v_intr - osum.v_intr),
4431590Srgrimes		    rate(sum.v_syscall - osum.v_syscall),
4441590Srgrimes		    rate(sum.v_swtch - osum.v_swtch));
4451590Srgrimes		cpustats();
4461590Srgrimes		(void)printf("\n");
4471590Srgrimes		(void)fflush(stdout);
4481590Srgrimes		if (reps >= 0 && --reps <= 0)
4491590Srgrimes			break;
4501590Srgrimes		osum = sum;
4511590Srgrimes		uptime = interval;
4521590Srgrimes		/*
4531590Srgrimes		 * We round upward to avoid losing low-frequency events
4541590Srgrimes		 * (i.e., >= 1 per interval but < 1 per second).
4551590Srgrimes		 */
4563659Sdg		if (interval != 1)
4573659Sdg			halfuptime = (uptime + 1) / 2;
4583659Sdg		else
4593659Sdg			halfuptime = 0;
4601590Srgrimes		(void)sleep(interval);
4611590Srgrimes	}
4621590Srgrimes}
4631590Srgrimes
46428693Scharniervoid
4651590Srgrimesprinthdr()
4661590Srgrimes{
4671590Srgrimes	register int i;
4681590Srgrimes
46923952Sscrappy	(void)printf(" procs      memory     page%*s", 20, "");
4701590Srgrimes	if (ndrives > 1)
4711590Srgrimes		(void)printf("disks %*s  faults      cpu\n",
4721590Srgrimes		   ndrives * 3 - 6, "");
4731590Srgrimes	else
4741590Srgrimes		(void)printf("%*s  faults      cpu\n", ndrives * 3, "");
47523952Sscrappy	(void)printf(" r b w     avm   fre  flt  re  pi  po  fr  sr ");
4761590Srgrimes	for (i = 0; i < dk_ndrive; i++)
4771590Srgrimes		if (dr_select[i])
4781590Srgrimes			(void)printf("%c%c ", dr_name[i][0],
4791590Srgrimes			    dr_name[i][strlen(dr_name[i]) - 1]);
4801590Srgrimes	(void)printf("  in   sy  cs us sy id\n");
4811590Srgrimes	hdrcnt = winlines - 2;
4821590Srgrimes}
4831590Srgrimes
4841590Srgrimes/*
4851590Srgrimes * Force a header to be prepended to the next output.
4861590Srgrimes */
4871590Srgrimesvoid
4881590Srgrimesneedhdr()
4891590Srgrimes{
4901590Srgrimes
4911590Srgrimes	hdrcnt = 1;
4921590Srgrimes}
4931590Srgrimes
49430180Sdima#ifdef notyet
4951590Srgrimesvoid
4961590Srgrimesdotimes()
4971590Srgrimes{
4981590Srgrimes	u_int pgintime, rectime;
4991590Srgrimes
5001590Srgrimes	kread(X_REC, &rectime, sizeof(rectime));
5011590Srgrimes	kread(X_PGIN, &pgintime, sizeof(pgintime));
5021590Srgrimes	kread(X_SUM, &sum, sizeof(sum));
5031590Srgrimes	(void)printf("%u reclaims, %u total time (usec)\n",
5041590Srgrimes	    sum.v_pgrec, rectime);
5051590Srgrimes	(void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec);
5061590Srgrimes	(void)printf("\n");
5071590Srgrimes	(void)printf("%u page ins, %u total time (msec)\n",
5081590Srgrimes	    sum.v_pgin, pgintime / 10);
5091590Srgrimes	(void)printf("average: %8.1f msec / page in\n",
5101590Srgrimes	    pgintime / (sum.v_pgin * 10.0));
5111590Srgrimes}
5121590Srgrimes#endif
5131590Srgrimes
51428693Scharnierlong
5151590Srgrimespct(top, bot)
5161590Srgrimes	long top, bot;
5171590Srgrimes{
5181590Srgrimes	long ans;
5191590Srgrimes
5201590Srgrimes	if (bot == 0)
5211590Srgrimes		return(0);
5221590Srgrimes	ans = (quad_t)top * 100 / bot;
5231590Srgrimes	return (ans);
5241590Srgrimes}
5251590Srgrimes
5261590Srgrimes#define	PCT(top, bot) pct((long)(top), (long)(bot))
5271590Srgrimes
5281590Srgrimes#if defined(tahoe)
5291590Srgrimes#include <machine/cpu.h>
5301590Srgrimes#endif
5311590Srgrimes
5321590Srgrimesvoid
5331590Srgrimesdosum()
5341590Srgrimes{
5351590Srgrimes	struct nchstats nchstats;
5361590Srgrimes	long nchtotal;
5371590Srgrimes#if defined(tahoe)
5381590Srgrimes	struct keystats keystats;
5391590Srgrimes#endif
5401590Srgrimes
5411590Srgrimes	kread(X_SUM, &sum, sizeof(sum));
5421590Srgrimes	(void)printf("%9u cpu context switches\n", sum.v_swtch);
5431590Srgrimes	(void)printf("%9u device interrupts\n", sum.v_intr);
5441590Srgrimes	(void)printf("%9u software interrupts\n", sum.v_soft);
5451590Srgrimes#ifdef vax
5461590Srgrimes	(void)printf("%9u pseudo-dma dz interrupts\n", sum.v_pdma);
5471590Srgrimes#endif
5481590Srgrimes	(void)printf("%9u traps\n", sum.v_trap);
5491590Srgrimes	(void)printf("%9u system calls\n", sum.v_syscall);
5503659Sdg	(void)printf("%9u swap pager pageins\n", sum.v_swapin);
5513693Sdg	(void)printf("%9u swap pager pages paged in\n", sum.v_swappgsin);
5523659Sdg	(void)printf("%9u swap pager pageouts\n", sum.v_swapout);
5533659Sdg	(void)printf("%9u swap pager pages paged out\n", sum.v_swappgsout);
5543659Sdg	(void)printf("%9u vnode pager pageins\n", sum.v_vnodein);
5553693Sdg	(void)printf("%9u vnode pager pages paged in\n", sum.v_vnodepgsin);
5563659Sdg	(void)printf("%9u vnode pager pageouts\n", sum.v_vnodeout);
5573659Sdg	(void)printf("%9u vnode pager pages paged out\n", sum.v_vnodepgsout);
5583693Sdg	(void)printf("%9u page daemon wakeups\n", sum.v_pdwakeups);
5593693Sdg	(void)printf("%9u pages examined by the page daemon\n", sum.v_pdpages);
5601590Srgrimes	(void)printf("%9u pages reactivated\n", sum.v_reactivated);
5617351Sdg	(void)printf("%9u copy-on-write faults\n", sum.v_cow_faults);
56234214Sdyson	(void)printf("%9u copy-on-write optimized faults\n", sum.v_cow_optim);
5637351Sdg	(void)printf("%9u zero fill pages zeroed\n", sum.v_zfod);
56434214Sdyson	(void)printf("%9u zero fill pages prezeroed\n", sum.v_ozfod);
5651590Srgrimes	(void)printf("%9u intransit blocking page faults\n", sum.v_intrans);
5661590Srgrimes	(void)printf("%9u total VM faults taken\n", sum.v_vm_faults);
5673693Sdg	(void)printf("%9u pages freed\n", sum.v_tfree);
5681590Srgrimes	(void)printf("%9u pages freed by daemon\n", sum.v_dfree);
5691590Srgrimes	(void)printf("%9u pages freed by exiting processes\n", sum.v_pfree);
5701590Srgrimes	(void)printf("%9u pages active\n", sum.v_active_count);
5711590Srgrimes	(void)printf("%9u pages inactive\n", sum.v_inactive_count);
5725463Sdg	(void)printf("%9u pages in VM cache\n", sum.v_cache_count);
5733693Sdg	(void)printf("%9u pages wired down\n", sum.v_wire_count);
5743693Sdg	(void)printf("%9u pages free\n", sum.v_free_count);
5751590Srgrimes	(void)printf("%9u bytes per page\n", sum.v_page_size);
5761590Srgrimes	kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
5771590Srgrimes	nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
5781590Srgrimes	    nchstats.ncs_badhits + nchstats.ncs_falsehits +
5791590Srgrimes	    nchstats.ncs_miss + nchstats.ncs_long;
5801590Srgrimes	(void)printf("%9ld total name lookups\n", nchtotal);
5811590Srgrimes	(void)printf(
58228693Scharnier	    "%9s cache hits (%ld%% pos + %ld%% neg) system %ld%% per-directory\n",
5831590Srgrimes	    "", PCT(nchstats.ncs_goodhits, nchtotal),
5841590Srgrimes	    PCT(nchstats.ncs_neghits, nchtotal),
5851590Srgrimes	    PCT(nchstats.ncs_pass2, nchtotal));
58628693Scharnier	(void)printf("%9s deletions %ld%%, falsehits %ld%%, toolong %ld%%\n", "",
5871590Srgrimes	    PCT(nchstats.ncs_badhits, nchtotal),
5881590Srgrimes	    PCT(nchstats.ncs_falsehits, nchtotal),
5891590Srgrimes	    PCT(nchstats.ncs_long, nchtotal));
5901590Srgrimes#if defined(tahoe)
5911590Srgrimes	kread(X_CKEYSTATS, &keystats, sizeof(keystats));
5921590Srgrimes	(void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
5931590Srgrimes	    keystats.ks_allocs, "code cache keys allocated",
5941590Srgrimes	    PCT(keystats.ks_allocfree, keystats.ks_allocs),
5951590Srgrimes	    PCT(keystats.ks_norefs, keystats.ks_allocs),
5961590Srgrimes	    PCT(keystats.ks_taken, keystats.ks_allocs),
5971590Srgrimes	    PCT(keystats.ks_shared, keystats.ks_allocs));
5981590Srgrimes	kread(X_DKEYSTATS, &keystats, sizeof(keystats));
5991590Srgrimes	(void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
6001590Srgrimes	    keystats.ks_allocs, "data cache keys allocated",
6011590Srgrimes	    PCT(keystats.ks_allocfree, keystats.ks_allocs),
6021590Srgrimes	    PCT(keystats.ks_norefs, keystats.ks_allocs),
6031590Srgrimes	    PCT(keystats.ks_taken, keystats.ks_allocs),
6041590Srgrimes	    PCT(keystats.ks_shared, keystats.ks_allocs));
6051590Srgrimes#endif
6061590Srgrimes}
6071590Srgrimes
60830180Sdima#ifdef notyet
6091590Srgrimesvoid
6101590Srgrimesdoforkst()
6111590Srgrimes{
6121590Srgrimes	struct forkstat fks;
6131590Srgrimes
6141590Srgrimes	kread(X_FORKSTAT, &fks, sizeof(struct forkstat));
6151590Srgrimes	(void)printf("%d forks, %d pages, average %.2f\n",
6161590Srgrimes	    fks.cntfork, fks.sizfork, (double)fks.sizfork / fks.cntfork);
6171590Srgrimes	(void)printf("%d vforks, %d pages, average %.2f\n",
6181590Srgrimes	    fks.cntvfork, fks.sizvfork, (double)fks.sizvfork / fks.cntvfork);
6191590Srgrimes}
6201590Srgrimes#endif
6211590Srgrimes
6221590Srgrimesvoid
6231590Srgrimesdkstats()
6241590Srgrimes{
6251590Srgrimes	register int dn, state;
6261590Srgrimes	double etime;
6271590Srgrimes	long tmp;
6281590Srgrimes
6291590Srgrimes	for (dn = 0; dn < dk_ndrive; ++dn) {
6301590Srgrimes		tmp = cur.xfer[dn];
6311590Srgrimes		cur.xfer[dn] -= last.xfer[dn];
6321590Srgrimes		last.xfer[dn] = tmp;
6331590Srgrimes	}
6341590Srgrimes	etime = 0;
6351590Srgrimes	for (state = 0; state < CPUSTATES; ++state) {
6361590Srgrimes		tmp = cur.time[state];
6371590Srgrimes		cur.time[state] -= last.time[state];
6381590Srgrimes		last.time[state] = tmp;
6391590Srgrimes		etime += cur.time[state];
6401590Srgrimes	}
6411590Srgrimes	if (etime == 0)
6421590Srgrimes		etime = 1;
6431590Srgrimes	etime /= hz;
6441590Srgrimes	for (dn = 0; dn < dk_ndrive; ++dn) {
6451590Srgrimes		if (!dr_select[dn])
6461590Srgrimes			continue;
6471590Srgrimes		(void)printf("%2.0f ", cur.xfer[dn] / etime);
6481590Srgrimes	}
6491590Srgrimes}
6501590Srgrimes
6511590Srgrimesvoid
6521590Srgrimescpustats()
6531590Srgrimes{
6541590Srgrimes	register int state;
6551590Srgrimes	double pct, total;
6561590Srgrimes
6571590Srgrimes	total = 0;
6581590Srgrimes	for (state = 0; state < CPUSTATES; ++state)
6591590Srgrimes		total += cur.time[state];
6601590Srgrimes	if (total)
6611590Srgrimes		pct = 100 / total;
6621590Srgrimes	else
6631590Srgrimes		pct = 0;
6641590Srgrimes	(void)printf("%2.0f ", (cur.time[CP_USER] + cur.time[CP_NICE]) * pct);
6651590Srgrimes	(void)printf("%2.0f ", (cur.time[CP_SYS] + cur.time[CP_INTR]) * pct);
6661590Srgrimes	(void)printf("%2.0f", cur.time[CP_IDLE] * pct);
6671590Srgrimes}
6681590Srgrimes
6691590Srgrimesvoid
6701590Srgrimesdointr()
6711590Srgrimes{
6721590Srgrimes	register long *intrcnt, inttotal, uptime;
6731590Srgrimes	register int nintr, inamlen;
6741590Srgrimes	register char *intrname;
6751590Srgrimes
6761590Srgrimes	uptime = getuptime();
6771590Srgrimes	nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value;
6781590Srgrimes	inamlen =
6791590Srgrimes	    namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value;
6801590Srgrimes	intrcnt = malloc((size_t)nintr);
6811590Srgrimes	intrname = malloc((size_t)inamlen);
68228693Scharnier	if (intrcnt == NULL || intrname == NULL)
68328693Scharnier		errx(1, "malloc");
6841590Srgrimes	kread(X_INTRCNT, intrcnt, (size_t)nintr);
6851590Srgrimes	kread(X_INTRNAMES, intrname, (size_t)inamlen);
6861590Srgrimes	(void)printf("interrupt      total      rate\n");
6871590Srgrimes	inttotal = 0;
6881590Srgrimes	nintr /= sizeof(long);
6891590Srgrimes	while (--nintr >= 0) {
6901590Srgrimes		if (*intrcnt)
6911590Srgrimes			(void)printf("%-12s %8ld %8ld\n", intrname,
6921590Srgrimes			    *intrcnt, *intrcnt / uptime);
6931590Srgrimes		intrname += strlen(intrname) + 1;
6941590Srgrimes		inttotal += *intrcnt++;
6951590Srgrimes	}
6961590Srgrimes	(void)printf("Total        %8ld %8ld\n", inttotal, inttotal / uptime);
6971590Srgrimes}
6981590Srgrimes
6991590Srgrimesvoid
7001590Srgrimesdomem()
7011590Srgrimes{
7021590Srgrimes	register struct kmembuckets *kp;
70330287Sphk	register struct malloc_type *ks;
7041590Srgrimes	register int i, j;
70530279Sphk	int len, size, first, nkms;
7061590Srgrimes	long totuse = 0, totfree = 0, totreq = 0;
70731560Sbde	const char *name;
70830287Sphk	struct malloc_type kmemstats[200],*kmsp;
70930279Sphk	char *kmemnames[200];
71030279Sphk	char buf[1024];
7111590Srgrimes	struct kmembuckets buckets[MINBUCKET + 16];
7121590Srgrimes
7131590Srgrimes	kread(X_KMEMBUCKETS, buckets, sizeof(buckets));
71430279Sphk	kread(X_KMEMSTATISTICS, &kmsp, sizeof(kmsp));
71530279Sphk	for (nkms=0; nkms < 200 && kmsp; nkms++) {
71630279Sphk		if (sizeof(kmemstats[0]) != kvm_read(kd, (u_long)kmsp,
71730279Sphk		    &kmemstats[nkms], sizeof(kmemstats[0])))
71830279Sphk			err(1,"kvm_read(%08x)", (u_long)kmsp);
71930279Sphk		if (sizeof(buf) !=  kvm_read(kd,
72030279Sphk	            (u_long)kmemstats[nkms].ks_shortdesc, buf, sizeof(buf)))
72130279Sphk			err(1,"kvm_read(%08x)",
72230279Sphk			    (u_long)kmemstats[nkms].ks_shortdesc);
72330279Sphk		kmemstats[nkms].ks_shortdesc = strdup(buf);
72430279Sphk		kmsp = kmemstats[nkms].ks_next;
72530279Sphk	}
7261590Srgrimes	(void)printf("Memory statistics by bucket size\n");
7271590Srgrimes	(void)printf(
7283372Sphk	    "Size   In Use   Free   Requests  HighWater  Couldfree\n");
7291590Srgrimes	for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) {
7301590Srgrimes		if (kp->kb_calls == 0)
7311590Srgrimes			continue;
7321590Srgrimes		size = 1 << i;
7333372Sphk		if(size < 1024)
7343372Sphk			(void)printf("%4d",size);
7353372Sphk		else
7363372Sphk			(void)printf("%3dK",size>>10);
7378874Srgrimes		(void)printf(" %8ld %6ld %10ld %7ld %10ld\n",
7381590Srgrimes			kp->kb_total - kp->kb_totalfree,
7391590Srgrimes			kp->kb_totalfree, kp->kb_calls,
7401590Srgrimes			kp->kb_highwat, kp->kb_couldfree);
7411590Srgrimes		totfree += size * kp->kb_totalfree;
7421590Srgrimes	}
7431590Srgrimes
7441590Srgrimes	(void)printf("\nMemory usage type by bucket size\n");
7453372Sphk	(void)printf("Size  Type(s)\n");
7461590Srgrimes	kp = &buckets[MINBUCKET];
7471590Srgrimes	for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) {
7481590Srgrimes		if (kp->kb_calls == 0)
7491590Srgrimes			continue;
7501590Srgrimes		first = 1;
7511590Srgrimes		len = 8;
75230279Sphk		for (i = 0, ks = &kmemstats[0]; i < nkms; i++, ks++) {
7531590Srgrimes			if (ks->ks_calls == 0)
7541590Srgrimes				continue;
7551590Srgrimes			if ((ks->ks_size & j) == 0)
7561590Srgrimes				continue;
75730279Sphk			name = ks->ks_shortdesc;
7581590Srgrimes			len += 2 + strlen(name);
7593372Sphk			if (first && j < 1024)
7603372Sphk				printf("%4d  %s", j, name);
7613372Sphk			else if (first)
7623372Sphk				printf("%3dK  %s", j>>10, name);
7631590Srgrimes			else
7641590Srgrimes				printf(",");
7653372Sphk			if (len >= 79) {
7661590Srgrimes				printf("\n\t ");
7671590Srgrimes				len = 10 + strlen(name);
7681590Srgrimes			}
7691590Srgrimes			if (!first)
7701590Srgrimes				printf(" %s", name);
7711590Srgrimes			first = 0;
7721590Srgrimes		}
7731590Srgrimes		printf("\n");
7741590Srgrimes	}
7751590Srgrimes
7761590Srgrimes	(void)printf(
7773372Sphk	    "\nMemory statistics by type                          Type  Kern\n");
7781590Srgrimes	(void)printf(
7793372Sphk"        Type  InUse MemUse HighUse  Limit Requests Limit Limit Size(s)\n");
78030279Sphk	for (i = 0, ks = &kmemstats[0]; i < nkms; i++, ks++) {
7811590Srgrimes		if (ks->ks_calls == 0)
7821590Srgrimes			continue;
7833372Sphk		(void)printf("%13s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u",
78430279Sphk		    ks->ks_shortdesc,
7851590Srgrimes		    ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
7861590Srgrimes		    (ks->ks_maxused + 1023) / 1024,
7871590Srgrimes		    (ks->ks_limit + 1023) / 1024, ks->ks_calls,
7881590Srgrimes		    ks->ks_limblocks, ks->ks_mapblocks);
7891590Srgrimes		first = 1;
7901590Srgrimes		for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
7911590Srgrimes			if ((ks->ks_size & j) == 0)
7921590Srgrimes				continue;
7931590Srgrimes			if (first)
7943372Sphk				printf("  ");
7951590Srgrimes			else
7963372Sphk				printf(",");
7973372Sphk			if(j<1024)
7983372Sphk				printf("%d",j);
7993372Sphk			else
8003372Sphk				printf("%dK",j>>10);
8011590Srgrimes			first = 0;
8021590Srgrimes		}
8031590Srgrimes		printf("\n");
8041590Srgrimes		totuse += ks->ks_memuse;
8051590Srgrimes		totreq += ks->ks_calls;
8061590Srgrimes	}
8071590Srgrimes	(void)printf("\nMemory Totals:  In Use    Free    Requests\n");
8081590Srgrimes	(void)printf("              %7ldK %6ldK    %8ld\n",
8091590Srgrimes	     (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq);
8101590Srgrimes}
8111590Srgrimes
8121590Srgrimes/*
8131590Srgrimes * kread reads something from the kernel, given its nlist index.
8141590Srgrimes */
8151590Srgrimesvoid
8161590Srgrimeskread(nlx, addr, size)
8171590Srgrimes	int nlx;
8181590Srgrimes	void *addr;
8191590Srgrimes	size_t size;
8201590Srgrimes{
8211590Srgrimes	char *sym;
8221590Srgrimes
8231590Srgrimes	if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
8241590Srgrimes		sym = namelist[nlx].n_name;
8251590Srgrimes		if (*sym == '_')
8261590Srgrimes			++sym;
82728693Scharnier		errx(1, "symbol %s not defined", sym);
8281590Srgrimes	}
8291590Srgrimes	if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) {
8301590Srgrimes		sym = namelist[nlx].n_name;
8311590Srgrimes		if (*sym == '_')
8321590Srgrimes			++sym;
83328693Scharnier		errx(1, "%s: %s", sym, kvm_geterr(kd));
8341590Srgrimes	}
8351590Srgrimes}
8361590Srgrimes
8371590Srgrimesvoid
8381590Srgrimesusage()
8391590Srgrimes{
8401590Srgrimes	(void)fprintf(stderr,
84128693Scharnier"usage: vmstat [-ims] [-c count] [-M core] [-N system] [-w wait] [disks]\n");
8421590Srgrimes	exit(1);
8431590Srgrimes}
844