vmstat.c revision 12804
1/*
2 * Copyright (c) 1980, 1986, 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char copyright[] =
36"@(#) Copyright (c) 1980, 1986, 1991, 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)vmstat.c	8.1 (Berkeley) 6/6/93";
42#endif /* not lint */
43
44#include <sys/param.h>
45#include <sys/time.h>
46#include <sys/proc.h>
47#include <sys/user.h>
48#include <sys/dkstat.h>
49#include <sys/buf.h>
50#include <sys/namei.h>
51#include <sys/malloc.h>
52#include <sys/signal.h>
53#include <sys/fcntl.h>
54#include <sys/ioctl.h>
55#include <sys/sysctl.h>
56#include <sys/vmmeter.h>
57#include <vm/vm.h>
58#include <time.h>
59#include <nlist.h>
60#include <kvm.h>
61#include <errno.h>
62#include <unistd.h>
63#include <stdio.h>
64#include <ctype.h>
65#include <stdlib.h>
66#include <string.h>
67#include <paths.h>
68#include <limits.h>
69
70struct nlist namelist[] = {
71#define	X_CPTIME	0
72	{ "_cp_time" },
73#define	X_DK_NDRIVE	1
74	{ "_dk_ndrive" },
75#define X_SUM		2
76	{ "_cnt" },
77#define	X_BOOTTIME	3
78	{ "_boottime" },
79#define	X_DKXFER	4
80	{ "_dk_xfer" },
81#define X_HZ		5
82	{ "_hz" },
83#define X_STATHZ	6
84	{ "_stathz" },
85#define X_NCHSTATS	7
86	{ "_nchstats" },
87#define	X_INTRNAMES	8
88	{ "_intrnames" },
89#define	X_EINTRNAMES	9
90	{ "_eintrnames" },
91#define	X_INTRCNT	10
92	{ "_intrcnt" },
93#define	X_EINTRCNT	11
94	{ "_eintrcnt" },
95#define	X_KMEMSTAT	12
96	{ "_kmemstats" },
97#define	X_KMEMBUCKETS	13
98	{ "_bucket" },
99#ifdef notdef
100#define	X_DEFICIT	14
101	{ "_deficit" },
102#define	X_FORKSTAT	15
103	{ "_forkstat" },
104#define X_REC		16
105	{ "_rectime" },
106#define X_PGIN		17
107	{ "_pgintime" },
108#define	X_XSTATS	18
109	{ "_xstats" },
110#define X_END		19
111#else
112#define X_END		14
113#endif
114#if defined(hp300) || defined(luna68k)
115#define	X_HPDINIT	(X_END)
116	{ "_hp_dinit" },
117#endif
118#if defined(i386)
119#define X_DK_NAMES	(X_END)
120	{ "_dk_names" },
121#endif
122#ifdef mips
123#define	X_SCSI_DINIT	(X_END)
124	{ "_scsi_dinit" },
125#endif
126#ifdef tahoe
127#define	X_VBDINIT	(X_END)
128	{ "_vbdinit" },
129#define	X_CKEYSTATS	(X_END+1)
130	{ "_ckeystats" },
131#define	X_DKEYSTATS	(X_END+2)
132	{ "_dkeystats" },
133#endif
134#ifdef vax
135#define X_MBDINIT	(X_END)
136	{ "_mbdinit" },
137#define X_UBDINIT	(X_END+1)
138	{ "_ubdinit" },
139#endif
140	{ "" },
141};
142
143struct _disk {
144	long time[CPUSTATES];
145	long *xfer;
146} cur, last;
147
148struct	vmmeter sum, osum;
149char	**dr_name;
150int	*dr_select, dk_ndrive, ndrives;
151
152int	winlines = 20;
153
154kvm_t *kd;
155
156#define	FORKSTAT	0x01
157#define	INTRSTAT	0x02
158#define	MEMSTAT		0x04
159#define	SUMSTAT		0x08
160#define	TIMESTAT	0x10
161#define	VMSTAT		0x20
162
163#include "names.c"			/* disk names -- machine dependent */
164
165void	cpustats(), dkstats(), dointr(), domem(), dosum();
166void	dovmstat(), kread(), usage();
167#ifdef notdef
168void	dotimes(), doforkst();
169#endif
170
171main(argc, argv)
172	register int argc;
173	register char **argv;
174{
175	extern int optind;
176	extern char *optarg;
177	register int c, todo;
178	u_int interval;
179	int reps;
180	char *memf, *nlistf;
181        char errbuf[_POSIX2_LINE_MAX];
182
183	memf = nlistf = NULL;
184	interval = reps = todo = 0;
185	while ((c = getopt(argc, argv, "c:fiM:mN:stw:")) != EOF) {
186		switch (c) {
187		case 'c':
188			reps = atoi(optarg);
189			break;
190#ifndef notdef
191		case 'f':
192			todo |= FORKSTAT;
193			break;
194#endif
195		case 'i':
196			todo |= INTRSTAT;
197			break;
198		case 'M':
199			memf = optarg;
200			break;
201		case 'm':
202			todo |= MEMSTAT;
203			break;
204		case 'N':
205			nlistf = optarg;
206			break;
207		case 's':
208			todo |= SUMSTAT;
209			break;
210#ifndef notdef
211		case 't':
212			todo |= TIMESTAT;
213			break;
214#endif
215		case 'w':
216			interval = atoi(optarg);
217			break;
218		case '?':
219		default:
220			usage();
221		}
222	}
223	argc -= optind;
224	argv += optind;
225
226	if (todo == 0)
227		todo = VMSTAT;
228
229	/*
230	 * Discard setgid privileges if not the running kernel so that bad
231	 * guys can't print interesting stuff from kernel memory.
232	 */
233	if (nlistf != NULL || memf != NULL)
234		setgid(getgid());
235
236        kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
237	if (kd == 0) {
238		(void)fprintf(stderr,
239		    "vmstat: kvm_openfiles: %s\n", errbuf);
240		exit(1);
241	}
242
243	if ((c = kvm_nlist(kd, namelist)) != 0) {
244		if (c > 0) {
245			(void)fprintf(stderr,
246			    "vmstat: undefined symbols:");
247			for (c = 0;
248			    c < sizeof(namelist)/sizeof(namelist[0]); c++)
249				if (namelist[c].n_type == 0)
250					fprintf(stderr, " %s",
251					    namelist[c].n_name);
252			(void)fputc('\n', stderr);
253		} else
254			(void)fprintf(stderr, "vmstat: kvm_nlist: %s\n",
255			    kvm_geterr(kd));
256		exit(1);
257	}
258
259	if (todo & VMSTAT) {
260		char **getdrivedata();
261		struct winsize winsize;
262
263		argv = getdrivedata(argv);
264		winsize.ws_row = 0;
265		(void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize);
266		if (winsize.ws_row > 0)
267			winlines = winsize.ws_row;
268
269	}
270
271#define	BACKWARD_COMPATIBILITY
272#ifdef	BACKWARD_COMPATIBILITY
273	if (*argv) {
274		interval = atoi(*argv);
275		if (*++argv)
276			reps = atoi(*argv);
277	}
278#endif
279
280	if (interval) {
281		if (!reps)
282			reps = -1;
283	} else if (reps)
284		interval = 1;
285
286#ifdef notdef
287	if (todo & FORKSTAT)
288		doforkst();
289#endif
290	if (todo & MEMSTAT)
291		domem();
292	if (todo & SUMSTAT)
293		dosum();
294#ifdef notdef
295	if (todo & TIMESTAT)
296		dotimes();
297#endif
298	if (todo & INTRSTAT)
299		dointr();
300	if (todo & VMSTAT)
301		dovmstat(interval, reps);
302	exit(0);
303}
304
305char **
306getdrivedata(argv)
307	char **argv;
308{
309	register int i;
310	register char **cp;
311	char buf[30];
312
313	kread(X_DK_NDRIVE, &dk_ndrive, sizeof(dk_ndrive));
314	if (dk_ndrive < 0) {
315		(void)fprintf(stderr, "vmstat: dk_ndrive %d\n", dk_ndrive);
316		exit(1);
317	}
318	dr_select = calloc((size_t)dk_ndrive, sizeof(int));
319	dr_name = calloc((size_t)dk_ndrive, sizeof(char *));
320	for (i = 0; i < dk_ndrive; i++)
321		dr_name[i] = NULL;
322	cur.xfer = calloc((size_t)dk_ndrive, sizeof(long));
323	last.xfer = calloc((size_t)dk_ndrive, sizeof(long));
324	if (!read_names())
325		exit (1);
326	for (i = 0; i < dk_ndrive; i++)
327		if (dr_name[i] == NULL) {
328			(void)sprintf(buf, "??%d", i);
329			dr_name[i] = strdup(buf);
330		}
331
332	/*
333	 * Choose drives to be displayed.  Priority goes to (in order) drives
334	 * supplied as arguments, default drives.  If everything isn't filled
335	 * in and there are drives not taken care of, display the first few
336	 * that fit.
337	 */
338#define BACKWARD_COMPATIBILITY
339	for (ndrives = 0; *argv; ++argv) {
340#ifdef	BACKWARD_COMPATIBILITY
341		if (isdigit(**argv))
342			break;
343#endif
344		for (i = 0; i < dk_ndrive; i++) {
345			if (strcmp(dr_name[i], *argv))
346				continue;
347			dr_select[i] = 1;
348			++ndrives;
349			break;
350		}
351	}
352	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
353		if (dr_select[i])
354			continue;
355		for (cp = defdrives; *cp; cp++)
356			if (strcmp(dr_name[i], *cp) == 0) {
357				dr_select[i] = 1;
358				++ndrives;
359				break;
360			}
361	}
362	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
363		if (dr_select[i])
364			continue;
365		dr_select[i] = 1;
366		++ndrives;
367	}
368	return(argv);
369}
370
371long
372getuptime()
373{
374	static time_t now, boottime;
375	time_t uptime;
376
377	if (boottime == 0)
378		kread(X_BOOTTIME, &boottime, sizeof(boottime));
379	(void)time(&now);
380	uptime = now - boottime;
381	if (uptime <= 0 || uptime > 60*60*24*365*10) {
382		(void)fprintf(stderr,
383		    "vmstat: time makes no sense; namelist must be wrong.\n");
384		exit(1);
385	}
386	return(uptime);
387}
388
389int	hz, hdrcnt;
390
391void
392dovmstat(interval, reps)
393	u_int interval;
394	int reps;
395{
396	struct vmtotal total;
397	time_t uptime, halfuptime;
398	void needhdr();
399	int mib[2], size;
400
401	uptime = getuptime();
402	halfuptime = uptime / 2;
403	(void)signal(SIGCONT, needhdr);
404
405	if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0)
406		kread(X_STATHZ, &hz, sizeof(hz));
407	if (!hz)
408		kread(X_HZ, &hz, sizeof(hz));
409
410	for (hdrcnt = 1;;) {
411		if (!--hdrcnt)
412			printhdr();
413		kread(X_CPTIME, cur.time, sizeof(cur.time));
414		kread(X_DKXFER, cur.xfer, sizeof(*cur.xfer) * dk_ndrive);
415		kread(X_SUM, &sum, sizeof(sum));
416		size = sizeof(total);
417		mib[0] = CTL_VM;
418		mib[1] = VM_METER;
419		if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
420			printf("Can't get kerninfo: %s\n", strerror(errno));
421			bzero(&total, sizeof(total));
422		}
423		(void)printf("%2d%2d%2d",
424		    total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
425#define pgtok(a) ((a) * sum.v_page_size >> 10)
426#define	rate(x)	(((x) + halfuptime) / uptime)	/* round */
427		(void)printf("%6ld%6ld ",
428		    pgtok(total.t_avm), pgtok(total.t_free));
429		(void)printf("%4lu ", rate(sum.v_vm_faults - osum.v_vm_faults));
430		(void)printf("%3lu ",
431		    rate(sum.v_reactivated - osum.v_reactivated));
432		(void)printf("%3lu ", rate(sum.v_swapin + sum.v_vnodein -
433		    (osum.v_swapin + osum.v_vnodein)));
434		(void)printf("%3lu ", rate(sum.v_swapout + sum.v_vnodeout -
435		    (osum.v_swapout + osum.v_vnodeout)));
436		(void)printf("%3lu ", rate(sum.v_tfree - osum.v_tfree));
437		(void)printf("%3lu ", rate(sum.v_pdpages - osum.v_pdpages));
438		dkstats();
439		(void)printf("%4lu %4lu %3lu ",
440		    rate(sum.v_intr - osum.v_intr),
441		    rate(sum.v_syscall - osum.v_syscall),
442		    rate(sum.v_swtch - osum.v_swtch));
443		cpustats();
444		(void)printf("\n");
445		(void)fflush(stdout);
446		if (reps >= 0 && --reps <= 0)
447			break;
448		osum = sum;
449		uptime = interval;
450		/*
451		 * We round upward to avoid losing low-frequency events
452		 * (i.e., >= 1 per interval but < 1 per second).
453		 */
454		if (interval != 1)
455			halfuptime = (uptime + 1) / 2;
456		else
457			halfuptime = 0;
458		(void)sleep(interval);
459	}
460}
461
462printhdr()
463{
464	register int i;
465
466	(void)printf(" procs   memory     page%*s", 20, "");
467	if (ndrives > 1)
468		(void)printf("disks %*s  faults      cpu\n",
469		   ndrives * 3 - 6, "");
470	else
471		(void)printf("%*s  faults      cpu\n", ndrives * 3, "");
472	(void)printf(" r b w   avm   fre  flt  re  pi  po  fr  sr ");
473	for (i = 0; i < dk_ndrive; i++)
474		if (dr_select[i])
475			(void)printf("%c%c ", dr_name[i][0],
476			    dr_name[i][strlen(dr_name[i]) - 1]);
477	(void)printf("  in   sy  cs us sy id\n");
478	hdrcnt = winlines - 2;
479}
480
481/*
482 * Force a header to be prepended to the next output.
483 */
484void
485needhdr()
486{
487
488	hdrcnt = 1;
489}
490
491#ifdef notdef
492void
493dotimes()
494{
495	u_int pgintime, rectime;
496
497	kread(X_REC, &rectime, sizeof(rectime));
498	kread(X_PGIN, &pgintime, sizeof(pgintime));
499	kread(X_SUM, &sum, sizeof(sum));
500	(void)printf("%u reclaims, %u total time (usec)\n",
501	    sum.v_pgrec, rectime);
502	(void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec);
503	(void)printf("\n");
504	(void)printf("%u page ins, %u total time (msec)\n",
505	    sum.v_pgin, pgintime / 10);
506	(void)printf("average: %8.1f msec / page in\n",
507	    pgintime / (sum.v_pgin * 10.0));
508}
509#endif
510
511pct(top, bot)
512	long top, bot;
513{
514	long ans;
515
516	if (bot == 0)
517		return(0);
518	ans = (quad_t)top * 100 / bot;
519	return (ans);
520}
521
522#define	PCT(top, bot) pct((long)(top), (long)(bot))
523
524#if defined(tahoe)
525#include <machine/cpu.h>
526#endif
527
528void
529dosum()
530{
531	struct nchstats nchstats;
532	long nchtotal;
533#if defined(tahoe)
534	struct keystats keystats;
535#endif
536
537	kread(X_SUM, &sum, sizeof(sum));
538	(void)printf("%9u cpu context switches\n", sum.v_swtch);
539	(void)printf("%9u device interrupts\n", sum.v_intr);
540	(void)printf("%9u software interrupts\n", sum.v_soft);
541#ifdef vax
542	(void)printf("%9u pseudo-dma dz interrupts\n", sum.v_pdma);
543#endif
544	(void)printf("%9u traps\n", sum.v_trap);
545	(void)printf("%9u system calls\n", sum.v_syscall);
546	(void)printf("%9u swap pager pageins\n", sum.v_swapin);
547	(void)printf("%9u swap pager pages paged in\n", sum.v_swappgsin);
548	(void)printf("%9u swap pager pageouts\n", sum.v_swapout);
549	(void)printf("%9u swap pager pages paged out\n", sum.v_swappgsout);
550	(void)printf("%9u vnode pager pageins\n", sum.v_vnodein);
551	(void)printf("%9u vnode pager pages paged in\n", sum.v_vnodepgsin);
552	(void)printf("%9u vnode pager pageouts\n", sum.v_vnodeout);
553	(void)printf("%9u vnode pager pages paged out\n", sum.v_vnodepgsout);
554	(void)printf("%9u page daemon wakeups\n", sum.v_pdwakeups);
555	(void)printf("%9u pages examined by the page daemon\n", sum.v_pdpages);
556	(void)printf("%9u pages reactivated\n", sum.v_reactivated);
557	(void)printf("%9u copy-on-write faults\n", sum.v_cow_faults);
558	(void)printf("%9u zero fill pages zeroed\n", sum.v_zfod);
559	(void)printf("%9u intransit blocking page faults\n", sum.v_intrans);
560	(void)printf("%9u total VM faults taken\n", sum.v_vm_faults);
561	(void)printf("%9u pages freed\n", sum.v_tfree);
562	(void)printf("%9u pages freed by daemon\n", sum.v_dfree);
563	(void)printf("%9u pages freed by exiting processes\n", sum.v_pfree);
564	(void)printf("%9u pages active\n", sum.v_active_count);
565	(void)printf("%9u pages inactive\n", sum.v_inactive_count);
566	(void)printf("%9u pages in VM cache\n", sum.v_cache_count);
567	(void)printf("%9u pages wired down\n", sum.v_wire_count);
568	(void)printf("%9u pages free\n", sum.v_free_count);
569	(void)printf("%9u bytes per page\n", sum.v_page_size);
570	kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
571	nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
572	    nchstats.ncs_badhits + nchstats.ncs_falsehits +
573	    nchstats.ncs_miss + nchstats.ncs_long;
574	(void)printf("%9ld total name lookups\n", nchtotal);
575	(void)printf(
576	    "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
577	    "", PCT(nchstats.ncs_goodhits, nchtotal),
578	    PCT(nchstats.ncs_neghits, nchtotal),
579	    PCT(nchstats.ncs_pass2, nchtotal));
580	(void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
581	    PCT(nchstats.ncs_badhits, nchtotal),
582	    PCT(nchstats.ncs_falsehits, nchtotal),
583	    PCT(nchstats.ncs_long, nchtotal));
584#if defined(tahoe)
585	kread(X_CKEYSTATS, &keystats, sizeof(keystats));
586	(void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
587	    keystats.ks_allocs, "code cache keys allocated",
588	    PCT(keystats.ks_allocfree, keystats.ks_allocs),
589	    PCT(keystats.ks_norefs, keystats.ks_allocs),
590	    PCT(keystats.ks_taken, keystats.ks_allocs),
591	    PCT(keystats.ks_shared, keystats.ks_allocs));
592	kread(X_DKEYSTATS, &keystats, sizeof(keystats));
593	(void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
594	    keystats.ks_allocs, "data cache keys allocated",
595	    PCT(keystats.ks_allocfree, keystats.ks_allocs),
596	    PCT(keystats.ks_norefs, keystats.ks_allocs),
597	    PCT(keystats.ks_taken, keystats.ks_allocs),
598	    PCT(keystats.ks_shared, keystats.ks_allocs));
599#endif
600}
601
602#ifdef notdef
603void
604doforkst()
605{
606	struct forkstat fks;
607
608	kread(X_FORKSTAT, &fks, sizeof(struct forkstat));
609	(void)printf("%d forks, %d pages, average %.2f\n",
610	    fks.cntfork, fks.sizfork, (double)fks.sizfork / fks.cntfork);
611	(void)printf("%d vforks, %d pages, average %.2f\n",
612	    fks.cntvfork, fks.sizvfork, (double)fks.sizvfork / fks.cntvfork);
613}
614#endif
615
616void
617dkstats()
618{
619	register int dn, state;
620	double etime;
621	long tmp;
622
623	for (dn = 0; dn < dk_ndrive; ++dn) {
624		tmp = cur.xfer[dn];
625		cur.xfer[dn] -= last.xfer[dn];
626		last.xfer[dn] = tmp;
627	}
628	etime = 0;
629	for (state = 0; state < CPUSTATES; ++state) {
630		tmp = cur.time[state];
631		cur.time[state] -= last.time[state];
632		last.time[state] = tmp;
633		etime += cur.time[state];
634	}
635	if (etime == 0)
636		etime = 1;
637	etime /= hz;
638	for (dn = 0; dn < dk_ndrive; ++dn) {
639		if (!dr_select[dn])
640			continue;
641		(void)printf("%2.0f ", cur.xfer[dn] / etime);
642	}
643}
644
645void
646cpustats()
647{
648	register int state;
649	double pct, total;
650
651	total = 0;
652	for (state = 0; state < CPUSTATES; ++state)
653		total += cur.time[state];
654	if (total)
655		pct = 100 / total;
656	else
657		pct = 0;
658	(void)printf("%2.0f ", (cur.time[CP_USER] + cur.time[CP_NICE]) * pct);
659	(void)printf("%2.0f ", (cur.time[CP_SYS] + cur.time[CP_INTR]) * pct);
660	(void)printf("%2.0f", cur.time[CP_IDLE] * pct);
661}
662
663void
664dointr()
665{
666	register long *intrcnt, inttotal, uptime;
667	register int nintr, inamlen;
668	register char *intrname;
669
670	uptime = getuptime();
671	nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value;
672	inamlen =
673	    namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value;
674	intrcnt = malloc((size_t)nintr);
675	intrname = malloc((size_t)inamlen);
676	if (intrcnt == NULL || intrname == NULL) {
677		(void)fprintf(stderr, "vmstat: %s.\n", strerror(errno));
678		exit(1);
679	}
680	kread(X_INTRCNT, intrcnt, (size_t)nintr);
681	kread(X_INTRNAMES, intrname, (size_t)inamlen);
682	(void)printf("interrupt      total      rate\n");
683	inttotal = 0;
684	nintr /= sizeof(long);
685	while (--nintr >= 0) {
686		if (*intrcnt)
687			(void)printf("%-12s %8ld %8ld\n", intrname,
688			    *intrcnt, *intrcnt / uptime);
689		intrname += strlen(intrname) + 1;
690		inttotal += *intrcnt++;
691	}
692	(void)printf("Total        %8ld %8ld\n", inttotal, inttotal / uptime);
693}
694
695/*
696 * These names are defined in <sys/malloc.h>.
697 */
698char *kmemnames[] = INITKMEMNAMES;
699
700void
701domem()
702{
703	register struct kmembuckets *kp;
704	register struct kmemstats *ks;
705	register int i, j;
706	int len, size, first;
707	long totuse = 0, totfree = 0, totreq = 0;
708	char *name;
709	struct kmemstats kmemstats[M_LAST];
710	struct kmembuckets buckets[MINBUCKET + 16];
711
712	kread(X_KMEMBUCKETS, buckets, sizeof(buckets));
713	(void)printf("Memory statistics by bucket size\n");
714	(void)printf(
715	    "Size   In Use   Free   Requests  HighWater  Couldfree\n");
716	for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) {
717		if (kp->kb_calls == 0)
718			continue;
719		size = 1 << i;
720		if(size < 1024)
721			(void)printf("%4d",size);
722		else
723			(void)printf("%3dK",size>>10);
724		(void)printf(" %8ld %6ld %10ld %7ld %10ld\n",
725			kp->kb_total - kp->kb_totalfree,
726			kp->kb_totalfree, kp->kb_calls,
727			kp->kb_highwat, kp->kb_couldfree);
728		totfree += size * kp->kb_totalfree;
729	}
730
731	kread(X_KMEMSTAT, kmemstats, sizeof(kmemstats));
732	(void)printf("\nMemory usage type by bucket size\n");
733	(void)printf("Size  Type(s)\n");
734	kp = &buckets[MINBUCKET];
735	for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) {
736		if (kp->kb_calls == 0)
737			continue;
738		first = 1;
739		len = 8;
740		for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
741			if (ks->ks_calls == 0)
742				continue;
743			if ((ks->ks_size & j) == 0)
744				continue;
745			name = kmemnames[i] ? kmemnames[i] : "undefined";
746			len += 2 + strlen(name);
747			if (first && j < 1024)
748				printf("%4d  %s", j, name);
749			else if (first)
750				printf("%3dK  %s", j>>10, name);
751			else
752				printf(",");
753			if (len >= 79) {
754				printf("\n\t ");
755				len = 10 + strlen(name);
756			}
757			if (!first)
758				printf(" %s", name);
759			first = 0;
760		}
761		printf("\n");
762	}
763
764	(void)printf(
765	    "\nMemory statistics by type                          Type  Kern\n");
766	(void)printf(
767"        Type  InUse MemUse HighUse  Limit Requests Limit Limit Size(s)\n");
768	for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
769		if (ks->ks_calls == 0)
770			continue;
771		(void)printf("%13s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u",
772		    kmemnames[i] ? kmemnames[i] : "undefined",
773		    ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
774		    (ks->ks_maxused + 1023) / 1024,
775		    (ks->ks_limit + 1023) / 1024, ks->ks_calls,
776		    ks->ks_limblocks, ks->ks_mapblocks);
777		first = 1;
778		for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
779			if ((ks->ks_size & j) == 0)
780				continue;
781			if (first)
782				printf("  ");
783			else
784				printf(",");
785			if(j<1024)
786				printf("%d",j);
787			else
788				printf("%dK",j>>10);
789			first = 0;
790		}
791		printf("\n");
792		totuse += ks->ks_memuse;
793		totreq += ks->ks_calls;
794	}
795	(void)printf("\nMemory Totals:  In Use    Free    Requests\n");
796	(void)printf("              %7ldK %6ldK    %8ld\n",
797	     (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq);
798}
799
800/*
801 * kread reads something from the kernel, given its nlist index.
802 */
803void
804kread(nlx, addr, size)
805	int nlx;
806	void *addr;
807	size_t size;
808{
809	char *sym;
810
811	if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
812		sym = namelist[nlx].n_name;
813		if (*sym == '_')
814			++sym;
815		(void)fprintf(stderr,
816		    "vmstat: symbol %s not defined\n", sym);
817		exit(1);
818	}
819	if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) {
820		sym = namelist[nlx].n_name;
821		if (*sym == '_')
822			++sym;
823		(void)fprintf(stderr, "vmstat: %s: %s\n", sym, kvm_geterr(kd));
824		exit(1);
825	}
826}
827
828void
829usage()
830{
831	(void)fprintf(stderr,
832	    "usage: vmstat [-ims] [-c count] [-M core] \
833[-N system] [-w wait] [disks]\n");
834	exit(1);
835}
836