xref: /csrg-svn/usr.bin/vmstat/vmstat.c (revision 45834)
121585Sdist /*
236580Sbostic  * Copyright (c) 1980 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[] =
1036580Sbostic "@(#) Copyright (c) 1980 The Regents of the University of California.\n\
1121585Sdist  All rights reserved.\n";
1236580Sbostic #endif /* not lint */
1310826Ssam 
1421585Sdist #ifndef lint
15*45834Sbostic static char sccsid[] = "@(#)vmstat.c	5.23 (Berkeley) 12/18/90";
1636580Sbostic #endif /* not lint */
1721585Sdist 
181155Sbill #include <sys/param.h>
1918761Ssam #include <sys/file.h>
201155Sbill #include <sys/vm.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>
2637912Sbostic #include <ctype.h>
27*45834Sbostic #include <errno.h>
28*45834Sbostic #include <kvm.h>
2937912Sbostic #include <nlist.h>
30*45834Sbostic #include <stdio.h>
31*45834Sbostic #include <stdlib.h>
32*45834Sbostic #include <string.h>
3337912Sbostic #include <paths.h>
341155Sbill 
351155Sbill struct nlist nl[] = {
361448Sbill #define	X_CPTIME	0
371448Sbill 	{ "_cp_time" },
381448Sbill #define	X_RATE		1
391155Sbill 	{ "_rate" },
401448Sbill #define X_TOTAL		2
411155Sbill 	{ "_total" },
421448Sbill #define	X_DEFICIT	3
431155Sbill 	{ "_deficit" },
441448Sbill #define	X_FORKSTAT	4
451155Sbill 	{ "_forkstat" },
461448Sbill #define X_SUM		5
471155Sbill 	{ "_sum" },
481448Sbill #define	X_FIRSTFREE	6
491155Sbill 	{ "_firstfree" },
501448Sbill #define	X_MAXFREE	7
511155Sbill 	{ "_maxfree" },
529249Ssam #define	X_BOOTTIME	8
539249Ssam 	{ "_boottime" },
541448Sbill #define	X_DKXFER	9
551448Sbill 	{ "_dk_xfer" },
5610826Ssam #define X_REC		10
571155Sbill 	{ "_rectime" },
5810826Ssam #define X_PGIN		11
591155Sbill 	{ "_pgintime" },
6010826Ssam #define X_HZ		12
613162Stoy 	{ "_hz" },
6218761Ssam #define X_PHZ		13
6315266Ssam 	{ "_phz" },
6415807Smckusick #define X_NCHSTATS	14
6515807Smckusick 	{ "_nchstats" },
6617262Smckusick #define	X_INTRNAMES	15
6717262Smckusick 	{ "_intrnames" },
6817262Smckusick #define	X_EINTRNAMES	16
6917262Smckusick 	{ "_eintrnames" },
7017262Smckusick #define	X_INTRCNT	17
7117262Smckusick 	{ "_intrcnt" },
7217262Smckusick #define	X_EINTRCNT	18
7317262Smckusick 	{ "_eintrcnt" },
7418761Ssam #define	X_DK_NDRIVE	19
7518761Ssam 	{ "_dk_ndrive" },
7625512Ssam #define	X_XSTATS	20
7725512Ssam 	{ "_xstats" },
7833610Smckusick #define	X_KMEMSTAT	21
7933610Smckusick 	{ "_kmemstats" },
8033610Smckusick #define	X_KMEMBUCKETS	22
8133610Smckusick 	{ "_bucket" },
8242952Sbostic #define X_END		22
8310826Ssam #ifdef vax
8442952Sbostic #define X_MBDINIT	(X_END+1)
8510826Ssam 	{ "_mbdinit" },
8642952Sbostic #define X_UBDINIT	(X_END+2)
8710826Ssam 	{ "_ubdinit" },
8810826Ssam #endif
8925708Ssam #ifdef tahoe
9042952Sbostic #define	X_VBDINIT	(X_END+1)
9125708Ssam 	{ "_vbdinit" },
9242952Sbostic #define	X_CKEYSTATS	(X_END+2)
9325960Ssam 	{ "_ckeystats" },
9442952Sbostic #define	X_DKEYSTATS	(X_END+3)
9525960Ssam 	{ "_dkeystats" },
9625708Ssam #endif
9742952Sbostic #ifdef hp300
9842952Sbostic #define	X_HPDINIT	(X_END+1)
9942952Sbostic 	{ "_hp_dinit" },
10042952Sbostic #endif
10110826Ssam 	{ "" },
1021155Sbill };
1031155Sbill 
104*45834Sbostic char	*vmunix = _PATH_UNIX;
105*45834Sbostic char	*kmem = NULL;
10618761Ssam char	**dr_name;
10718761Ssam int	*dr_select;
10818761Ssam int	dk_ndrive;
10918761Ssam int	ndrives = 0;
11018761Ssam #ifdef vax
11118761Ssam char	*defdrives[] = { "hp0", "hp1", "hp2",  0 };
11218761Ssam #else
11342952Sbostic #ifdef hp300
11442952Sbostic char	*defdrives[] = { "rd0", "rd1", "rd2",  0 };
11542952Sbostic #else
11618761Ssam char	*defdrives[] = { 0 };
11718761Ssam #endif
11842952Sbostic #endif
1191155Sbill double	stat1();
1201155Sbill int	firstfree, maxfree;
1213162Stoy int	hz;
12215266Ssam int	phz;
12315266Ssam int	HZ;
12418761Ssam 
12518761Ssam struct {
1261155Sbill 	int	busy;
1271448Sbill 	long	time[CPUSTATES];
12818761Ssam 	long	*xfer;
1291155Sbill 	struct	vmmeter Rate;
1301155Sbill 	struct	vmtotal	Total;
1311155Sbill 	struct	vmmeter Sum;
1321155Sbill 	struct	forkstat Forkstat;
1331155Sbill 	unsigned rectime;
1341155Sbill 	unsigned pgintime;
135*45834Sbostic } s, s1;
1361155Sbill #define	rate		s.Rate
1371155Sbill #define	total		s.Total
1381155Sbill #define	sum		s.Sum
1391155Sbill #define	forkstat	s.Forkstat
1401155Sbill 
14110826Ssam struct	vmmeter osum;
1421155Sbill int	deficit;
1431155Sbill double	etime;
14417262Smckusick time_t	now, boottime;
14518768Ssam int	lines = 1;
146*45834Sbostic void	printhdr();
147*45834Sbostic long	lseek();
1481155Sbill 
14929664Ssam #define	INTS(x)	((x) - (hz + phz))
15029664Ssam 
151*45834Sbostic #define	FORKSTAT	0x01
152*45834Sbostic #define	INTRSTAT	0x02
153*45834Sbostic #define	MEMSTAT		0x04
154*45834Sbostic #define	SUMSTAT		0x08
155*45834Sbostic #define	TIMESTAT	0x10
156*45834Sbostic #define	VMSTAT		0x20
157*45834Sbostic #define	ZEROOUT		0x40
158*45834Sbostic 
1591155Sbill main(argc, argv)
160*45834Sbostic 	register int argc;
161*45834Sbostic 	register char **argv;
1621155Sbill {
163*45834Sbostic 	register int c, i, todo = 0;
164*45834Sbostic 	extern int optind;
165*45834Sbostic 	extern char *optarg;
1661155Sbill 
167*45834Sbostic 	while ((c = getopt(argc, argv, "fik:mstu:z")) != EOF) {
168*45834Sbostic 		switch (c) {
169*45834Sbostic 		case 'f':
170*45834Sbostic 			todo |= FORKSTAT;
171*45834Sbostic 			break;
172*45834Sbostic 		case 'i':
173*45834Sbostic 			todo |= INTRSTAT;
174*45834Sbostic 			break;
175*45834Sbostic 		case 'k':
176*45834Sbostic 			kmem = optarg;
177*45834Sbostic 			break;
178*45834Sbostic 		case 'm':
179*45834Sbostic 			todo |= MEMSTAT;
180*45834Sbostic 			break;
181*45834Sbostic 		case 's':
182*45834Sbostic 			todo |= SUMSTAT;
183*45834Sbostic 			break;
184*45834Sbostic 		case 't':
185*45834Sbostic 			todo |= TIMESTAT;
186*45834Sbostic 			break;
187*45834Sbostic 		case 'u':
188*45834Sbostic 			vmunix = optarg;
189*45834Sbostic 			break;
190*45834Sbostic 		case 'z':
191*45834Sbostic 			todo |= ZEROOUT;
192*45834Sbostic 			break;
193*45834Sbostic 		case '?':
194*45834Sbostic 			usage();
195*45834Sbostic 			/* NOTREACHED */
196*45834Sbostic 		default:
197*45834Sbostic 			(void) fprintf(stderr,
198*45834Sbostic 			    "vmstat: internal error in options\n");
199*45834Sbostic 			exit(1);
200*45834Sbostic 			/* NOTREACHED */
201*45834Sbostic 		}
202*45834Sbostic 	}
203*45834Sbostic 
204*45834Sbostic 	/*
205*45834Sbostic 	 * Zeroing the statistics is fundamentally different
206*45834Sbostic 	 * (and really belongs in a separate program).
207*45834Sbostic 	 */
208*45834Sbostic 	if (todo & ZEROOUT) {
209*45834Sbostic 		if (todo & ~ZEROOUT || kmem)
210*45834Sbostic 			usage();
211*45834Sbostic 		nl[0].n_name = nl[X_SUM].n_name;
212*45834Sbostic 		nl[1].n_name = 0;
213*45834Sbostic 		if (nlist(vmunix, nl) || nl[0].n_type == 0) {
214*45834Sbostic 			(void) fprintf(stderr,
215*45834Sbostic 			    "vmstat: cannot get symbol %s from %s\n",
216*45834Sbostic 			    nl[0].n_name, vmunix);
217*45834Sbostic 			exit(1);
218*45834Sbostic 		}
219*45834Sbostic 		if ((i = open(kmem = _PATH_KMEM, 2)) < 0) {
220*45834Sbostic 			(void) fprintf(stderr, "vmstat: cannot write %s: %s\n",
221*45834Sbostic 			    kmem, strerror(errno));
222*45834Sbostic 			exit(1);
223*45834Sbostic 		}
224*45834Sbostic 		(void) lseek(i, (long)nl[0].n_value, L_SET);
225*45834Sbostic 		if (write(i, (char *)&s.Sum, sizeof s.Sum) != sizeof s.Sum) {
226*45834Sbostic 			(void) fprintf(stderr, "vmstat: write(%s): %s\n",
227*45834Sbostic 			    kmem, strerror(errno));
228*45834Sbostic 			exit(1);
229*45834Sbostic 		}
230*45834Sbostic 		exit(0);
231*45834Sbostic 	}
232*45834Sbostic 
233*45834Sbostic 	if (todo == 0)
234*45834Sbostic 		todo = VMSTAT;
235*45834Sbostic 
236*45834Sbostic 	if (kvm_openfiles(vmunix, kmem, (char *)NULL) < 0) {
237*45834Sbostic 		(void) fprintf(stderr,
238*45834Sbostic 		    "vmstat: kvm_openfiles(%s, %s, NULL): %s\n",
239*45834Sbostic 		    vmunix, kmem ? kmem : "NULL", kvm_geterr());
2401155Sbill 		exit(1);
2411155Sbill 	}
242*45834Sbostic 
243*45834Sbostic 	(void) kvm_nlist(nl);
244*45834Sbostic 	if (nl[0].n_type == 0) {
245*45834Sbostic 		(void) fprintf(stderr, "vmstat: %s: no namelist\n",
246*45834Sbostic 		    vmunix);
2471155Sbill 		exit(1);
2481155Sbill 	}
2491155Sbill 
250*45834Sbostic 	/*
251*45834Sbostic 	 * Fork, memory, sum, and time statistics do not need everything.
252*45834Sbostic 	 */
253*45834Sbostic 	if (todo & FORKSTAT)
254*45834Sbostic 		doforkst();
255*45834Sbostic 	if (todo & MEMSTAT)
256*45834Sbostic 		domem();
257*45834Sbostic 	if (todo & SUMSTAT)
258*45834Sbostic 		dosum();
259*45834Sbostic 	if (todo & TIMESTAT)
260*45834Sbostic 		dotimes();
261*45834Sbostic 	if (todo & INTRSTAT)
262*45834Sbostic 		dointr();
263*45834Sbostic 	if (todo & VMSTAT) {
264*45834Sbostic 		/*
265*45834Sbostic 		 * Read drive names, decide which drives to report, etc.
266*45834Sbostic 		 */
267*45834Sbostic 		argc -= optind;
268*45834Sbostic 		argv += optind;
269*45834Sbostic 		i = getdrivedata(argc, argv);
270*45834Sbostic 		argc -= i;
271*45834Sbostic 		argv += i;
272*45834Sbostic 		dovmstat(argc > 0 ? atoi(argv[0]) : 0,
273*45834Sbostic 			 argc > 1 ? atoi(argv[1]) : 0);
274*45834Sbostic 	}
275*45834Sbostic 	exit(0);
276*45834Sbostic }
27710826Ssam 
278*45834Sbostic usage()
279*45834Sbostic {
2801155Sbill 
281*45834Sbostic 	(void) fprintf(stderr,
282*45834Sbostic "usage: vmstat [-fimst]\n\tvmstat [drive-list] [interval [count]]\n\tvmstat -z\n");
283*45834Sbostic 	exit(1);
284*45834Sbostic }
28533610Smckusick 
286*45834Sbostic /*
287*45834Sbostic  * kread reads something from the kernel, given its nlist index.
288*45834Sbostic  */
289*45834Sbostic void
290*45834Sbostic kread(nlx, addr, size)
291*45834Sbostic 	int nlx;
292*45834Sbostic 	char *addr;
293*45834Sbostic 	size_t size;
294*45834Sbostic {
295*45834Sbostic 	char *sym;
2961155Sbill 
297*45834Sbostic 	if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) {
298*45834Sbostic 		sym = nl[nlx].n_name;
299*45834Sbostic 		if (*sym == '_')
300*45834Sbostic 			sym++;
301*45834Sbostic 		(void) fprintf(stderr,
302*45834Sbostic 		    "vmstat: symbol `%s' not defined in %s\n", sym, vmunix);
303*45834Sbostic 		exit(1);
3041155Sbill 	}
305*45834Sbostic 	if (kvm_read(nl[nlx].n_value, addr, size) != size) {
306*45834Sbostic 		sym = nl[nlx].n_name;
307*45834Sbostic 		if (*sym == '_')
308*45834Sbostic 			sym++;
309*45834Sbostic 		(void) fprintf(stderr,
310*45834Sbostic 		    "vmstat: error reading `%s': %s\n", sym, kvm_geterr());
311*45834Sbostic 		exit(1);
31218761Ssam 	}
313*45834Sbostic }
314*45834Sbostic 
315*45834Sbostic getdrivedata(argc, argv)
316*45834Sbostic 	int argc;
317*45834Sbostic 	char **argv;
318*45834Sbostic {
319*45834Sbostic 	register int i;
320*45834Sbostic 	register char **cp;
321*45834Sbostic 	int ret;
322*45834Sbostic 	char buf[30];
323*45834Sbostic 
324*45834Sbostic 	kread(X_FIRSTFREE, (char *)&firstfree, sizeof firstfree);
325*45834Sbostic 	kread(X_MAXFREE, (char *)&maxfree, sizeof maxfree);
326*45834Sbostic 	kread(X_HZ, (char *)&hz, sizeof hz);
327*45834Sbostic 	if (nl[X_PHZ].n_type != 0 && nl[X_PHZ].n_value != 0)
328*45834Sbostic 		kread(X_PHZ, (char *)&phz, sizeof phz);
32915266Ssam 	HZ = phz ? phz : hz;
330*45834Sbostic 	kread(X_DK_NDRIVE, (char *)&dk_ndrive, sizeof dk_ndrive);
33118761Ssam 	if (dk_ndrive <= 0) {
332*45834Sbostic 		(void) fprintf(stderr, "vmstat: dk_ndrive %d\n", dk_ndrive);
33318761Ssam 		exit(1);
33418761Ssam 	}
335*45834Sbostic 	dr_select = (int *)calloc((size_t)dk_ndrive, sizeof (int));
336*45834Sbostic 	dr_name = (char **)malloc((size_t)dk_ndrive * sizeof (char *));
337*45834Sbostic 	for (i = 0; i < dk_ndrive; i++)
338*45834Sbostic 		dr_name[i] = NULL;
339*45834Sbostic 	s.xfer = (long *)calloc((size_t)dk_ndrive, sizeof (long));
340*45834Sbostic 	s1.xfer = (long *)calloc((size_t)dk_ndrive, sizeof (long));
3413162Stoy 	read_names();
342*45834Sbostic 	for (i = 0; i < dk_ndrive; i++) {
343*45834Sbostic 		if (dr_name[i] == NULL) {
344*45834Sbostic 			(void) sprintf(buf, "??%d", i);
345*45834Sbostic 			dr_name[i] = strdup(buf);
346*45834Sbostic 		}
3471155Sbill 	}
348*45834Sbostic 
34918761Ssam 	/*
35018761Ssam 	 * Choose drives to be displayed.  Priority
35118761Ssam 	 * goes to (in order) drives supplied as arguments,
35218761Ssam 	 * default drives.  If everything isn't filled
35318761Ssam 	 * in and there are drives not taken care of,
35418761Ssam 	 * display the first few that fit.
35518761Ssam 	 */
356*45834Sbostic 	ret = 0;
35718761Ssam 	ndrives = 0;
35818761Ssam 	while (argc > 0 && !isdigit(argv[0][0])) {
35918761Ssam 		for (i = 0; i < dk_ndrive; i++) {
36018761Ssam 			if (strcmp(dr_name[i], argv[0]))
36118761Ssam 				continue;
36218761Ssam 			dr_select[i] = 1;
36318761Ssam 			ndrives++;
364*45834Sbostic 			break;
36518761Ssam 		}
366*45834Sbostic 		ret++;
36718761Ssam 		argc--, argv++;
36818761Ssam 	}
36918761Ssam 	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
37018761Ssam 		if (dr_select[i])
37118761Ssam 			continue;
37218761Ssam 		for (cp = defdrives; *cp; cp++)
37318761Ssam 			if (strcmp(dr_name[i], *cp) == 0) {
37418761Ssam 				dr_select[i] = 1;
37518761Ssam 				ndrives++;
37618761Ssam 				break;
37718761Ssam 			}
37818761Ssam 	}
37918761Ssam 	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
38018761Ssam 		if (dr_select[i])
38118761Ssam 			continue;
38218761Ssam 		dr_select[i] = 1;
38318761Ssam 		ndrives++;
38418761Ssam 	}
385*45834Sbostic 	return (ret);
386*45834Sbostic }
387*45834Sbostic 
388*45834Sbostic long
389*45834Sbostic getuptime()
390*45834Sbostic {
391*45834Sbostic 	time_t time();
392*45834Sbostic 	long uptime;
393*45834Sbostic 
394*45834Sbostic 	if (boottime == 0)
395*45834Sbostic 		kread(X_BOOTTIME, (char *)&boottime, sizeof boottime);
396*45834Sbostic 	(void) time(&now);
397*45834Sbostic 	uptime = now - boottime;
398*45834Sbostic 	if (uptime <= 0 || uptime > 60*60*24*365*10) {
399*45834Sbostic 		(void) fprintf(stderr,
400*45834Sbostic 		    "vmstat: time makes no sense; namelist must be wrong.\n");
401*45834Sbostic 		exit(1);
402*45834Sbostic 	}
403*45834Sbostic 	return (uptime);
404*45834Sbostic }
405*45834Sbostic 
406*45834Sbostic dovmstat(sleeptime, iter)
407*45834Sbostic 	int sleeptime, iter;
408*45834Sbostic {
409*45834Sbostic 	register int i;
410*45834Sbostic 	long interval, t;
411*45834Sbostic 
412*45834Sbostic 	interval = getuptime();
413*45834Sbostic 	(void) signal(SIGCONT, printhdr);
4141155Sbill loop:
41518768Ssam 	if (--lines == 0)
41618768Ssam 		printhdr();
417*45834Sbostic 	kread(X_CPTIME, (char *)s.time, sizeof s.time);
418*45834Sbostic 	kread(X_DKXFER, (char *)s.xfer, sizeof *s.xfer * dk_ndrive);
419*45834Sbostic 	if (interval != 1)
420*45834Sbostic 		kread(X_SUM, (char *)&rate, sizeof rate);
42118761Ssam 	else
422*45834Sbostic 		kread(X_RATE, (char *)&rate, sizeof rate);
423*45834Sbostic 	kread(X_TOTAL, (char *)&total, sizeof total);
42410826Ssam 	osum = sum;
425*45834Sbostic 	kread(X_SUM, (char *)&sum, sizeof sum);
426*45834Sbostic 	kread(X_DEFICIT, (char *)&deficit, sizeof deficit);
4271448Sbill 	etime = 0;
428*45834Sbostic 	for (i = 0; i < dk_ndrive; i++) {
4291448Sbill 		t = s.xfer[i];
4301448Sbill 		s.xfer[i] -= s1.xfer[i];
4311448Sbill 		s1.xfer[i] = t;
4321155Sbill 	}
433*45834Sbostic 	for (i = 0; i < CPUSTATES; i++) {
4341448Sbill 		t = s.time[i];
4351448Sbill 		s.time[i] -= s1.time[i];
4361448Sbill 		s1.time[i] = t;
4371448Sbill 		etime += s.time[i];
4381155Sbill 	}
439*45834Sbostic 	if (etime == 0.)
4401155Sbill 		etime = 1.;
441*45834Sbostic 	(void) printf("%2d%2d%2d",
442*45834Sbostic 	    total.t_rq, total.t_dw + total.t_pw, total.t_sw);
443*45834Sbostic #define pgtok(a) ((a)*NBPG >> 10)
444*45834Sbostic 	(void) printf("%6ld%6ld", pgtok(total.t_avm), pgtok(total.t_free));
445*45834Sbostic 	(void) printf("%4lu%3lu",
446*45834Sbostic 	    (rate.v_pgrec - (rate.v_xsfrec+rate.v_xifrec)) / interval,
447*45834Sbostic 	    (rate.v_xsfrec+rate.v_xifrec) / interval);
448*45834Sbostic 	(void) printf("%4lu", pgtok(rate.v_pgpgin) / interval);
449*45834Sbostic 	(void) printf("%4lu%4lu%4d%4lu", pgtok(rate.v_pgpgout) / interval,
450*45834Sbostic 	    pgtok(rate.v_dfree) / interval,
451*45834Sbostic 	    pgtok(deficit), rate.v_scan / interval);
45218761Ssam 	etime /= (float)HZ;
45318761Ssam 	for (i = 0; i < dk_ndrive; i++)
45418761Ssam 		if (dr_select[i])
45518761Ssam 			stats(i);
456*45834Sbostic 	(void) printf("%4lu%4lu%4lu", INTS(rate.v_intr / interval),
457*45834Sbostic 	    rate.v_syscall / interval, rate.v_swtch / interval);
458*45834Sbostic 	for(i = 0; i < CPUSTATES; i++) {
4591155Sbill 		float f = stat1(i);
4601155Sbill 		if (i == 0) {		/* US+NI */
4611155Sbill 			i++;
4621155Sbill 			f += stat1(i);
4631155Sbill 		}
464*45834Sbostic 		(void) printf("%3.0f", f);
4651155Sbill 	}
466*45834Sbostic 	(void) printf("\n");
467*45834Sbostic 	(void) fflush(stdout);
468*45834Sbostic 	interval = 1;
469*45834Sbostic 	if (iter && --iter == 0)
470*45834Sbostic 		return;
471*45834Sbostic 	if (sleeptime) {
472*45834Sbostic 		sleep((unsigned)sleeptime);
4731155Sbill 		goto loop;
4741155Sbill 	}
4751155Sbill }
4761155Sbill 
477*45834Sbostic void
47817262Smckusick printhdr()
47917262Smckusick {
48018761Ssam 	register int i, j;
48118761Ssam 
482*45834Sbostic 	(void) printf(" procs     memory              page           ");
48318761Ssam 	i = (ndrives * 3 - 6) / 2;
48418761Ssam 	if (i < 0)
48518761Ssam 		i = 0;
48618761Ssam 	for (j = 0; j < i; j++)
487*45834Sbostic 		(void) putchar(' ');
488*45834Sbostic 	(void) printf("faults");
48918761Ssam 	i = ndrives * 3 - 6 - i;
49018761Ssam 	for (j = 0; j < i; j++)
491*45834Sbostic 		(void) putchar(' ');
492*45834Sbostic 	(void) printf("               cpu\n");
493*45834Sbostic 	(void) printf(" r b w   avm   fre  re at  pi  po  fr  de  sr ");
49418761Ssam 	for (i = 0; i < dk_ndrive; i++)
49518761Ssam 		if (dr_select[i])
496*45834Sbostic 			(void) printf("%c%c ", dr_name[i][0],
497*45834Sbostic 			    dr_name[i][strlen(dr_name[i]) - 1]);
498*45834Sbostic 	(void) printf(" in  sy  cs us sy id\n");
49918768Ssam 	lines = 19;
50017262Smckusick }
50117262Smckusick 
5021155Sbill dotimes()
5031155Sbill {
5041155Sbill 
505*45834Sbostic 	kread(X_REC, (char *)&s.rectime, sizeof s.rectime);
506*45834Sbostic 	kread(X_PGIN, (char *)&s.pgintime, sizeof s.pgintime);
507*45834Sbostic 	kread(X_SUM, (char *)&sum, sizeof sum);
508*45834Sbostic 	(void) printf("%u reclaims, %u total time (usec)\n",
509*45834Sbostic 	    sum.v_pgrec, s.rectime);
510*45834Sbostic 	(void) printf("average: %u usec / reclaim\n", s.rectime / sum.v_pgrec);
511*45834Sbostic 	(void) printf("\n");
512*45834Sbostic 	(void) printf("%u page ins, %u total time (msec)\n",
513*45834Sbostic 	    sum.v_pgin, s.pgintime / 10);
514*45834Sbostic 	(void) printf("average: %8.1f msec / page in\n",
515*45834Sbostic 	    s.pgintime / (sum.v_pgin * 10.0));
5161155Sbill }
5171155Sbill 
518*45834Sbostic pct(top, bot)
519*45834Sbostic 	long top, bot;
520*45834Sbostic {
521*45834Sbostic 
522*45834Sbostic 	if (bot == 0)
523*45834Sbostic 		return (0);
524*45834Sbostic 	return ((top * 100) / bot);
525*45834Sbostic }
526*45834Sbostic 
527*45834Sbostic #define	PCT(top, bot) pct((long)(top), (long)(bot))
528*45834Sbostic 
52930069Ssam #if defined(tahoe)
530*45834Sbostic #include <machine/cpu.h>
53130069Ssam #endif
53230069Ssam 
5331155Sbill dosum()
5341155Sbill {
53518761Ssam 	struct nchstats nchstats;
53625960Ssam 	struct xstats xstats;
53715807Smckusick 	long nchtotal;
53825960Ssam #if defined(tahoe)
53925960Ssam 	struct keystats keystats;
54025960Ssam #endif
5411155Sbill 
542*45834Sbostic 	kread(X_SUM, (char *)&sum, sizeof sum);
543*45834Sbostic 	(void) printf("%9u swap ins\n", sum.v_swpin);
544*45834Sbostic 	(void) printf("%9u swap outs\n", sum.v_swpout);
545*45834Sbostic 	(void) printf("%9u pages swapped in\n", sum.v_pswpin / CLSIZE);
546*45834Sbostic 	(void) printf("%9u pages swapped out\n", sum.v_pswpout / CLSIZE);
547*45834Sbostic 	(void) printf("%9u total address trans. faults taken\n", sum.v_faults);
548*45834Sbostic 	(void) printf("%9u page ins\n", sum.v_pgin);
549*45834Sbostic 	(void) printf("%9u page outs\n", sum.v_pgout);
550*45834Sbostic 	(void) printf("%9u pages paged in\n", sum.v_pgpgin);
551*45834Sbostic 	(void) printf("%9u pages paged out\n", sum.v_pgpgout);
552*45834Sbostic 	(void) printf("%9u sequential process pages freed\n", sum.v_seqfree);
553*45834Sbostic 	(void) printf("%9u total reclaims (%d%% fast)\n", sum.v_pgrec,
554*45834Sbostic 	    PCT(sum.v_fastpgrec, sum.v_pgrec));
555*45834Sbostic 	(void) printf("%9u reclaims from free list\n", sum.v_pgfrec);
556*45834Sbostic 	(void) printf("%9u intransit blocking page faults\n", sum.v_intrans);
557*45834Sbostic 	(void) printf("%9u zero fill pages created\n", sum.v_nzfod / CLSIZE);
558*45834Sbostic 	(void) printf("%9u zero fill page faults\n", sum.v_zfod / CLSIZE);
559*45834Sbostic 	(void) printf("%9u executable fill pages created\n",
560*45834Sbostic 	    sum.v_nexfod / CLSIZE);
561*45834Sbostic 	(void) printf("%9u executable fill page faults\n",
562*45834Sbostic 	    sum.v_exfod / CLSIZE);
563*45834Sbostic 	(void) printf("%9u swap text pages found in free list\n",
564*45834Sbostic 	    sum.v_xsfrec);
565*45834Sbostic 	(void) printf("%9u inode text pages found in free list\n",
566*45834Sbostic 	    sum.v_xifrec);
567*45834Sbostic 	(void) printf("%9u file fill pages created\n", sum.v_nvrfod / CLSIZE);
568*45834Sbostic 	(void) printf("%9u file fill page faults\n", sum.v_vrfod / CLSIZE);
569*45834Sbostic 	(void) printf("%9u pages examined by the clock daemon\n", sum.v_scan);
570*45834Sbostic 	(void) printf("%9u revolutions of the clock hand\n", sum.v_rev);
571*45834Sbostic 	(void) printf("%9u pages freed by the clock daemon\n",
572*45834Sbostic 	    sum.v_dfree / CLSIZE);
573*45834Sbostic 	(void) printf("%9u cpu context switches\n", sum.v_swtch);
574*45834Sbostic 	(void) printf("%9u device interrupts\n", sum.v_intr);
575*45834Sbostic 	(void) printf("%9u software interrupts\n", sum.v_soft);
57618761Ssam #ifdef vax
577*45834Sbostic 	(void) printf("%9u pseudo-dma dz interrupts\n", sum.v_pdma);
57818761Ssam #endif
579*45834Sbostic 	(void) printf("%9u traps\n", sum.v_trap);
580*45834Sbostic 	(void) printf("%9u system calls\n", sum.v_syscall);
581*45834Sbostic 	kread(X_NCHSTATS, (char *)&nchstats, sizeof nchstats);
58238773Smckusick 	nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
58338773Smckusick 	    nchstats.ncs_badhits + nchstats.ncs_falsehits +
58438773Smckusick 	    nchstats.ncs_miss + nchstats.ncs_long;
585*45834Sbostic 	(void) printf("%9ld total name lookups\n", nchtotal);
586*45834Sbostic 	(void) printf(
587*45834Sbostic 	    "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
588*45834Sbostic 	    "", PCT(nchstats.ncs_goodhits, nchtotal),
589*45834Sbostic 	    PCT(nchstats.ncs_neghits, nchtotal),
590*45834Sbostic 	    PCT(nchstats.ncs_pass2, nchtotal));
591*45834Sbostic 	(void) printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
592*45834Sbostic 	    PCT(nchstats.ncs_badhits, nchtotal),
593*45834Sbostic 	    PCT(nchstats.ncs_falsehits, nchtotal),
594*45834Sbostic 	    PCT(nchstats.ncs_long, nchtotal));
595*45834Sbostic 	kread(X_XSTATS, (char *)&xstats, sizeof xstats);
596*45834Sbostic 	(void) printf("%9lu total calls to xalloc (cache hits %d%%)\n",
597*45834Sbostic 	    xstats.alloc, PCT(xstats.alloc_cachehit, xstats.alloc));
598*45834Sbostic 	(void) printf("%9s sticky %lu flushed %lu unused %lu\n", "",
59925512Ssam 	    xstats.alloc_inuse, xstats.alloc_cacheflush, xstats.alloc_unused);
600*45834Sbostic 	(void) printf("%9lu total calls to xfree", xstats.free);
601*45834Sbostic 	(void) printf(" (sticky %lu cached %lu swapped %lu)\n",
60225512Ssam 	    xstats.free_inuse, xstats.free_cache, xstats.free_cacheswap);
60325960Ssam #if defined(tahoe)
604*45834Sbostic 	kread(X_CKEYSTATS, (char *)&keystats, sizeof keystats);
605*45834Sbostic 	(void) printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
60625960Ssam 	    keystats.ks_allocs, "code cache keys allocated",
607*45834Sbostic 	    PCT(keystats.ks_allocfree, keystats.ks_allocs),
608*45834Sbostic 	    PCT(keystats.ks_norefs, keystats.ks_allocs),
609*45834Sbostic 	    PCT(keystats.ks_taken, keystats.ks_allocs),
610*45834Sbostic 	    PCT(keystats.ks_shared, keystats.ks_allocs));
611*45834Sbostic 	kread(X_DKEYSTATS, (char *)&keystats, sizeof keystats);
612*45834Sbostic 	(void) printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
61325960Ssam 	    keystats.ks_allocs, "data cache keys allocated",
614*45834Sbostic 	    PCT(keystats.ks_allocfree, keystats.ks_allocs),
615*45834Sbostic 	    PCT(keystats.ks_norefs, keystats.ks_allocs),
616*45834Sbostic 	    PCT(keystats.ks_taken, keystats.ks_allocs),
617*45834Sbostic 	    PCT(keystats.ks_shared, keystats.ks_allocs));
61825960Ssam #endif
6191155Sbill }
6201155Sbill 
6211155Sbill doforkst()
6221155Sbill {
6231155Sbill 
624*45834Sbostic 	kread(X_FORKSTAT, (char *)&forkstat, sizeof forkstat);
625*45834Sbostic 	(void) printf("%d forks, %d pages, average=%.2f\n",
6261155Sbill 		forkstat.cntfork, forkstat.sizfork,
6271155Sbill 		(float) forkstat.sizfork / forkstat.cntfork);
628*45834Sbostic 	(void) printf("%d vforks, %d pages, average=%.2f\n",
6291155Sbill 		forkstat.cntvfork, forkstat.sizvfork,
6301155Sbill 		(float)forkstat.sizvfork / forkstat.cntvfork);
6311155Sbill }
6321155Sbill 
6331155Sbill stats(dn)
6341155Sbill {
6351155Sbill 
63618761Ssam 	if (dn >= dk_ndrive) {
637*45834Sbostic 		(void) printf("  0");
6381155Sbill 		return;
6391155Sbill 	}
640*45834Sbostic 	(void) printf("%3.0f", s.xfer[dn]/etime);
6411155Sbill }
6421155Sbill 
6431155Sbill double
6441155Sbill stat1(row)
6451155Sbill {
6461448Sbill 	double t;
6471448Sbill 	register i;
6481155Sbill 
6491155Sbill 	t = 0;
6501155Sbill 	for(i=0; i<CPUSTATES; i++)
6511448Sbill 		t += s.time[i];
6521448Sbill 	if(t == 0.)
6531448Sbill 		t = 1.;
6541448Sbill 	return(s.time[row]*100./t);
6551155Sbill }
6561155Sbill 
657*45834Sbostic dointr()
6581155Sbill {
659*45834Sbostic 	register int nintr, inamlen;
660*45834Sbostic 	register long *intrcnt, inttotal, uptime = getuptime();
661*45834Sbostic 	register char *intrname;
6621155Sbill 
663*45834Sbostic 	nintr = nl[X_EINTRCNT].n_value - nl[X_INTRCNT].n_value;
664*45834Sbostic 	inamlen = nl[X_EINTRNAMES].n_value - nl[X_INTRNAMES].n_value;
665*45834Sbostic 	intrcnt = (long *)malloc((size_t)nintr);
666*45834Sbostic 	intrname = malloc((size_t)inamlen);
66717262Smckusick 	if (intrcnt == NULL || intrname == NULL) {
668*45834Sbostic 		(void) fprintf(stderr, "vmstat: %s.\n", strerror(errno));
66917262Smckusick 		exit(9);
67017262Smckusick 	}
671*45834Sbostic 	kread(X_INTRCNT, (char *)intrcnt, (size_t)nintr);
672*45834Sbostic 	kread(X_INTRNAMES, intrname, (size_t)inamlen);
673*45834Sbostic 	(void) printf("interrupt      total      rate\n");
67417262Smckusick 	inttotal = 0;
675*45834Sbostic 	nintr /= sizeof(long);
676*45834Sbostic 	while (--nintr >= 0) {
67717262Smckusick 		if (*intrcnt)
678*45834Sbostic 			(void) printf("%-12s %8ld %8ld\n", intrname,
679*45834Sbostic 			    *intrcnt, *intrcnt / uptime);
68017262Smckusick 		intrname += strlen(intrname) + 1;
68117262Smckusick 		inttotal += *intrcnt++;
68217262Smckusick 	}
683*45834Sbostic 	(void) printf("Total        %8ld %8ld\n", inttotal, inttotal / uptime);
68417262Smckusick }
68517262Smckusick 
68633610Smckusick /*
68745152Smckusick  * These names are defined in <sys/malloc.h>.
68833610Smckusick  */
68945152Smckusick char *kmemnames[] = INITKMEMNAMES;
69033610Smckusick 
69133610Smckusick domem()
69233610Smckusick {
693*45834Sbostic 	register struct kmembuckets *kp;
694*45834Sbostic 	register struct kmemstats *ks;
695*45834Sbostic 	register int i;
69633610Smckusick 	struct kmemstats kmemstats[M_LAST];
69733610Smckusick 	struct kmembuckets buckets[MINBUCKET + 16];
69833610Smckusick 
699*45834Sbostic 	kread(X_KMEMBUCKETS, (char *)buckets, sizeof buckets);
700*45834Sbostic 	(void) printf("Memory statistics by bucket size\n");
701*45834Sbostic 	(void) printf(
702*45834Sbostic 	    "    Size   In Use   Free   Requests  HighWater  Couldfree\n");
70333610Smckusick 	for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) {
70433610Smckusick 		if (kp->kb_calls == 0)
70533610Smckusick 			continue;
706*45834Sbostic 		(void) printf("%8d%9ld%7ld%11ld%8ld%11ld\n", 1 << i,
70733610Smckusick 			kp->kb_total - kp->kb_totalfree,
70833610Smckusick 			kp->kb_totalfree, kp->kb_calls,
70933610Smckusick 			kp->kb_highwat, kp->kb_couldfree);
71033610Smckusick 
71133610Smckusick 	}
712*45834Sbostic 	kread(X_KMEMSTAT, (char *)kmemstats, sizeof kmemstats);
713*45834Sbostic 	(void) printf("Memory statistics by type\n");
714*45834Sbostic 	(void) printf("\
715*45834Sbostic      Type   In Use  MemUse   HighUse  Limit  Requests TypeLimit KernLimit\n");
71633610Smckusick 	for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
71733610Smckusick 		if (ks->ks_calls == 0)
71833610Smckusick 			continue;
719*45834Sbostic 		(void) printf("%10s%7ld%8ldK%9ldK%6ldK%9ld%7u%10u\n",
72033610Smckusick 			kmemnames[i] ? kmemnames[i] : "undefined",
72133610Smckusick 			ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
72233610Smckusick 			(ks->ks_maxused + 1023) / 1024,
72333610Smckusick 			(ks->ks_limit + 1023) / 1024, ks->ks_calls,
72433610Smckusick 			ks->ks_limblocks, ks->ks_mapblocks);
72533610Smckusick 	}
72633610Smckusick }
72733610Smckusick 
7283162Stoy /*
7293162Stoy  * Read the drive names out of kmem.
7303162Stoy  */
73110826Ssam #ifdef vax
732*45834Sbostic #include <uba/ubavar.h>
733*45834Sbostic #include <mba/mbavar.h>
73418761Ssam 
7353162Stoy read_names()
7363162Stoy {
737*45834Sbostic 	register char *p;
738*45834Sbostic 	unsigned long mp, up;
7393162Stoy 	struct mba_device mdev;
7403162Stoy 	struct mba_driver mdrv;
741*45834Sbostic 	struct uba_device udev;
7423162Stoy 	struct uba_driver udrv;
743*45834Sbostic 	char name[10];
744*45834Sbostic 	static char buf[BUFSIZ];
7453162Stoy 
746*45834Sbostic 	mp = nl[X_MBDINIT].n_value;
747*45834Sbostic 	up = nl[X_UBDINIT].n_value;
748*45834Sbostic 	if (mp == 0 && up == 0) {
749*45834Sbostic 		(void) fprintf(stderr,
750*45834Sbostic 		    "vmstat: disk init info not in namelist\n");
7513162Stoy 		exit(1);
7523162Stoy 	}
753*45834Sbostic 	p = buf;
754*45834Sbostic 	if (mp) for (;; mp += sizeof mdev) {
755*45834Sbostic 		(void) kvm_read((u_long)mp, (char *)&mdev, sizeof mdev);
7563162Stoy 		if (mdev.mi_driver == 0)
7573162Stoy 			break;
7583162Stoy 		if (mdev.mi_dk < 0 || mdev.mi_alive == 0)
7593162Stoy 			continue;
760*45834Sbostic 		(void) kvm_read((u_long)mdev.mi_driver,
761*45834Sbostic 		    (char *)&mdrv, sizeof mdrv);
762*45834Sbostic 		(void) kvm_read((u_long)mdrv.md_dname, name, sizeof name);
763*45834Sbostic 		dr_name[mdev.mi_dk] = p;
764*45834Sbostic 		p += sprintf(p, "%s%d", name, mdev.mi_unit);
7653162Stoy 	}
766*45834Sbostic 	if (up) for (;; up += sizeof udev) {
767*45834Sbostic 		(void) kvm_read(up, (char *)&udev, sizeof udev);
7683162Stoy 		if (udev.ui_driver == 0)
7693162Stoy 			break;
7703162Stoy 		if (udev.ui_dk < 0 || udev.ui_alive == 0)
7713162Stoy 			continue;
772*45834Sbostic 		(void) kvm_read((u_long)udev.ui_driver,
773*45834Sbostic 		    (char *)&udrv, sizeof udrv);
774*45834Sbostic 		(void) kvm_read((u_long)udrv.ud_dname, name, sizeof name);
775*45834Sbostic 		dr_name[udev.ui_dk] = p;
776*45834Sbostic 		p += sprintf(p, "%s%d", name, udev.ui_unit);
7773162Stoy 	}
7783162Stoy }
77910826Ssam #endif
78025708Ssam 
78125708Ssam #ifdef tahoe
782*45834Sbostic #include <vba/vbavar.h>
78325708Ssam 
78425708Ssam /*
78525708Ssam  * Read the drive names out of kmem.
78625708Ssam  */
78725708Ssam read_names()
78825708Ssam {
789*45834Sbostic 	register char *p;
79025708Ssam 	struct vba_device udev, *up;
79125708Ssam 	struct vba_driver udrv;
792*45834Sbostic 	char name[10];
793*45834Sbostic 	static char buf[BUFSIZ];
79425708Ssam 
79525708Ssam 	up = (struct vba_device *) nl[X_VBDINIT].n_value;
79625708Ssam 	if (up == 0) {
797*45834Sbostic 		(void) fprintf(stderr,
798*45834Sbostic 		    "vmstat: disk init info not in namelist\n");
79925708Ssam 		exit(1);
80025708Ssam 	}
801*45834Sbostic 	p = buf;
802*45834Sbostic 	for (;; up += sizeof udev) {
803*45834Sbostic 		(void) kvm_read(up, (char *)&udev, sizeof udev);
80425708Ssam 		if (udev.ui_driver == 0)
80525708Ssam 			break;
80625708Ssam 		if (udev.ui_dk < 0 || udev.ui_alive == 0)
80725708Ssam 			continue;
808*45834Sbostic 		(void) kvm_read((u_long)udev.ui_driver,
809*45834Sbostic 		    (char *)&udrv, sizeof udrv);
810*45834Sbostic 		(void) kvm_read((u_long)udrv.ud_dname, name, sizeof name);
811*45834Sbostic 		dr_name[udev.ui_dk] = p;
812*45834Sbostic 		p += sprintf(p, "%s%d", name, udev.ui_unit);
81325708Ssam 	}
81425708Ssam }
81525708Ssam #endif
81642952Sbostic 
81742952Sbostic #ifdef hp300
81842952Sbostic #include <hpdev/device.h>
81942952Sbostic 
82042952Sbostic read_names()
82142952Sbostic {
822*45834Sbostic 	register char *p;
823*45834Sbostic 	register u_long hp;
82442952Sbostic 	struct hp_device hdev;
82542952Sbostic 	struct driver hdrv;
826*45834Sbostic 	static char buf[BUFSIZ];
82742952Sbostic 
828*45834Sbostic 	hp = nl[X_HPDINIT].n_value;
82942952Sbostic 	if (hp == 0) {
830*45834Sbostic 		(void) fprintf(stderr,
831*45834Sbostic 		    "vmstat: disk init info not in namelist\n");
83242952Sbostic 		exit(1);
83342952Sbostic 	}
834*45834Sbostic 	p = buf;
835*45834Sbostic 	for (;; hp += sizeof hdev) {
836*45834Sbostic 		(void) kvm_read(hp, (char *)&hdev, sizeof hdev);
83742952Sbostic 		if (hdev.hp_driver == 0)
83842952Sbostic 			break;
839*45834Sbostic 		if (hdev.hp_dk < 0 || hdev.hp_alive == 0)
84042952Sbostic 			continue;
841*45834Sbostic 		(void) kvm_read((u_long)hdev.hp_driver,
842*45834Sbostic 		    (char *)&hdrv, sizeof hdrv);
843*45834Sbostic 		(void) kvm_read((u_long)hdrv.d_name, name, sizeof name);
844*45834Sbostic 		dr_name[hdev.hp_dk] = p;
845*45834Sbostic 		p += sprintf(p, "%s%d", name, hdev.hp_unit);
84642952Sbostic 	}
84742952Sbostic }
84842952Sbostic #endif
849