xref: /csrg-svn/usr.bin/vmstat/vmstat.c (revision 48570)
121585Sdist /*
2*48570Sbostic  * 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[] =
10*48570Sbostic "@(#) 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*48570Sbostic static char sccsid[] = "@(#)vmstat.c	5.25 (Berkeley) 04/23/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>
26*48570Sbostic #include <signal.h>
27*48570Sbostic #include <fcntl.h>
28*48570Sbostic #include <time.h>
29*48570Sbostic #include <nlist.h>
30*48570Sbostic #include <kvm.h>
3145834Sbostic #include <errno.h>
32*48570Sbostic #include <unistd.h>
3345834Sbostic #include <stdio.h>
34*48570Sbostic #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" },
52*48570Sbostic #define	X_BOOTTIME	6
539249Ssam 	{ "_boottime" },
54*48570Sbostic #define	X_DKXFER	7
551448Sbill 	{ "_dk_xfer" },
56*48570Sbostic #define X_REC		8
571155Sbill 	{ "_rectime" },
58*48570Sbostic #define X_PGIN		9
591155Sbill 	{ "_pgintime" },
60*48570Sbostic #define X_HZ		10
613162Stoy 	{ "_hz" },
62*48570Sbostic #define X_PHZ		11
6315266Ssam 	{ "_phz" },
64*48570Sbostic #define X_NCHSTATS	12
6515807Smckusick 	{ "_nchstats" },
66*48570Sbostic #define	X_INTRNAMES	13
6717262Smckusick 	{ "_intrnames" },
68*48570Sbostic #define	X_EINTRNAMES	14
6917262Smckusick 	{ "_eintrnames" },
70*48570Sbostic #define	X_INTRCNT	15
7117262Smckusick 	{ "_intrcnt" },
72*48570Sbostic #define	X_EINTRCNT	16
7317262Smckusick 	{ "_eintrcnt" },
74*48570Sbostic #define	X_DK_NDRIVE	17
7518761Ssam 	{ "_dk_ndrive" },
76*48570Sbostic #define	X_XSTATS	18
7725512Ssam 	{ "_xstats" },
78*48570Sbostic #define	X_KMEMSTAT	19
7933610Smckusick 	{ "_kmemstats" },
80*48570Sbostic #define	X_KMEMBUCKETS	20
8133610Smckusick 	{ "_bucket" },
82*48570Sbostic #define X_END		20
83*48570Sbostic #ifdef hp300
84*48570Sbostic #define	X_HPDINIT	(X_END+1)
85*48570Sbostic 	{ "_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
95*48570Sbostic #ifdef vax
96*48570Sbostic #define X_MBDINIT	(X_END+1)
97*48570Sbostic 	{ "_mbdinit" },
98*48570Sbostic #define X_UBDINIT	(X_END+2)
99*48570Sbostic 	{ "_ubdinit" },
10042952Sbostic #endif
10110826Ssam 	{ "" },
1021155Sbill };
1031155Sbill 
104*48570Sbostic struct _disk {
105*48570Sbostic 	long time[CPUSTATES];
106*48570Sbostic 	long *xfer;
107*48570Sbostic } cur, last;
10818761Ssam 
109*48570Sbostic struct vmmeter sum;
110*48570Sbostic double etime, stat1();
111*48570Sbostic char *vmunix = _PATH_UNIX;
112*48570Sbostic char **dr_name;
113*48570Sbostic int *dr_select, dk_ndrive, ndrives;
1141155Sbill 
11545834Sbostic #define	FORKSTAT	0x01
11645834Sbostic #define	INTRSTAT	0x02
11745834Sbostic #define	MEMSTAT		0x04
11845834Sbostic #define	SUMSTAT		0x08
11945834Sbostic #define	TIMESTAT	0x10
12045834Sbostic #define	VMSTAT		0x20
12145834Sbostic #define	ZEROOUT		0x40
12245834Sbostic 
123*48570Sbostic void kread();
124*48570Sbostic 
125*48570Sbostic #include "names.c"			/* disk names -- machine dependent */
126*48570Sbostic 
127*48570Sbostic void doforkst(), dointr(), domem(), dosum(), dotimes(), dovmstat();
128*48570Sbostic void stats(), usage(), zero();
129*48570Sbostic 
1301155Sbill main(argc, argv)
13145834Sbostic 	register int argc;
13245834Sbostic 	register char **argv;
1331155Sbill {
13445834Sbostic 	extern int optind;
13545834Sbostic 	extern char *optarg;
136*48570Sbostic 	register int c, todo;
137*48570Sbostic 	u_int interval;
138*48570Sbostic 	int reps;
139*48570Sbostic 	char *kmem;
1401155Sbill 
141*48570Sbostic 	kmem = NULL;
142*48570Sbostic 	interval = reps = todo = 0;
143*48570Sbostic 	while ((c = getopt(argc, argv, "c:fiM:mN:stw:z")) != EOF) {
14445834Sbostic 		switch (c) {
145*48570Sbostic 		case 'c':
146*48570Sbostic 			reps = atoi(optarg);
147*48570Sbostic 			break;
14845834Sbostic 		case 'f':
14945834Sbostic 			todo |= FORKSTAT;
15045834Sbostic 			break;
15145834Sbostic 		case 'i':
15245834Sbostic 			todo |= INTRSTAT;
15345834Sbostic 			break;
154*48570Sbostic 		case 'M':
15545834Sbostic 			kmem = optarg;
15645834Sbostic 			break;
15745834Sbostic 		case 'm':
15845834Sbostic 			todo |= MEMSTAT;
15945834Sbostic 			break;
160*48570Sbostic 		case 'N':
161*48570Sbostic 			vmunix = optarg;
162*48570Sbostic 			break;
16345834Sbostic 		case 's':
16445834Sbostic 			todo |= SUMSTAT;
16545834Sbostic 			break;
16645834Sbostic 		case 't':
16745834Sbostic 			todo |= TIMESTAT;
16845834Sbostic 			break;
169*48570Sbostic 		case 'w':
170*48570Sbostic 			interval = atoi(optarg);
17145834Sbostic 			break;
17245834Sbostic 		case 'z':
17345834Sbostic 			todo |= ZEROOUT;
17445834Sbostic 			break;
17545834Sbostic 		case '?':
176*48570Sbostic 		default:
17745834Sbostic 			usage();
17845834Sbostic 		}
17945834Sbostic 	}
180*48570Sbostic 	argc -= optind;
181*48570Sbostic 	argv += optind;
18245834Sbostic 
18345834Sbostic 	if (todo & ZEROOUT) {
18445834Sbostic 		if (todo & ~ZEROOUT || kmem)
18545834Sbostic 			usage();
186*48570Sbostic 		zero();
18745834Sbostic 		exit(0);
18845834Sbostic 	}
18945834Sbostic 
19045834Sbostic 	if (todo == 0)
19145834Sbostic 		todo = VMSTAT;
19245834Sbostic 
193*48570Sbostic 	if (kvm_openfiles(vmunix, kmem, NULL) < 0) {
194*48570Sbostic 		(void)fprintf(stderr,
195*48570Sbostic 		    "vmstat: kvm_openfiles: %s\n", kvm_geterr());
1961155Sbill 		exit(1);
1971155Sbill 	}
19845834Sbostic 
199*48570Sbostic 	(void)kvm_nlist(nl);
20045834Sbostic 	if (nl[0].n_type == 0) {
201*48570Sbostic 		(void)fprintf(stderr,
202*48570Sbostic 		    "vmstat: %s: no namelist\n", vmunix);
2031155Sbill 		exit(1);
2041155Sbill 	}
2051155Sbill 
206*48570Sbostic 	if (todo & VMSTAT) {
207*48570Sbostic 		char **getdrivedata();
208*48570Sbostic 
209*48570Sbostic 		argv = getdrivedata(argv);
210*48570Sbostic 	}
211*48570Sbostic 
212*48570Sbostic #define	BACKWARD_COMPATIBILITY
213*48570Sbostic #ifdef	BACKWARD_COMPATIBILITY
214*48570Sbostic 	if (*argv) {
215*48570Sbostic 		interval = atoi(*argv);
216*48570Sbostic 		if (*++argv)
217*48570Sbostic 			reps = atoi(*argv);
218*48570Sbostic 	}
219*48570Sbostic #endif
220*48570Sbostic 
22145834Sbostic 	if (todo & FORKSTAT)
22245834Sbostic 		doforkst();
22345834Sbostic 	if (todo & MEMSTAT)
22445834Sbostic 		domem();
22545834Sbostic 	if (todo & SUMSTAT)
22645834Sbostic 		dosum();
22745834Sbostic 	if (todo & TIMESTAT)
22845834Sbostic 		dotimes();
22945834Sbostic 	if (todo & INTRSTAT)
23045834Sbostic 		dointr();
231*48570Sbostic 	if (todo & VMSTAT)
232*48570Sbostic 		dovmstat(interval, reps);
23345834Sbostic 	exit(0);
23445834Sbostic }
23510826Ssam 
236*48570Sbostic char **
237*48570Sbostic getdrivedata(argv)
23845834Sbostic 	char **argv;
23945834Sbostic {
24045834Sbostic 	register int i;
24145834Sbostic 	register char **cp;
24245834Sbostic 	char buf[30];
24345834Sbostic 
244*48570Sbostic 	kread(X_DK_NDRIVE, &dk_ndrive, sizeof(dk_ndrive));
24518761Ssam 	if (dk_ndrive <= 0) {
246*48570Sbostic 		(void)fprintf(stderr, "vmstat: dk_ndrive %d\n", dk_ndrive);
24718761Ssam 		exit(1);
24818761Ssam 	}
249*48570Sbostic 	dr_select = calloc((size_t)dk_ndrive, sizeof(int));
250*48570Sbostic 	dr_name = calloc((size_t)dk_ndrive, sizeof(char *));
25145834Sbostic 	for (i = 0; i < dk_ndrive; i++)
25245834Sbostic 		dr_name[i] = NULL;
253*48570Sbostic 	cur.xfer = calloc((size_t)dk_ndrive, sizeof(long));
254*48570Sbostic 	last.xfer = calloc((size_t)dk_ndrive, sizeof(long));
2553162Stoy 	read_names();
256*48570Sbostic 	for (i = 0; i < dk_ndrive; i++)
25745834Sbostic 		if (dr_name[i] == NULL) {
258*48570Sbostic 			(void)sprintf(buf, "??%d", i);
25945834Sbostic 			dr_name[i] = strdup(buf);
26045834Sbostic 		}
26145834Sbostic 
26218761Ssam 	/*
263*48570Sbostic 	 * Choose drives to be displayed.  Priority goes to (in order) drives
264*48570Sbostic 	 * supplied as arguments, default drives.  If everything isn't filled
265*48570Sbostic 	 * in and there are drives not taken care of, display the first few
266*48570Sbostic 	 * that fit.
26718761Ssam 	 */
268*48570Sbostic #define BACKWARD_COMPATIBILITY
269*48570Sbostic 	for (ndrives = 0; *argv; ++argv) {
270*48570Sbostic #ifdef	BACKWARD_COMPATIBILITY
271*48570Sbostic 		if (isdigit(**argv))
272*48570Sbostic 			break;
273*48570Sbostic #endif
27418761Ssam 		for (i = 0; i < dk_ndrive; i++) {
275*48570Sbostic 			if (strcmp(dr_name[i], *argv))
27618761Ssam 				continue;
27718761Ssam 			dr_select[i] = 1;
278*48570Sbostic 			++ndrives;
27945834Sbostic 			break;
28018761Ssam 		}
28118761Ssam 	}
28218761Ssam 	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
28318761Ssam 		if (dr_select[i])
28418761Ssam 			continue;
28518761Ssam 		for (cp = defdrives; *cp; cp++)
28618761Ssam 			if (strcmp(dr_name[i], *cp) == 0) {
28718761Ssam 				dr_select[i] = 1;
288*48570Sbostic 				++ndrives;
28918761Ssam 				break;
29018761Ssam 			}
29118761Ssam 	}
29218761Ssam 	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
29318761Ssam 		if (dr_select[i])
29418761Ssam 			continue;
29518761Ssam 		dr_select[i] = 1;
296*48570Sbostic 		++ndrives;
29718761Ssam 	}
298*48570Sbostic 	return(argv);
29945834Sbostic }
30045834Sbostic 
30145834Sbostic long
30245834Sbostic getuptime()
30345834Sbostic {
304*48570Sbostic 	static time_t now, boottime;
305*48570Sbostic 	time_t uptime;
30645834Sbostic 
30745834Sbostic 	if (boottime == 0)
308*48570Sbostic 		kread(X_BOOTTIME, &boottime, sizeof(boottime));
309*48570Sbostic 	(void)time(&now);
31045834Sbostic 	uptime = now - boottime;
31145834Sbostic 	if (uptime <= 0 || uptime > 60*60*24*365*10) {
312*48570Sbostic 		(void)fprintf(stderr,
31345834Sbostic 		    "vmstat: time makes no sense; namelist must be wrong.\n");
31445834Sbostic 		exit(1);
31545834Sbostic 	}
316*48570Sbostic 	return(uptime);
31745834Sbostic }
31845834Sbostic 
319*48570Sbostic void
320*48570Sbostic dovmstat(interval, reps)
321*48570Sbostic 	u_int interval;
322*48570Sbostic 	int reps;
32345834Sbostic {
324*48570Sbostic 	struct vmmeter rate;
325*48570Sbostic 	struct vmtotal total;
32645834Sbostic 	register int i;
327*48570Sbostic 	time_t uptime;
328*48570Sbostic 	long tmp;
329*48570Sbostic 	int deficit, hdrcnt, HZ, hz, phz;
330*48570Sbostic 	void printhdr();
33145834Sbostic 
332*48570Sbostic 	uptime = getuptime();
333*48570Sbostic 	(void)signal(SIGCONT, printhdr);
334*48570Sbostic 
335*48570Sbostic 	kread(X_HZ, &hz, sizeof(hz));
336*48570Sbostic 	if (nl[X_PHZ].n_type != 0 && nl[X_PHZ].n_value != 0)
337*48570Sbostic 		kread(X_PHZ, &phz, sizeof(phz));
338*48570Sbostic 	HZ = phz ? phz : hz;
339*48570Sbostic 
340*48570Sbostic 	for (hdrcnt = 1;;) {
341*48570Sbostic 		if (!--hdrcnt) {
342*48570Sbostic 			printhdr();
343*48570Sbostic 			hdrcnt = 20;
344*48570Sbostic 		}
345*48570Sbostic 		kread(X_CPTIME, cur.time, sizeof(cur.time));
346*48570Sbostic 		kread(X_DKXFER, cur.xfer, sizeof(*cur.xfer * dk_ndrive));
347*48570Sbostic 		if (uptime != 1)
348*48570Sbostic 			kread(X_SUM, &rate, sizeof(rate));
349*48570Sbostic 		else
350*48570Sbostic 			kread(X_RATE, &rate, sizeof(rate));
351*48570Sbostic 		kread(X_TOTAL, &total, sizeof(total));
352*48570Sbostic 		kread(X_SUM, &sum, sizeof(sum));
353*48570Sbostic 		kread(X_DEFICIT, &deficit, sizeof(deficit));
354*48570Sbostic 		etime = 0;
355*48570Sbostic 		for (i = 0; i < dk_ndrive; i++) {
356*48570Sbostic 			tmp = cur.xfer[i];
357*48570Sbostic 			cur.xfer[i] -= last.xfer[i];
358*48570Sbostic 			last.xfer[i] = tmp;
359*48570Sbostic 		}
360*48570Sbostic 		for (i = 0; i < CPUSTATES; i++) {
361*48570Sbostic 			tmp = cur.time[i];
362*48570Sbostic 			cur.time[i] -= last.time[i];
363*48570Sbostic 			last.time[i] = tmp;
364*48570Sbostic 			etime += cur.time[i];
365*48570Sbostic 		}
366*48570Sbostic 		if (etime == 0.)
367*48570Sbostic 			etime = 1.;
368*48570Sbostic 		(void)printf("%2d%2d%2d",
369*48570Sbostic 		    total.t_rq, total.t_dw + total.t_pw, total.t_sw);
37045834Sbostic #define pgtok(a) ((a)*NBPG >> 10)
371*48570Sbostic 		(void)printf("%6ld%6ld",
372*48570Sbostic 		    pgtok(total.t_avm), pgtok(total.t_free));
373*48570Sbostic 		(void)printf("%4lu%3lu",
374*48570Sbostic 		    (rate.v_pgrec - (rate.v_xsfrec+rate.v_xifrec)) / uptime,
375*48570Sbostic 		    (rate.v_xsfrec+rate.v_xifrec) / uptime);
376*48570Sbostic 		(void)printf("%4lu", pgtok(rate.v_pgpgin) / uptime);
377*48570Sbostic 		(void)printf("%4lu%4lu%4d%4lu", pgtok(rate.v_pgpgout) / uptime,
378*48570Sbostic 		    pgtok(rate.v_dfree) / uptime,
379*48570Sbostic 		    pgtok(deficit), rate.v_scan / uptime);
380*48570Sbostic 		etime /= (float)HZ;
381*48570Sbostic 		for (i = 0; i < dk_ndrive; i++)
382*48570Sbostic 			if (dr_select[i])
383*48570Sbostic 				stats(i);
384*48570Sbostic #define	INTS(x)	((x) - (hz + phz))
385*48570Sbostic 		(void)printf("%4lu%4lu%4lu", INTS(rate.v_intr / uptime),
386*48570Sbostic 		    rate.v_syscall / uptime, rate.v_swtch / uptime);
387*48570Sbostic 		for (i = 0; i < CPUSTATES; i++) {
388*48570Sbostic 			double f;
389*48570Sbostic 
390*48570Sbostic 			f = stat1(i);
391*48570Sbostic 			if (i == 0) {		/* US+NI */
392*48570Sbostic 				i++;
393*48570Sbostic 				f += stat1(i);
394*48570Sbostic 			}
395*48570Sbostic 			(void)printf("%3.0f", f);
3961155Sbill 		}
397*48570Sbostic 		(void)printf("\n");
398*48570Sbostic 		(void)fflush(stdout);
399*48570Sbostic 		uptime = 1;
400*48570Sbostic 		if (--reps <= 0)
401*48570Sbostic 			break;
402*48570Sbostic 		if (interval)
403*48570Sbostic 			sleep(interval);
4041155Sbill 	}
4051155Sbill }
4061155Sbill 
40745834Sbostic void
40817262Smckusick printhdr()
40917262Smckusick {
410*48570Sbostic 	register int i;
41118761Ssam 
412*48570Sbostic 	(void)printf(" procs   memory     page%*s", 22, "");
413*48570Sbostic 	if (ndrives > 1)
414*48570Sbostic 		(void)printf("disks %*s faults     cpu\n",
415*48570Sbostic 		   ndrives * 3 - 6, "");
416*48570Sbostic 	else
417*48570Sbostic 		(void)printf("%*s faults     cpu\n", ndrives * 3, "");
418*48570Sbostic 	(void)printf(" r b w   avm   fre  re at  pi  po  fr  de  sr ");
41918761Ssam 	for (i = 0; i < dk_ndrive; i++)
42018761Ssam 		if (dr_select[i])
421*48570Sbostic 			(void)printf("%c%c ", dr_name[i][0],
42245834Sbostic 			    dr_name[i][strlen(dr_name[i]) - 1]);
423*48570Sbostic 	(void)printf(" in  sy  cs us sy id\n");
42417262Smckusick }
42517262Smckusick 
426*48570Sbostic void
4271155Sbill dotimes()
4281155Sbill {
429*48570Sbostic 	u_int pgintime, rectime;
4301155Sbill 
431*48570Sbostic 	kread(X_REC, &rectime, sizeof(rectime));
432*48570Sbostic 	kread(X_PGIN, &pgintime, sizeof(pgintime));
433*48570Sbostic 	kread(X_SUM, &sum, sizeof(sum));
434*48570Sbostic 	(void)printf("%u reclaims, %u total time (usec)\n",
435*48570Sbostic 	    sum.v_pgrec, rectime);
436*48570Sbostic 	(void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec);
437*48570Sbostic 	(void)printf("\n");
438*48570Sbostic 	(void)printf("%u page ins, %u total time (msec)\n",
439*48570Sbostic 	    sum.v_pgin, pgintime / 10);
440*48570Sbostic 	(void)printf("average: %8.1f msec / page in\n",
441*48570Sbostic 	    pgintime / (sum.v_pgin * 10.0));
4421155Sbill }
4431155Sbill 
44445834Sbostic pct(top, bot)
44545834Sbostic 	long top, bot;
44645834Sbostic {
44745834Sbostic 	if (bot == 0)
448*48570Sbostic 		return(0);
449*48570Sbostic 	return((top * 100) / bot);
45045834Sbostic }
45145834Sbostic 
45245834Sbostic #define	PCT(top, bot) pct((long)(top), (long)(bot))
45345834Sbostic 
45430069Ssam #if defined(tahoe)
45545834Sbostic #include <machine/cpu.h>
45630069Ssam #endif
45730069Ssam 
458*48570Sbostic void
4591155Sbill dosum()
4601155Sbill {
46118761Ssam 	struct nchstats nchstats;
46225960Ssam 	struct xstats xstats;
46315807Smckusick 	long nchtotal;
46425960Ssam #if defined(tahoe)
46525960Ssam 	struct keystats keystats;
46625960Ssam #endif
4671155Sbill 
468*48570Sbostic 	kread(X_SUM, &sum, sizeof(sum));
469*48570Sbostic 	(void)printf("%9u swap ins\n", sum.v_swpin);
470*48570Sbostic 	(void)printf("%9u swap outs\n", sum.v_swpout);
471*48570Sbostic 	(void)printf("%9u pages swapped in\n", sum.v_pswpin / CLSIZE);
472*48570Sbostic 	(void)printf("%9u pages swapped out\n", sum.v_pswpout / CLSIZE);
473*48570Sbostic 	(void)printf("%9u total address trans. faults taken\n", sum.v_faults);
474*48570Sbostic 	(void)printf("%9u page ins\n", sum.v_pgin);
475*48570Sbostic 	(void)printf("%9u page outs\n", sum.v_pgout);
476*48570Sbostic 	(void)printf("%9u pages paged in\n", sum.v_pgpgin);
477*48570Sbostic 	(void)printf("%9u pages paged out\n", sum.v_pgpgout);
478*48570Sbostic 	(void)printf("%9u sequential process pages freed\n", sum.v_seqfree);
479*48570Sbostic 	(void)printf("%9u total reclaims (%d%% fast)\n", sum.v_pgrec,
48045834Sbostic 	    PCT(sum.v_fastpgrec, sum.v_pgrec));
481*48570Sbostic 	(void)printf("%9u reclaims from free list\n", sum.v_pgfrec);
482*48570Sbostic 	(void)printf("%9u intransit blocking page faults\n", sum.v_intrans);
483*48570Sbostic 	(void)printf("%9u zero fill pages created\n", sum.v_nzfod / CLSIZE);
484*48570Sbostic 	(void)printf("%9u zero fill page faults\n", sum.v_zfod / CLSIZE);
485*48570Sbostic 	(void)printf("%9u executable fill pages created\n",
48645834Sbostic 	    sum.v_nexfod / CLSIZE);
487*48570Sbostic 	(void)printf("%9u executable fill page faults\n",
48845834Sbostic 	    sum.v_exfod / CLSIZE);
489*48570Sbostic 	(void)printf("%9u swap text pages found in free list\n",
49045834Sbostic 	    sum.v_xsfrec);
491*48570Sbostic 	(void)printf("%9u inode text pages found in free list\n",
49245834Sbostic 	    sum.v_xifrec);
493*48570Sbostic 	(void)printf("%9u file fill pages created\n", sum.v_nvrfod / CLSIZE);
494*48570Sbostic 	(void)printf("%9u file fill page faults\n", sum.v_vrfod / CLSIZE);
495*48570Sbostic 	(void)printf("%9u pages examined by the clock daemon\n", sum.v_scan);
496*48570Sbostic 	(void)printf("%9u revolutions of the clock hand\n", sum.v_rev);
497*48570Sbostic 	(void)printf("%9u pages freed by the clock daemon\n",
49845834Sbostic 	    sum.v_dfree / CLSIZE);
499*48570Sbostic 	(void)printf("%9u cpu context switches\n", sum.v_swtch);
500*48570Sbostic 	(void)printf("%9u device interrupts\n", sum.v_intr);
501*48570Sbostic 	(void)printf("%9u software interrupts\n", sum.v_soft);
50218761Ssam #ifdef vax
503*48570Sbostic 	(void)printf("%9u pseudo-dma dz interrupts\n", sum.v_pdma);
50418761Ssam #endif
505*48570Sbostic 	(void)printf("%9u traps\n", sum.v_trap);
506*48570Sbostic 	(void)printf("%9u system calls\n", sum.v_syscall);
507*48570Sbostic 	kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
50838773Smckusick 	nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
50938773Smckusick 	    nchstats.ncs_badhits + nchstats.ncs_falsehits +
51038773Smckusick 	    nchstats.ncs_miss + nchstats.ncs_long;
511*48570Sbostic 	(void)printf("%9ld total name lookups\n", nchtotal);
512*48570Sbostic 	(void)printf(
51345834Sbostic 	    "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
51445834Sbostic 	    "", PCT(nchstats.ncs_goodhits, nchtotal),
51545834Sbostic 	    PCT(nchstats.ncs_neghits, nchtotal),
51645834Sbostic 	    PCT(nchstats.ncs_pass2, nchtotal));
517*48570Sbostic 	(void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
51845834Sbostic 	    PCT(nchstats.ncs_badhits, nchtotal),
51945834Sbostic 	    PCT(nchstats.ncs_falsehits, nchtotal),
52045834Sbostic 	    PCT(nchstats.ncs_long, nchtotal));
521*48570Sbostic 	kread(X_XSTATS, &xstats, sizeof(xstats));
522*48570Sbostic 	(void)printf("%9lu total calls to xalloc (cache hits %d%%)\n",
52345834Sbostic 	    xstats.alloc, PCT(xstats.alloc_cachehit, xstats.alloc));
524*48570Sbostic 	(void)printf("%9s sticky %lu flushed %lu unused %lu\n", "",
52525512Ssam 	    xstats.alloc_inuse, xstats.alloc_cacheflush, xstats.alloc_unused);
526*48570Sbostic 	(void)printf("%9lu total calls to xfree", xstats.free);
527*48570Sbostic 	(void)printf(" (sticky %lu cached %lu swapped %lu)\n",
52825512Ssam 	    xstats.free_inuse, xstats.free_cache, xstats.free_cacheswap);
52925960Ssam #if defined(tahoe)
530*48570Sbostic 	kread(X_CKEYSTATS, &keystats, sizeof(keystats));
531*48570Sbostic 	(void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
53225960Ssam 	    keystats.ks_allocs, "code cache keys allocated",
53345834Sbostic 	    PCT(keystats.ks_allocfree, keystats.ks_allocs),
53445834Sbostic 	    PCT(keystats.ks_norefs, keystats.ks_allocs),
53545834Sbostic 	    PCT(keystats.ks_taken, keystats.ks_allocs),
53645834Sbostic 	    PCT(keystats.ks_shared, keystats.ks_allocs));
537*48570Sbostic 	kread(X_DKEYSTATS, &keystats, sizeof(keystats));
538*48570Sbostic 	(void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
53925960Ssam 	    keystats.ks_allocs, "data cache keys allocated",
54045834Sbostic 	    PCT(keystats.ks_allocfree, keystats.ks_allocs),
54145834Sbostic 	    PCT(keystats.ks_norefs, keystats.ks_allocs),
54245834Sbostic 	    PCT(keystats.ks_taken, keystats.ks_allocs),
54345834Sbostic 	    PCT(keystats.ks_shared, keystats.ks_allocs));
54425960Ssam #endif
5451155Sbill }
5461155Sbill 
547*48570Sbostic void
5481155Sbill doforkst()
5491155Sbill {
550*48570Sbostic 	struct forkstat fks;
5511155Sbill 
552*48570Sbostic 	kread(X_FORKSTAT, &fks, sizeof(struct forkstat));
553*48570Sbostic 	(void)printf("%d forks, %d pages, average %.2f\n",
554*48570Sbostic 	    fks.cntfork, fks.sizfork, (double)fks.sizfork / fks.cntfork);
555*48570Sbostic 	(void)printf("%d vforks, %d pages, average %.2f\n",
556*48570Sbostic 	    fks.cntvfork, fks.sizvfork, (double)fks.sizvfork / fks.cntvfork);
5571155Sbill }
5581155Sbill 
559*48570Sbostic void
5601155Sbill stats(dn)
561*48570Sbostic 	int dn;
5621155Sbill {
563*48570Sbostic 	if (dn >= dk_ndrive)
564*48570Sbostic 		(void)printf("  0");
565*48570Sbostic 	else
566*48570Sbostic 		(void)printf("%3.0f", cur.xfer[dn] / etime);
5671155Sbill }
5681155Sbill 
5691155Sbill double
5701155Sbill stat1(row)
571*48570Sbostic 	int row;
5721155Sbill {
573*48570Sbostic 	register int i;
5741448Sbill 	double t;
5751155Sbill 
5761155Sbill 	t = 0;
577*48570Sbostic 	for (i = 0; i < CPUSTATES; i++)
578*48570Sbostic 		t += cur.time[i];
579*48570Sbostic 	if (t == 0.)
5801448Sbill 		t = 1.;
581*48570Sbostic 	return(cur.time[row]*100./t);
5821155Sbill }
5831155Sbill 
584*48570Sbostic void
58545834Sbostic dointr()
5861155Sbill {
587*48570Sbostic 	register long *intrcnt, inttotal, uptime;
58845834Sbostic 	register int nintr, inamlen;
58945834Sbostic 	register char *intrname;
5901155Sbill 
591*48570Sbostic 	uptime = getuptime();
59245834Sbostic 	nintr = nl[X_EINTRCNT].n_value - nl[X_INTRCNT].n_value;
59345834Sbostic 	inamlen = nl[X_EINTRNAMES].n_value - nl[X_INTRNAMES].n_value;
594*48570Sbostic 	intrcnt = malloc((size_t)nintr);
59545834Sbostic 	intrname = malloc((size_t)inamlen);
59617262Smckusick 	if (intrcnt == NULL || intrname == NULL) {
597*48570Sbostic 		(void)fprintf(stderr, "vmstat: %s.\n", strerror(errno));
598*48570Sbostic 		exit(1);
59917262Smckusick 	}
600*48570Sbostic 	kread(X_INTRCNT, intrcnt, (size_t)nintr);
60145834Sbostic 	kread(X_INTRNAMES, intrname, (size_t)inamlen);
602*48570Sbostic 	(void)printf("interrupt      total      rate\n");
60317262Smckusick 	inttotal = 0;
60445834Sbostic 	nintr /= sizeof(long);
60545834Sbostic 	while (--nintr >= 0) {
60617262Smckusick 		if (*intrcnt)
607*48570Sbostic 			(void)printf("%-12s %8ld %8ld\n", intrname,
60845834Sbostic 			    *intrcnt, *intrcnt / uptime);
60917262Smckusick 		intrname += strlen(intrname) + 1;
61017262Smckusick 		inttotal += *intrcnt++;
61117262Smckusick 	}
612*48570Sbostic 	(void)printf("Total        %8ld %8ld\n", inttotal, inttotal / uptime);
61317262Smckusick }
61417262Smckusick 
61533610Smckusick /*
61645152Smckusick  * These names are defined in <sys/malloc.h>.
61733610Smckusick  */
61845152Smckusick char *kmemnames[] = INITKMEMNAMES;
61933610Smckusick 
620*48570Sbostic void
62133610Smckusick domem()
62233610Smckusick {
62345834Sbostic 	register struct kmembuckets *kp;
62445834Sbostic 	register struct kmemstats *ks;
62545834Sbostic 	register int i;
62633610Smckusick 	struct kmemstats kmemstats[M_LAST];
62733610Smckusick 	struct kmembuckets buckets[MINBUCKET + 16];
62833610Smckusick 
629*48570Sbostic 	kread(X_KMEMBUCKETS, buckets, sizeof(buckets));
630*48570Sbostic 	(void)printf("Memory statistics by bucket size\n");
631*48570Sbostic 	(void)printf(
63245834Sbostic 	    "    Size   In Use   Free   Requests  HighWater  Couldfree\n");
63333610Smckusick 	for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) {
63433610Smckusick 		if (kp->kb_calls == 0)
63533610Smckusick 			continue;
636*48570Sbostic 		(void)printf("%8d%9ld%7ld%11ld%8ld%11ld\n", 1 << i,
63733610Smckusick 			kp->kb_total - kp->kb_totalfree,
63833610Smckusick 			kp->kb_totalfree, kp->kb_calls,
63933610Smckusick 			kp->kb_highwat, kp->kb_couldfree);
64033610Smckusick 
64133610Smckusick 	}
642*48570Sbostic 	kread(X_KMEMSTAT, kmemstats, sizeof(kmemstats));
643*48570Sbostic 	(void)printf("\nMemory statistics by type\n");
644*48570Sbostic 	(void)printf(
645*48570Sbostic "      Type  In Use  MemUse   HighUse  Limit Requests  TypeLimit KernLimit\n");
64633610Smckusick 	for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
64733610Smckusick 		if (ks->ks_calls == 0)
64833610Smckusick 			continue;
649*48570Sbostic 		(void)printf("%10s%7ld%8ldK%9ldK%6ldK%9ld%7u%10u\n",
650*48570Sbostic 		    kmemnames[i] ? kmemnames[i] : "undefined",
651*48570Sbostic 		    ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
652*48570Sbostic 		    (ks->ks_maxused + 1023) / 1024,
653*48570Sbostic 		    (ks->ks_limit + 1023) / 1024, ks->ks_calls,
654*48570Sbostic 		    ks->ks_limblocks, ks->ks_mapblocks);
65533610Smckusick 	}
65633610Smckusick }
65733610Smckusick 
658*48570Sbostic void
659*48570Sbostic zero()
6603162Stoy {
661*48570Sbostic 	struct nlist znl[] = {
662*48570Sbostic #undef	X_SUM
663*48570Sbostic #define X_SUM		0
664*48570Sbostic 		{ "_sum" },
665*48570Sbostic 		{ "" },
666*48570Sbostic 	};
667*48570Sbostic 	int fd;
668*48570Sbostic 	char *kmem;
6693162Stoy 
670*48570Sbostic 	if (geteuid()) {
671*48570Sbostic 		(void)fprintf(stderr, "vmstat: %s\n", strerror(EPERM));
6723162Stoy 		exit(1);
6733162Stoy 	}
674*48570Sbostic 	/*
675*48570Sbostic 	 * Zeroing the statistics is fundamentally different
676*48570Sbostic 	 * (and really belongs in a separate program).
677*48570Sbostic 	 */
678*48570Sbostic 	if (nlist(vmunix, znl) || nl[0].n_type == 0) {
679*48570Sbostic 		(void)fprintf(stderr, "vmstat: %s: symbol %s not found\n",
680*48570Sbostic 		    vmunix, nl[0].n_name);
681*48570Sbostic 		exit(1);
6823162Stoy 	}
683*48570Sbostic 
684*48570Sbostic 	kmem = _PATH_KMEM;
685*48570Sbostic 	if ((fd = open(kmem, O_RDWR)) < 0) {
686*48570Sbostic 		(void)fprintf(stderr,
687*48570Sbostic 		    "vmstat: %s: %s\n", kmem, strerror(errno));
688*48570Sbostic 		exit(1);
6893162Stoy 	}
690*48570Sbostic 	if (lseek(fd, (long)nl[0].n_value, L_SET) == -1 ||
691*48570Sbostic 	    write(fd, &sum, sizeof(sum)) != sizeof(sum)) {
692*48570Sbostic 		(void)fprintf(stderr,
693*48570Sbostic 		    "vmstat: %s: %s\n", kmem, strerror(errno));
694*48570Sbostic 		exit(1);
695*48570Sbostic 	}
6963162Stoy }
69725708Ssam 
69825708Ssam /*
699*48570Sbostic  * kread reads something from the kernel, given its nlist index.
70025708Ssam  */
701*48570Sbostic void
702*48570Sbostic kread(nlx, addr, size)
703*48570Sbostic 	int nlx;
704*48570Sbostic 	void *addr;
705*48570Sbostic 	size_t size;
70625708Ssam {
707*48570Sbostic 	char *sym;
70825708Ssam 
709*48570Sbostic 	if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) {
710*48570Sbostic 		sym = nl[nlx].n_name;
711*48570Sbostic 		if (*sym == '_')
712*48570Sbostic 			++sym;
713*48570Sbostic 		(void)fprintf(stderr,
714*48570Sbostic 		    "vmstat: %s: symbol %s not defined\n", vmunix, sym);
71525708Ssam 		exit(1);
71625708Ssam 	}
717*48570Sbostic 	if (kvm_read((void *)nl[nlx].n_value, addr, size) != size) {
718*48570Sbostic 		sym = nl[nlx].n_name;
719*48570Sbostic 		if (*sym == '_')
720*48570Sbostic 			++sym;
721*48570Sbostic 		(void)fprintf(stderr, "vmstat: %s: %s\n", sym, kvm_geterr());
722*48570Sbostic 		exit(1);
72325708Ssam 	}
72425708Ssam }
72542952Sbostic 
726*48570Sbostic void
727*48570Sbostic usage()
72842952Sbostic {
729*48570Sbostic 	(void)fprintf(stderr,
730*48570Sbostic 	    "usage: vmstat [-fimst] [-c count] [-M core] \
731*48570Sbostic [-N system] [-w wait] [disks]\n       vmstat -z\n");
732*48570Sbostic 	exit(1);
73342952Sbostic }
734