xref: /csrg-svn/usr.bin/vmstat/vmstat.c (revision 49924)
121585Sdist /*
248570Sbostic  * Copyright (c) 1980, 1986, 1991 The Regents of the University of California.
336580Sbostic  * All rights reserved.
436580Sbostic  *
542784Sbostic  * %sccs.include.redist.c%
621585Sdist  */
721585Sdist 
810826Ssam #ifndef lint
921585Sdist char copyright[] =
1048570Sbostic "@(#) Copyright (c) 1980, 1986, 1991 The Regents of the University of California.\n\
1121585Sdist  All rights reserved.\n";
1236580Sbostic #endif /* not lint */
1310826Ssam 
1421585Sdist #ifndef lint
15*49924Sbostic static char sccsid[] = "@(#)vmstat.c	5.27 (Berkeley) 05/29/91";
1636580Sbostic #endif /* not lint */
1721585Sdist 
181155Sbill #include <sys/param.h>
191155Sbill #include <sys/vm.h>
2046892Sbostic #include <sys/user.h>
2129664Ssam #include <sys/dkstat.h>
223162Stoy #include <sys/buf.h>
2317262Smckusick #include <sys/namei.h>
2425708Ssam #include <sys/text.h>
2533610Smckusick #include <sys/malloc.h>
2648570Sbostic #include <signal.h>
2748570Sbostic #include <fcntl.h>
2848570Sbostic #include <time.h>
2948570Sbostic #include <nlist.h>
3048570Sbostic #include <kvm.h>
3145834Sbostic #include <errno.h>
3248570Sbostic #include <unistd.h>
3345834Sbostic #include <stdio.h>
3448570Sbostic #include <ctype.h>
3545834Sbostic #include <stdlib.h>
3645834Sbostic #include <string.h>
3737912Sbostic #include <paths.h>
381155Sbill 
391155Sbill struct nlist nl[] = {
401448Sbill #define	X_CPTIME	0
411448Sbill 	{ "_cp_time" },
421448Sbill #define	X_RATE		1
431155Sbill 	{ "_rate" },
441448Sbill #define X_TOTAL		2
451155Sbill 	{ "_total" },
461448Sbill #define	X_DEFICIT	3
471155Sbill 	{ "_deficit" },
481448Sbill #define	X_FORKSTAT	4
491155Sbill 	{ "_forkstat" },
501448Sbill #define X_SUM		5
511155Sbill 	{ "_sum" },
5248570Sbostic #define	X_BOOTTIME	6
539249Ssam 	{ "_boottime" },
5448570Sbostic #define	X_DKXFER	7
551448Sbill 	{ "_dk_xfer" },
5648570Sbostic #define X_REC		8
571155Sbill 	{ "_rectime" },
5848570Sbostic #define X_PGIN		9
591155Sbill 	{ "_pgintime" },
6048570Sbostic #define X_HZ		10
613162Stoy 	{ "_hz" },
6248570Sbostic #define X_PHZ		11
6315266Ssam 	{ "_phz" },
6448570Sbostic #define X_NCHSTATS	12
6515807Smckusick 	{ "_nchstats" },
6648570Sbostic #define	X_INTRNAMES	13
6717262Smckusick 	{ "_intrnames" },
6848570Sbostic #define	X_EINTRNAMES	14
6917262Smckusick 	{ "_eintrnames" },
7048570Sbostic #define	X_INTRCNT	15
7117262Smckusick 	{ "_intrcnt" },
7248570Sbostic #define	X_EINTRCNT	16
7317262Smckusick 	{ "_eintrcnt" },
7448570Sbostic #define	X_DK_NDRIVE	17
7518761Ssam 	{ "_dk_ndrive" },
7648570Sbostic #define	X_XSTATS	18
7725512Ssam 	{ "_xstats" },
7848570Sbostic #define	X_KMEMSTAT	19
7933610Smckusick 	{ "_kmemstats" },
8048570Sbostic #define	X_KMEMBUCKETS	20
8133610Smckusick 	{ "_bucket" },
8248570Sbostic #define X_END		20
8348570Sbostic #ifdef hp300
8448570Sbostic #define	X_HPDINIT	(X_END+1)
8548570Sbostic 	{ "_hp_dinit" },
8610826Ssam #endif
8725708Ssam #ifdef tahoe
8842952Sbostic #define	X_VBDINIT	(X_END+1)
8925708Ssam 	{ "_vbdinit" },
9042952Sbostic #define	X_CKEYSTATS	(X_END+2)
9125960Ssam 	{ "_ckeystats" },
9242952Sbostic #define	X_DKEYSTATS	(X_END+3)
9325960Ssam 	{ "_dkeystats" },
9425708Ssam #endif
9548570Sbostic #ifdef vax
9648570Sbostic #define X_MBDINIT	(X_END+1)
9748570Sbostic 	{ "_mbdinit" },
9848570Sbostic #define X_UBDINIT	(X_END+2)
9948570Sbostic 	{ "_ubdinit" },
10042952Sbostic #endif
10110826Ssam 	{ "" },
1021155Sbill };
1031155Sbill 
10448570Sbostic struct _disk {
10548570Sbostic 	long time[CPUSTATES];
10648570Sbostic 	long *xfer;
10748570Sbostic } cur, last;
10818761Ssam 
10948570Sbostic struct vmmeter sum;
11048570Sbostic char *vmunix = _PATH_UNIX;
11148570Sbostic char **dr_name;
11248570Sbostic int *dr_select, dk_ndrive, ndrives;
1131155Sbill 
11445834Sbostic #define	FORKSTAT	0x01
11545834Sbostic #define	INTRSTAT	0x02
11645834Sbostic #define	MEMSTAT		0x04
11745834Sbostic #define	SUMSTAT		0x08
11845834Sbostic #define	TIMESTAT	0x10
11945834Sbostic #define	VMSTAT		0x20
12045834Sbostic #define	ZEROOUT		0x40
12145834Sbostic 
12248570Sbostic #include "names.c"			/* disk names -- machine dependent */
12348570Sbostic 
12448613Sbostic void cpustats(), dkstats(), doforkst(), dointr(), domem(), dosum();
12548613Sbostic void dotimes(), dovmstat(), kread(), usage(), zero();
12648570Sbostic 
1271155Sbill main(argc, argv)
12845834Sbostic 	register int argc;
12945834Sbostic 	register char **argv;
1301155Sbill {
13145834Sbostic 	extern int optind;
13245834Sbostic 	extern char *optarg;
13348570Sbostic 	register int c, todo;
13448570Sbostic 	u_int interval;
13548570Sbostic 	int reps;
13648570Sbostic 	char *kmem;
1371155Sbill 
13848570Sbostic 	kmem = NULL;
13948570Sbostic 	interval = reps = todo = 0;
14048570Sbostic 	while ((c = getopt(argc, argv, "c:fiM:mN:stw:z")) != EOF) {
14145834Sbostic 		switch (c) {
14248570Sbostic 		case 'c':
14348570Sbostic 			reps = atoi(optarg);
14448570Sbostic 			break;
14545834Sbostic 		case 'f':
14645834Sbostic 			todo |= FORKSTAT;
14745834Sbostic 			break;
14845834Sbostic 		case 'i':
14945834Sbostic 			todo |= INTRSTAT;
15045834Sbostic 			break;
15148570Sbostic 		case 'M':
15245834Sbostic 			kmem = optarg;
15345834Sbostic 			break;
15445834Sbostic 		case 'm':
15545834Sbostic 			todo |= MEMSTAT;
15645834Sbostic 			break;
15748570Sbostic 		case 'N':
15848570Sbostic 			vmunix = optarg;
15948570Sbostic 			break;
16045834Sbostic 		case 's':
16145834Sbostic 			todo |= SUMSTAT;
16245834Sbostic 			break;
16345834Sbostic 		case 't':
16445834Sbostic 			todo |= TIMESTAT;
16545834Sbostic 			break;
16648570Sbostic 		case 'w':
16748570Sbostic 			interval = atoi(optarg);
16845834Sbostic 			break;
16945834Sbostic 		case 'z':
17045834Sbostic 			todo |= ZEROOUT;
17145834Sbostic 			break;
17245834Sbostic 		case '?':
17348570Sbostic 		default:
17445834Sbostic 			usage();
17545834Sbostic 		}
17645834Sbostic 	}
17748570Sbostic 	argc -= optind;
17848570Sbostic 	argv += optind;
17945834Sbostic 
18045834Sbostic 	if (todo & ZEROOUT) {
18145834Sbostic 		if (todo & ~ZEROOUT || kmem)
18245834Sbostic 			usage();
18348570Sbostic 		zero();
18445834Sbostic 		exit(0);
18545834Sbostic 	}
18645834Sbostic 
18745834Sbostic 	if (todo == 0)
18845834Sbostic 		todo = VMSTAT;
18945834Sbostic 
19048570Sbostic 	if (kvm_openfiles(vmunix, kmem, NULL) < 0) {
19148570Sbostic 		(void)fprintf(stderr,
19248570Sbostic 		    "vmstat: kvm_openfiles: %s\n", kvm_geterr());
1931155Sbill 		exit(1);
1941155Sbill 	}
19545834Sbostic 
19648570Sbostic 	(void)kvm_nlist(nl);
19745834Sbostic 	if (nl[0].n_type == 0) {
19848570Sbostic 		(void)fprintf(stderr,
19948570Sbostic 		    "vmstat: %s: no namelist\n", vmunix);
2001155Sbill 		exit(1);
2011155Sbill 	}
2021155Sbill 
20348570Sbostic 	if (todo & VMSTAT) {
20448570Sbostic 		char **getdrivedata();
20548570Sbostic 
20648570Sbostic 		argv = getdrivedata(argv);
20748570Sbostic 	}
20848570Sbostic 
20948570Sbostic #define	BACKWARD_COMPATIBILITY
21048570Sbostic #ifdef	BACKWARD_COMPATIBILITY
21148570Sbostic 	if (*argv) {
21248570Sbostic 		interval = atoi(*argv);
21348570Sbostic 		if (*++argv)
21448570Sbostic 			reps = atoi(*argv);
21548570Sbostic 	}
21648570Sbostic #endif
21748570Sbostic 
21848613Sbostic 	if (interval) {
21948613Sbostic 		if (!reps)
22048613Sbostic 			reps = -1;
22148613Sbostic 	} else
22248613Sbostic 		if (reps)
22348613Sbostic 			interval = 1;
22448613Sbostic 
22545834Sbostic 	if (todo & FORKSTAT)
22645834Sbostic 		doforkst();
22745834Sbostic 	if (todo & MEMSTAT)
22845834Sbostic 		domem();
22945834Sbostic 	if (todo & SUMSTAT)
23045834Sbostic 		dosum();
23145834Sbostic 	if (todo & TIMESTAT)
23245834Sbostic 		dotimes();
23345834Sbostic 	if (todo & INTRSTAT)
23445834Sbostic 		dointr();
23548570Sbostic 	if (todo & VMSTAT)
23648570Sbostic 		dovmstat(interval, reps);
23745834Sbostic 	exit(0);
23845834Sbostic }
23910826Ssam 
24048570Sbostic char **
24148570Sbostic getdrivedata(argv)
24245834Sbostic 	char **argv;
24345834Sbostic {
24445834Sbostic 	register int i;
24545834Sbostic 	register char **cp;
24645834Sbostic 	char buf[30];
24745834Sbostic 
24848570Sbostic 	kread(X_DK_NDRIVE, &dk_ndrive, sizeof(dk_ndrive));
24918761Ssam 	if (dk_ndrive <= 0) {
25048570Sbostic 		(void)fprintf(stderr, "vmstat: dk_ndrive %d\n", dk_ndrive);
25118761Ssam 		exit(1);
25218761Ssam 	}
25348570Sbostic 	dr_select = calloc((size_t)dk_ndrive, sizeof(int));
25448570Sbostic 	dr_name = calloc((size_t)dk_ndrive, sizeof(char *));
25545834Sbostic 	for (i = 0; i < dk_ndrive; i++)
25645834Sbostic 		dr_name[i] = NULL;
25748570Sbostic 	cur.xfer = calloc((size_t)dk_ndrive, sizeof(long));
25848570Sbostic 	last.xfer = calloc((size_t)dk_ndrive, sizeof(long));
2593162Stoy 	read_names();
26048570Sbostic 	for (i = 0; i < dk_ndrive; i++)
26145834Sbostic 		if (dr_name[i] == NULL) {
26248570Sbostic 			(void)sprintf(buf, "??%d", i);
26345834Sbostic 			dr_name[i] = strdup(buf);
26445834Sbostic 		}
26545834Sbostic 
26618761Ssam 	/*
26748570Sbostic 	 * Choose drives to be displayed.  Priority goes to (in order) drives
26848570Sbostic 	 * supplied as arguments, default drives.  If everything isn't filled
26948570Sbostic 	 * in and there are drives not taken care of, display the first few
27048570Sbostic 	 * that fit.
27118761Ssam 	 */
27248570Sbostic #define BACKWARD_COMPATIBILITY
27348570Sbostic 	for (ndrives = 0; *argv; ++argv) {
27448570Sbostic #ifdef	BACKWARD_COMPATIBILITY
27548570Sbostic 		if (isdigit(**argv))
27648570Sbostic 			break;
27748570Sbostic #endif
27818761Ssam 		for (i = 0; i < dk_ndrive; i++) {
27948570Sbostic 			if (strcmp(dr_name[i], *argv))
28018761Ssam 				continue;
28118761Ssam 			dr_select[i] = 1;
28248570Sbostic 			++ndrives;
28345834Sbostic 			break;
28418761Ssam 		}
28518761Ssam 	}
28618761Ssam 	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
28718761Ssam 		if (dr_select[i])
28818761Ssam 			continue;
28918761Ssam 		for (cp = defdrives; *cp; cp++)
29018761Ssam 			if (strcmp(dr_name[i], *cp) == 0) {
29118761Ssam 				dr_select[i] = 1;
29248570Sbostic 				++ndrives;
29318761Ssam 				break;
29418761Ssam 			}
29518761Ssam 	}
29618761Ssam 	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
29718761Ssam 		if (dr_select[i])
29818761Ssam 			continue;
29918761Ssam 		dr_select[i] = 1;
30048570Sbostic 		++ndrives;
30118761Ssam 	}
30248570Sbostic 	return(argv);
30345834Sbostic }
30445834Sbostic 
30545834Sbostic long
30645834Sbostic getuptime()
30745834Sbostic {
30848570Sbostic 	static time_t now, boottime;
30948570Sbostic 	time_t uptime;
31045834Sbostic 
31145834Sbostic 	if (boottime == 0)
31248570Sbostic 		kread(X_BOOTTIME, &boottime, sizeof(boottime));
31348570Sbostic 	(void)time(&now);
31445834Sbostic 	uptime = now - boottime;
31545834Sbostic 	if (uptime <= 0 || uptime > 60*60*24*365*10) {
31648570Sbostic 		(void)fprintf(stderr,
31745834Sbostic 		    "vmstat: time makes no sense; namelist must be wrong.\n");
31845834Sbostic 		exit(1);
31945834Sbostic 	}
32048570Sbostic 	return(uptime);
32145834Sbostic }
32245834Sbostic 
32348613Sbostic int hz;
32448613Sbostic 
32548570Sbostic void
32648570Sbostic dovmstat(interval, reps)
32748570Sbostic 	u_int interval;
32848570Sbostic 	int reps;
32945834Sbostic {
33048570Sbostic 	struct vmmeter rate;
33148570Sbostic 	struct vmtotal total;
33248570Sbostic 	time_t uptime;
33348613Sbostic 	int deficit, hdrcnt;
33448570Sbostic 	void printhdr();
33545834Sbostic 
33648570Sbostic 	uptime = getuptime();
33748570Sbostic 	(void)signal(SIGCONT, printhdr);
33848570Sbostic 
33948570Sbostic 	if (nl[X_PHZ].n_type != 0 && nl[X_PHZ].n_value != 0)
34048613Sbostic 		kread(X_PHZ, &hz, sizeof(hz));
34148613Sbostic 	if (!hz)
34248613Sbostic 		kread(X_HZ, &hz, sizeof(hz));
34348570Sbostic 
34448570Sbostic 	for (hdrcnt = 1;;) {
34548570Sbostic 		if (!--hdrcnt) {
34648570Sbostic 			printhdr();
34748570Sbostic 			hdrcnt = 20;
34848570Sbostic 		}
34948570Sbostic 		kread(X_CPTIME, cur.time, sizeof(cur.time));
35048570Sbostic 		kread(X_DKXFER, cur.xfer, sizeof(*cur.xfer * dk_ndrive));
35148570Sbostic 		if (uptime != 1)
35248570Sbostic 			kread(X_SUM, &rate, sizeof(rate));
35348570Sbostic 		else
35448570Sbostic 			kread(X_RATE, &rate, sizeof(rate));
35548570Sbostic 		kread(X_TOTAL, &total, sizeof(total));
35648570Sbostic 		kread(X_SUM, &sum, sizeof(sum));
35748570Sbostic 		kread(X_DEFICIT, &deficit, sizeof(deficit));
35848570Sbostic 		(void)printf("%2d%2d%2d",
35948570Sbostic 		    total.t_rq, total.t_dw + total.t_pw, total.t_sw);
36045834Sbostic #define pgtok(a) ((a)*NBPG >> 10)
36148570Sbostic 		(void)printf("%6ld%6ld",
36248570Sbostic 		    pgtok(total.t_avm), pgtok(total.t_free));
36348570Sbostic 		(void)printf("%4lu%3lu",
36448570Sbostic 		    (rate.v_pgrec - (rate.v_xsfrec+rate.v_xifrec)) / uptime,
36548570Sbostic 		    (rate.v_xsfrec+rate.v_xifrec) / uptime);
36648570Sbostic 		(void)printf("%4lu", pgtok(rate.v_pgpgin) / uptime);
36748570Sbostic 		(void)printf("%4lu%4lu%4d%4lu", pgtok(rate.v_pgpgout) / uptime,
36848570Sbostic 		    pgtok(rate.v_dfree) / uptime,
36948570Sbostic 		    pgtok(deficit), rate.v_scan / uptime);
37048613Sbostic 		dkstats();
37148613Sbostic 		(void)printf("%4lu%4lu%4lu", rate.v_intr / uptime,
37248570Sbostic 		    rate.v_syscall / uptime, rate.v_swtch / uptime);
37348613Sbostic 		cpustats();
37448570Sbostic 		(void)printf("\n");
37548570Sbostic 		(void)fflush(stdout);
37648570Sbostic 		uptime = 1;
37748613Sbostic 		if (reps >= 0 && --reps <= 0)
37848570Sbostic 			break;
37948613Sbostic 		(void)sleep(interval);
3801155Sbill 	}
3811155Sbill }
3821155Sbill 
38345834Sbostic void
38417262Smckusick printhdr()
38517262Smckusick {
38648570Sbostic 	register int i;
38718761Ssam 
38848570Sbostic 	(void)printf(" procs   memory     page%*s", 22, "");
38948570Sbostic 	if (ndrives > 1)
39048570Sbostic 		(void)printf("disks %*s faults     cpu\n",
39148570Sbostic 		   ndrives * 3 - 6, "");
39248570Sbostic 	else
39348570Sbostic 		(void)printf("%*s faults     cpu\n", ndrives * 3, "");
39448570Sbostic 	(void)printf(" r b w   avm   fre  re at  pi  po  fr  de  sr ");
39518761Ssam 	for (i = 0; i < dk_ndrive; i++)
39618761Ssam 		if (dr_select[i])
39748570Sbostic 			(void)printf("%c%c ", dr_name[i][0],
39845834Sbostic 			    dr_name[i][strlen(dr_name[i]) - 1]);
39948570Sbostic 	(void)printf(" in  sy  cs us sy id\n");
40017262Smckusick }
40117262Smckusick 
40248570Sbostic void
4031155Sbill dotimes()
4041155Sbill {
40548570Sbostic 	u_int pgintime, rectime;
4061155Sbill 
40748570Sbostic 	kread(X_REC, &rectime, sizeof(rectime));
40848570Sbostic 	kread(X_PGIN, &pgintime, sizeof(pgintime));
40948570Sbostic 	kread(X_SUM, &sum, sizeof(sum));
41048570Sbostic 	(void)printf("%u reclaims, %u total time (usec)\n",
41148570Sbostic 	    sum.v_pgrec, rectime);
41248570Sbostic 	(void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec);
41348570Sbostic 	(void)printf("\n");
41448570Sbostic 	(void)printf("%u page ins, %u total time (msec)\n",
41548570Sbostic 	    sum.v_pgin, pgintime / 10);
41648570Sbostic 	(void)printf("average: %8.1f msec / page in\n",
41748570Sbostic 	    pgintime / (sum.v_pgin * 10.0));
4181155Sbill }
4191155Sbill 
42045834Sbostic pct(top, bot)
42145834Sbostic 	long top, bot;
42245834Sbostic {
42345834Sbostic 	if (bot == 0)
42448570Sbostic 		return(0);
42548570Sbostic 	return((top * 100) / bot);
42645834Sbostic }
42745834Sbostic 
42845834Sbostic #define	PCT(top, bot) pct((long)(top), (long)(bot))
42945834Sbostic 
43030069Ssam #if defined(tahoe)
43145834Sbostic #include <machine/cpu.h>
43230069Ssam #endif
43330069Ssam 
43448570Sbostic void
4351155Sbill dosum()
4361155Sbill {
43718761Ssam 	struct nchstats nchstats;
43825960Ssam 	struct xstats xstats;
43915807Smckusick 	long nchtotal;
44025960Ssam #if defined(tahoe)
44125960Ssam 	struct keystats keystats;
44225960Ssam #endif
4431155Sbill 
44448570Sbostic 	kread(X_SUM, &sum, sizeof(sum));
44548570Sbostic 	(void)printf("%9u swap ins\n", sum.v_swpin);
44648570Sbostic 	(void)printf("%9u swap outs\n", sum.v_swpout);
44748570Sbostic 	(void)printf("%9u pages swapped in\n", sum.v_pswpin / CLSIZE);
44848570Sbostic 	(void)printf("%9u pages swapped out\n", sum.v_pswpout / CLSIZE);
44948570Sbostic 	(void)printf("%9u total address trans. faults taken\n", sum.v_faults);
45048570Sbostic 	(void)printf("%9u page ins\n", sum.v_pgin);
45148570Sbostic 	(void)printf("%9u page outs\n", sum.v_pgout);
45248570Sbostic 	(void)printf("%9u pages paged in\n", sum.v_pgpgin);
45348570Sbostic 	(void)printf("%9u pages paged out\n", sum.v_pgpgout);
45448570Sbostic 	(void)printf("%9u sequential process pages freed\n", sum.v_seqfree);
45548570Sbostic 	(void)printf("%9u total reclaims (%d%% fast)\n", sum.v_pgrec,
45645834Sbostic 	    PCT(sum.v_fastpgrec, sum.v_pgrec));
45748570Sbostic 	(void)printf("%9u reclaims from free list\n", sum.v_pgfrec);
45848570Sbostic 	(void)printf("%9u intransit blocking page faults\n", sum.v_intrans);
45948570Sbostic 	(void)printf("%9u zero fill pages created\n", sum.v_nzfod / CLSIZE);
46048570Sbostic 	(void)printf("%9u zero fill page faults\n", sum.v_zfod / CLSIZE);
46148570Sbostic 	(void)printf("%9u executable fill pages created\n",
46245834Sbostic 	    sum.v_nexfod / CLSIZE);
46348570Sbostic 	(void)printf("%9u executable fill page faults\n",
46445834Sbostic 	    sum.v_exfod / CLSIZE);
46548570Sbostic 	(void)printf("%9u swap text pages found in free list\n",
46645834Sbostic 	    sum.v_xsfrec);
46748570Sbostic 	(void)printf("%9u inode text pages found in free list\n",
46845834Sbostic 	    sum.v_xifrec);
46948570Sbostic 	(void)printf("%9u file fill pages created\n", sum.v_nvrfod / CLSIZE);
47048570Sbostic 	(void)printf("%9u file fill page faults\n", sum.v_vrfod / CLSIZE);
47148570Sbostic 	(void)printf("%9u pages examined by the clock daemon\n", sum.v_scan);
47248570Sbostic 	(void)printf("%9u revolutions of the clock hand\n", sum.v_rev);
47348570Sbostic 	(void)printf("%9u pages freed by the clock daemon\n",
47445834Sbostic 	    sum.v_dfree / CLSIZE);
47548570Sbostic 	(void)printf("%9u cpu context switches\n", sum.v_swtch);
47648570Sbostic 	(void)printf("%9u device interrupts\n", sum.v_intr);
47748570Sbostic 	(void)printf("%9u software interrupts\n", sum.v_soft);
47818761Ssam #ifdef vax
47948570Sbostic 	(void)printf("%9u pseudo-dma dz interrupts\n", sum.v_pdma);
48018761Ssam #endif
48148570Sbostic 	(void)printf("%9u traps\n", sum.v_trap);
48248570Sbostic 	(void)printf("%9u system calls\n", sum.v_syscall);
48348570Sbostic 	kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
48438773Smckusick 	nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
48538773Smckusick 	    nchstats.ncs_badhits + nchstats.ncs_falsehits +
48638773Smckusick 	    nchstats.ncs_miss + nchstats.ncs_long;
48748570Sbostic 	(void)printf("%9ld total name lookups\n", nchtotal);
48848570Sbostic 	(void)printf(
48945834Sbostic 	    "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
49045834Sbostic 	    "", PCT(nchstats.ncs_goodhits, nchtotal),
49145834Sbostic 	    PCT(nchstats.ncs_neghits, nchtotal),
49245834Sbostic 	    PCT(nchstats.ncs_pass2, nchtotal));
49348570Sbostic 	(void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
49445834Sbostic 	    PCT(nchstats.ncs_badhits, nchtotal),
49545834Sbostic 	    PCT(nchstats.ncs_falsehits, nchtotal),
49645834Sbostic 	    PCT(nchstats.ncs_long, nchtotal));
49748570Sbostic 	kread(X_XSTATS, &xstats, sizeof(xstats));
49848570Sbostic 	(void)printf("%9lu total calls to xalloc (cache hits %d%%)\n",
49945834Sbostic 	    xstats.alloc, PCT(xstats.alloc_cachehit, xstats.alloc));
50048570Sbostic 	(void)printf("%9s sticky %lu flushed %lu unused %lu\n", "",
50125512Ssam 	    xstats.alloc_inuse, xstats.alloc_cacheflush, xstats.alloc_unused);
50248570Sbostic 	(void)printf("%9lu total calls to xfree", xstats.free);
50348570Sbostic 	(void)printf(" (sticky %lu cached %lu swapped %lu)\n",
50425512Ssam 	    xstats.free_inuse, xstats.free_cache, xstats.free_cacheswap);
50525960Ssam #if defined(tahoe)
50648570Sbostic 	kread(X_CKEYSTATS, &keystats, sizeof(keystats));
50748570Sbostic 	(void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
50825960Ssam 	    keystats.ks_allocs, "code cache keys allocated",
50945834Sbostic 	    PCT(keystats.ks_allocfree, keystats.ks_allocs),
51045834Sbostic 	    PCT(keystats.ks_norefs, keystats.ks_allocs),
51145834Sbostic 	    PCT(keystats.ks_taken, keystats.ks_allocs),
51245834Sbostic 	    PCT(keystats.ks_shared, keystats.ks_allocs));
51348570Sbostic 	kread(X_DKEYSTATS, &keystats, sizeof(keystats));
51448570Sbostic 	(void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
51525960Ssam 	    keystats.ks_allocs, "data cache keys allocated",
51645834Sbostic 	    PCT(keystats.ks_allocfree, keystats.ks_allocs),
51745834Sbostic 	    PCT(keystats.ks_norefs, keystats.ks_allocs),
51845834Sbostic 	    PCT(keystats.ks_taken, keystats.ks_allocs),
51945834Sbostic 	    PCT(keystats.ks_shared, keystats.ks_allocs));
52025960Ssam #endif
5211155Sbill }
5221155Sbill 
52348570Sbostic void
5241155Sbill doforkst()
5251155Sbill {
52648570Sbostic 	struct forkstat fks;
5271155Sbill 
52848570Sbostic 	kread(X_FORKSTAT, &fks, sizeof(struct forkstat));
52948570Sbostic 	(void)printf("%d forks, %d pages, average %.2f\n",
53048570Sbostic 	    fks.cntfork, fks.sizfork, (double)fks.sizfork / fks.cntfork);
53148570Sbostic 	(void)printf("%d vforks, %d pages, average %.2f\n",
53248570Sbostic 	    fks.cntvfork, fks.sizvfork, (double)fks.sizvfork / fks.cntvfork);
5331155Sbill }
5341155Sbill 
53548570Sbostic void
53648613Sbostic dkstats()
5371155Sbill {
53848613Sbostic 	register int dn, state;
53948613Sbostic 	double etime;
54048613Sbostic 	long tmp;
54148613Sbostic 
54248613Sbostic 	for (dn = 0; dn < dk_ndrive; ++dn) {
54348613Sbostic 		tmp = cur.xfer[dn];
54448613Sbostic 		cur.xfer[dn] -= last.xfer[dn];
54548613Sbostic 		last.xfer[dn] = tmp;
54648613Sbostic 	}
54748613Sbostic 	etime = 0;
54848613Sbostic 	for (state = 0; state < CPUSTATES; ++state) {
54948613Sbostic 		tmp = cur.time[state];
55048613Sbostic 		cur.time[state] -= last.time[state];
55148613Sbostic 		last.time[state] = tmp;
55248613Sbostic 		etime += cur.time[state];
55348613Sbostic 	}
55448613Sbostic 	if (etime == 0)
55548613Sbostic 		etime = 1;
55648613Sbostic 	etime /= hz;
55748613Sbostic 	for (dn = 0; dn < dk_ndrive; ++dn) {
55848613Sbostic 		if (!dr_select[dn])
55948613Sbostic 			continue;
56048570Sbostic 		(void)printf("%3.0f", cur.xfer[dn] / etime);
56148613Sbostic 	}
5621155Sbill }
5631155Sbill 
56448613Sbostic void
56548613Sbostic cpustats()
5661155Sbill {
56748613Sbostic 	register int state;
56848613Sbostic 	double pct, total;
5691155Sbill 
57048613Sbostic 	total = 0;
57148613Sbostic 	for (state = 0; state < CPUSTATES; ++state)
57248613Sbostic 		total += cur.time[state];
57348613Sbostic 	if (total)
57448613Sbostic 		pct = 100 / total;
57548613Sbostic 	else
57648613Sbostic 		pct = 0;
57748613Sbostic 	(void)printf("%3.0f",				/* user + nice */
57848613Sbostic 	    (cur.time[0] + cur.time[1]) * pct);
57948613Sbostic 	(void)printf("%3.0f", cur.time[2] * pct);	/* system */
58048613Sbostic 	(void)printf("%3.0f", cur.time[3] * pct);	/* idle */
5811155Sbill }
5821155Sbill 
58348570Sbostic void
58445834Sbostic dointr()
5851155Sbill {
58648570Sbostic 	register long *intrcnt, inttotal, uptime;
58745834Sbostic 	register int nintr, inamlen;
58845834Sbostic 	register char *intrname;
5891155Sbill 
59048570Sbostic 	uptime = getuptime();
59145834Sbostic 	nintr = nl[X_EINTRCNT].n_value - nl[X_INTRCNT].n_value;
59245834Sbostic 	inamlen = nl[X_EINTRNAMES].n_value - nl[X_INTRNAMES].n_value;
59348570Sbostic 	intrcnt = malloc((size_t)nintr);
59445834Sbostic 	intrname = malloc((size_t)inamlen);
59517262Smckusick 	if (intrcnt == NULL || intrname == NULL) {
59648570Sbostic 		(void)fprintf(stderr, "vmstat: %s.\n", strerror(errno));
59748570Sbostic 		exit(1);
59817262Smckusick 	}
59948570Sbostic 	kread(X_INTRCNT, intrcnt, (size_t)nintr);
60045834Sbostic 	kread(X_INTRNAMES, intrname, (size_t)inamlen);
60148570Sbostic 	(void)printf("interrupt      total      rate\n");
60217262Smckusick 	inttotal = 0;
60345834Sbostic 	nintr /= sizeof(long);
60445834Sbostic 	while (--nintr >= 0) {
60517262Smckusick 		if (*intrcnt)
60648570Sbostic 			(void)printf("%-12s %8ld %8ld\n", intrname,
60745834Sbostic 			    *intrcnt, *intrcnt / uptime);
60817262Smckusick 		intrname += strlen(intrname) + 1;
60917262Smckusick 		inttotal += *intrcnt++;
61017262Smckusick 	}
61148570Sbostic 	(void)printf("Total        %8ld %8ld\n", inttotal, inttotal / uptime);
61217262Smckusick }
61317262Smckusick 
61433610Smckusick /*
61545152Smckusick  * These names are defined in <sys/malloc.h>.
61633610Smckusick  */
61745152Smckusick char *kmemnames[] = INITKMEMNAMES;
61833610Smckusick 
61948570Sbostic void
62033610Smckusick domem()
62133610Smckusick {
62245834Sbostic 	register struct kmembuckets *kp;
62345834Sbostic 	register struct kmemstats *ks;
62445834Sbostic 	register int i;
62533610Smckusick 	struct kmemstats kmemstats[M_LAST];
62633610Smckusick 	struct kmembuckets buckets[MINBUCKET + 16];
62733610Smckusick 
62848570Sbostic 	kread(X_KMEMBUCKETS, buckets, sizeof(buckets));
62948570Sbostic 	(void)printf("Memory statistics by bucket size\n");
63048570Sbostic 	(void)printf(
63145834Sbostic 	    "    Size   In Use   Free   Requests  HighWater  Couldfree\n");
63233610Smckusick 	for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) {
63333610Smckusick 		if (kp->kb_calls == 0)
63433610Smckusick 			continue;
63548570Sbostic 		(void)printf("%8d%9ld%7ld%11ld%8ld%11ld\n", 1 << i,
63633610Smckusick 			kp->kb_total - kp->kb_totalfree,
63733610Smckusick 			kp->kb_totalfree, kp->kb_calls,
63833610Smckusick 			kp->kb_highwat, kp->kb_couldfree);
63933610Smckusick 
64033610Smckusick 	}
64148570Sbostic 	kread(X_KMEMSTAT, kmemstats, sizeof(kmemstats));
64248570Sbostic 	(void)printf("\nMemory statistics by type\n");
64348570Sbostic 	(void)printf(
64448570Sbostic "      Type  In Use  MemUse   HighUse  Limit Requests  TypeLimit KernLimit\n");
64533610Smckusick 	for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
64633610Smckusick 		if (ks->ks_calls == 0)
64733610Smckusick 			continue;
64848570Sbostic 		(void)printf("%10s%7ld%8ldK%9ldK%6ldK%9ld%7u%10u\n",
64948570Sbostic 		    kmemnames[i] ? kmemnames[i] : "undefined",
65048570Sbostic 		    ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
65148570Sbostic 		    (ks->ks_maxused + 1023) / 1024,
65248570Sbostic 		    (ks->ks_limit + 1023) / 1024, ks->ks_calls,
65348570Sbostic 		    ks->ks_limblocks, ks->ks_mapblocks);
65433610Smckusick 	}
65533610Smckusick }
65633610Smckusick 
65748570Sbostic void
65848570Sbostic zero()
6593162Stoy {
660*49924Sbostic 	static struct nlist znl[] = {
66148570Sbostic #undef	X_SUM
66248570Sbostic #define X_SUM		0
66348570Sbostic 		{ "_sum" },
66448570Sbostic 		{ "" },
66548570Sbostic 	};
66648570Sbostic 	int fd;
66748570Sbostic 	char *kmem;
6683162Stoy 
66948570Sbostic 	if (geteuid()) {
67048570Sbostic 		(void)fprintf(stderr, "vmstat: %s\n", strerror(EPERM));
6713162Stoy 		exit(1);
6723162Stoy 	}
67348570Sbostic 	/*
67448570Sbostic 	 * Zeroing the statistics is fundamentally different
67548570Sbostic 	 * (and really belongs in a separate program).
67648570Sbostic 	 */
67748570Sbostic 	if (nlist(vmunix, znl) || nl[0].n_type == 0) {
67848570Sbostic 		(void)fprintf(stderr, "vmstat: %s: symbol %s not found\n",
67948570Sbostic 		    vmunix, nl[0].n_name);
68048570Sbostic 		exit(1);
6813162Stoy 	}
68248570Sbostic 
68348570Sbostic 	kmem = _PATH_KMEM;
68448570Sbostic 	if ((fd = open(kmem, O_RDWR)) < 0) {
68548570Sbostic 		(void)fprintf(stderr,
68648570Sbostic 		    "vmstat: %s: %s\n", kmem, strerror(errno));
68748570Sbostic 		exit(1);
6883162Stoy 	}
68948570Sbostic 	if (lseek(fd, (long)nl[0].n_value, L_SET) == -1 ||
69048570Sbostic 	    write(fd, &sum, sizeof(sum)) != sizeof(sum)) {
69148570Sbostic 		(void)fprintf(stderr,
69248570Sbostic 		    "vmstat: %s: %s\n", kmem, strerror(errno));
69348570Sbostic 		exit(1);
69448570Sbostic 	}
6953162Stoy }
69625708Ssam 
69725708Ssam /*
69848570Sbostic  * kread reads something from the kernel, given its nlist index.
69925708Ssam  */
70048570Sbostic void
70148570Sbostic kread(nlx, addr, size)
70248570Sbostic 	int nlx;
70348570Sbostic 	void *addr;
70448570Sbostic 	size_t size;
70525708Ssam {
70648570Sbostic 	char *sym;
70725708Ssam 
70848570Sbostic 	if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) {
70948570Sbostic 		sym = nl[nlx].n_name;
71048570Sbostic 		if (*sym == '_')
71148570Sbostic 			++sym;
71248570Sbostic 		(void)fprintf(stderr,
71348570Sbostic 		    "vmstat: %s: symbol %s not defined\n", vmunix, sym);
71425708Ssam 		exit(1);
71525708Ssam 	}
71648570Sbostic 	if (kvm_read((void *)nl[nlx].n_value, addr, size) != size) {
71748570Sbostic 		sym = nl[nlx].n_name;
71848570Sbostic 		if (*sym == '_')
71948570Sbostic 			++sym;
72048570Sbostic 		(void)fprintf(stderr, "vmstat: %s: %s\n", sym, kvm_geterr());
72148570Sbostic 		exit(1);
72225708Ssam 	}
72325708Ssam }
72442952Sbostic 
72548570Sbostic void
72648570Sbostic usage()
72742952Sbostic {
72848570Sbostic 	(void)fprintf(stderr,
72948570Sbostic 	    "usage: vmstat [-fimst] [-c count] [-M core] \
73048570Sbostic [-N system] [-w wait] [disks]\n       vmstat -z\n");
73148570Sbostic 	exit(1);
73242952Sbostic }
733