xref: /original-bsd/usr.bin/vmstat/vmstat.c (revision 95a66346)
1 /*
2  * Copyright (c) 1980 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1980 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)vmstat.c	5.24 (Berkeley) 03/02/91";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/file.h>
20 #include <sys/vm.h>
21 #include <sys/user.h>
22 #include <sys/dkstat.h>
23 #include <sys/buf.h>
24 #include <sys/namei.h>
25 #include <sys/text.h>
26 #include <sys/malloc.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <kvm.h>
30 #include <nlist.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <paths.h>
35 
36 struct nlist nl[] = {
37 #define	X_CPTIME	0
38 	{ "_cp_time" },
39 #define	X_RATE		1
40 	{ "_rate" },
41 #define X_TOTAL		2
42 	{ "_total" },
43 #define	X_DEFICIT	3
44 	{ "_deficit" },
45 #define	X_FORKSTAT	4
46 	{ "_forkstat" },
47 #define X_SUM		5
48 	{ "_sum" },
49 #define	X_FIRSTFREE	6
50 	{ "_firstfree" },
51 #define	X_MAXFREE	7
52 	{ "_maxfree" },
53 #define	X_BOOTTIME	8
54 	{ "_boottime" },
55 #define	X_DKXFER	9
56 	{ "_dk_xfer" },
57 #define X_REC		10
58 	{ "_rectime" },
59 #define X_PGIN		11
60 	{ "_pgintime" },
61 #define X_HZ		12
62 	{ "_hz" },
63 #define X_PHZ		13
64 	{ "_phz" },
65 #define X_NCHSTATS	14
66 	{ "_nchstats" },
67 #define	X_INTRNAMES	15
68 	{ "_intrnames" },
69 #define	X_EINTRNAMES	16
70 	{ "_eintrnames" },
71 #define	X_INTRCNT	17
72 	{ "_intrcnt" },
73 #define	X_EINTRCNT	18
74 	{ "_eintrcnt" },
75 #define	X_DK_NDRIVE	19
76 	{ "_dk_ndrive" },
77 #define	X_XSTATS	20
78 	{ "_xstats" },
79 #define	X_KMEMSTAT	21
80 	{ "_kmemstats" },
81 #define	X_KMEMBUCKETS	22
82 	{ "_bucket" },
83 #define X_END		22
84 #ifdef vax
85 #define X_MBDINIT	(X_END+1)
86 	{ "_mbdinit" },
87 #define X_UBDINIT	(X_END+2)
88 	{ "_ubdinit" },
89 #endif
90 #ifdef tahoe
91 #define	X_VBDINIT	(X_END+1)
92 	{ "_vbdinit" },
93 #define	X_CKEYSTATS	(X_END+2)
94 	{ "_ckeystats" },
95 #define	X_DKEYSTATS	(X_END+3)
96 	{ "_dkeystats" },
97 #endif
98 #ifdef hp300
99 #define	X_HPDINIT	(X_END+1)
100 	{ "_hp_dinit" },
101 #endif
102 	{ "" },
103 };
104 
105 char	*vmunix = _PATH_UNIX;
106 char	*kmem = NULL;
107 char	**dr_name;
108 int	*dr_select;
109 int	dk_ndrive;
110 int	ndrives = 0;
111 #ifdef vax
112 char	*defdrives[] = { "hp0", "hp1", "hp2",  0 };
113 #else
114 #ifdef hp300
115 char	*defdrives[] = { "rd0", "rd1", "rd2",  0 };
116 #else
117 char	*defdrives[] = { 0 };
118 #endif
119 #endif
120 double	stat1();
121 int	firstfree, maxfree;
122 int	hz;
123 int	phz;
124 int	HZ;
125 
126 struct {
127 	int	busy;
128 	long	time[CPUSTATES];
129 	long	*xfer;
130 	struct	vmmeter Rate;
131 	struct	vmtotal	Total;
132 	struct	vmmeter Sum;
133 	struct	forkstat Forkstat;
134 	unsigned rectime;
135 	unsigned pgintime;
136 } s, s1;
137 #define	rate		s.Rate
138 #define	total		s.Total
139 #define	sum		s.Sum
140 #define	forkstat	s.Forkstat
141 
142 struct	vmmeter osum;
143 int	deficit;
144 double	etime;
145 time_t	now, boottime;
146 int	lines = 1;
147 void	printhdr();
148 long	lseek();
149 
150 #define	INTS(x)	((x) - (hz + phz))
151 
152 #define	FORKSTAT	0x01
153 #define	INTRSTAT	0x02
154 #define	MEMSTAT		0x04
155 #define	SUMSTAT		0x08
156 #define	TIMESTAT	0x10
157 #define	VMSTAT		0x20
158 #define	ZEROOUT		0x40
159 
160 main(argc, argv)
161 	register int argc;
162 	register char **argv;
163 {
164 	register int c, i, todo = 0;
165 	extern int optind;
166 	extern char *optarg;
167 
168 	while ((c = getopt(argc, argv, "fik:mstu:z")) != EOF) {
169 		switch (c) {
170 		case 'f':
171 			todo |= FORKSTAT;
172 			break;
173 		case 'i':
174 			todo |= INTRSTAT;
175 			break;
176 		case 'k':
177 			kmem = optarg;
178 			break;
179 		case 'm':
180 			todo |= MEMSTAT;
181 			break;
182 		case 's':
183 			todo |= SUMSTAT;
184 			break;
185 		case 't':
186 			todo |= TIMESTAT;
187 			break;
188 		case 'u':
189 			vmunix = optarg;
190 			break;
191 		case 'z':
192 			todo |= ZEROOUT;
193 			break;
194 		case '?':
195 			usage();
196 			/* NOTREACHED */
197 		default:
198 			(void) fprintf(stderr,
199 			    "vmstat: internal error in options\n");
200 			exit(1);
201 			/* NOTREACHED */
202 		}
203 	}
204 
205 	/*
206 	 * Zeroing the statistics is fundamentally different
207 	 * (and really belongs in a separate program).
208 	 */
209 	if (todo & ZEROOUT) {
210 		if (todo & ~ZEROOUT || kmem)
211 			usage();
212 		nl[0].n_name = nl[X_SUM].n_name;
213 		nl[1].n_name = 0;
214 		if (nlist(vmunix, nl) || nl[0].n_type == 0) {
215 			(void) fprintf(stderr,
216 			    "vmstat: cannot get symbol %s from %s\n",
217 			    nl[0].n_name, vmunix);
218 			exit(1);
219 		}
220 		if ((i = open(kmem = _PATH_KMEM, 2)) < 0) {
221 			(void) fprintf(stderr, "vmstat: cannot write %s: %s\n",
222 			    kmem, strerror(errno));
223 			exit(1);
224 		}
225 		(void) lseek(i, (long)nl[0].n_value, L_SET);
226 		if (write(i, (char *)&s.Sum, sizeof s.Sum) != sizeof s.Sum) {
227 			(void) fprintf(stderr, "vmstat: write(%s): %s\n",
228 			    kmem, strerror(errno));
229 			exit(1);
230 		}
231 		exit(0);
232 	}
233 
234 	if (todo == 0)
235 		todo = VMSTAT;
236 
237 	if (kvm_openfiles(vmunix, kmem, (char *)NULL) < 0) {
238 		(void) fprintf(stderr,
239 		    "vmstat: kvm_openfiles(%s, %s, NULL): %s\n",
240 		    vmunix, kmem ? kmem : "NULL", kvm_geterr());
241 		exit(1);
242 	}
243 
244 	(void) kvm_nlist(nl);
245 	if (nl[0].n_type == 0) {
246 		(void) fprintf(stderr, "vmstat: %s: no namelist\n",
247 		    vmunix);
248 		exit(1);
249 	}
250 
251 	/*
252 	 * Fork, memory, sum, and time statistics do not need everything.
253 	 */
254 	if (todo & FORKSTAT)
255 		doforkst();
256 	if (todo & MEMSTAT)
257 		domem();
258 	if (todo & SUMSTAT)
259 		dosum();
260 	if (todo & TIMESTAT)
261 		dotimes();
262 	if (todo & INTRSTAT)
263 		dointr();
264 	if (todo & VMSTAT) {
265 		/*
266 		 * Read drive names, decide which drives to report, etc.
267 		 */
268 		argc -= optind;
269 		argv += optind;
270 		i = getdrivedata(argc, argv);
271 		argc -= i;
272 		argv += i;
273 		dovmstat(argc > 0 ? atoi(argv[0]) : 0,
274 			 argc > 1 ? atoi(argv[1]) : 0);
275 	}
276 	exit(0);
277 }
278 
279 usage()
280 {
281 
282 	(void) fprintf(stderr,
283 "usage: vmstat [-fimst]\n\tvmstat [drive-list] [interval [count]]\n\tvmstat -z\n");
284 	exit(1);
285 }
286 
287 /*
288  * kread reads something from the kernel, given its nlist index.
289  */
290 void
291 kread(nlx, addr, size)
292 	int nlx;
293 	char *addr;
294 	size_t size;
295 {
296 	char *sym;
297 
298 	if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0) {
299 		sym = nl[nlx].n_name;
300 		if (*sym == '_')
301 			sym++;
302 		(void) fprintf(stderr,
303 		    "vmstat: symbol `%s' not defined in %s\n", sym, vmunix);
304 		exit(1);
305 	}
306 	if (kvm_read(nl[nlx].n_value, addr, size) != size) {
307 		sym = nl[nlx].n_name;
308 		if (*sym == '_')
309 			sym++;
310 		(void) fprintf(stderr,
311 		    "vmstat: error reading `%s': %s\n", sym, kvm_geterr());
312 		exit(1);
313 	}
314 }
315 
316 getdrivedata(argc, argv)
317 	int argc;
318 	char **argv;
319 {
320 	register int i;
321 	register char **cp;
322 	int ret;
323 	char buf[30];
324 
325 	kread(X_FIRSTFREE, (char *)&firstfree, sizeof firstfree);
326 	kread(X_MAXFREE, (char *)&maxfree, sizeof maxfree);
327 	kread(X_HZ, (char *)&hz, sizeof hz);
328 	if (nl[X_PHZ].n_type != 0 && nl[X_PHZ].n_value != 0)
329 		kread(X_PHZ, (char *)&phz, sizeof phz);
330 	HZ = phz ? phz : hz;
331 	kread(X_DK_NDRIVE, (char *)&dk_ndrive, sizeof dk_ndrive);
332 	if (dk_ndrive <= 0) {
333 		(void) fprintf(stderr, "vmstat: dk_ndrive %d\n", dk_ndrive);
334 		exit(1);
335 	}
336 	dr_select = (int *)calloc((size_t)dk_ndrive, sizeof (int));
337 	dr_name = (char **)malloc((size_t)dk_ndrive * sizeof (char *));
338 	for (i = 0; i < dk_ndrive; i++)
339 		dr_name[i] = NULL;
340 	s.xfer = (long *)calloc((size_t)dk_ndrive, sizeof (long));
341 	s1.xfer = (long *)calloc((size_t)dk_ndrive, sizeof (long));
342 	read_names();
343 	for (i = 0; i < dk_ndrive; i++) {
344 		if (dr_name[i] == NULL) {
345 			(void) sprintf(buf, "??%d", i);
346 			dr_name[i] = strdup(buf);
347 		}
348 	}
349 
350 	/*
351 	 * Choose drives to be displayed.  Priority
352 	 * goes to (in order) drives supplied as arguments,
353 	 * default drives.  If everything isn't filled
354 	 * in and there are drives not taken care of,
355 	 * display the first few that fit.
356 	 */
357 	ret = 0;
358 	ndrives = 0;
359 	while (argc > 0 && !isdigit(argv[0][0])) {
360 		for (i = 0; i < dk_ndrive; i++) {
361 			if (strcmp(dr_name[i], argv[0]))
362 				continue;
363 			dr_select[i] = 1;
364 			ndrives++;
365 			break;
366 		}
367 		ret++;
368 		argc--, argv++;
369 	}
370 	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
371 		if (dr_select[i])
372 			continue;
373 		for (cp = defdrives; *cp; cp++)
374 			if (strcmp(dr_name[i], *cp) == 0) {
375 				dr_select[i] = 1;
376 				ndrives++;
377 				break;
378 			}
379 	}
380 	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
381 		if (dr_select[i])
382 			continue;
383 		dr_select[i] = 1;
384 		ndrives++;
385 	}
386 	return (ret);
387 }
388 
389 long
390 getuptime()
391 {
392 	time_t time();
393 	long uptime;
394 
395 	if (boottime == 0)
396 		kread(X_BOOTTIME, (char *)&boottime, sizeof boottime);
397 	(void) time(&now);
398 	uptime = now - boottime;
399 	if (uptime <= 0 || uptime > 60*60*24*365*10) {
400 		(void) fprintf(stderr,
401 		    "vmstat: time makes no sense; namelist must be wrong.\n");
402 		exit(1);
403 	}
404 	return (uptime);
405 }
406 
407 dovmstat(sleeptime, iter)
408 	int sleeptime, iter;
409 {
410 	register int i;
411 	long interval, t;
412 
413 	interval = getuptime();
414 	(void) signal(SIGCONT, printhdr);
415 loop:
416 	if (--lines == 0)
417 		printhdr();
418 	kread(X_CPTIME, (char *)s.time, sizeof s.time);
419 	kread(X_DKXFER, (char *)s.xfer, sizeof *s.xfer * dk_ndrive);
420 	if (interval != 1)
421 		kread(X_SUM, (char *)&rate, sizeof rate);
422 	else
423 		kread(X_RATE, (char *)&rate, sizeof rate);
424 	kread(X_TOTAL, (char *)&total, sizeof total);
425 	osum = sum;
426 	kread(X_SUM, (char *)&sum, sizeof sum);
427 	kread(X_DEFICIT, (char *)&deficit, sizeof deficit);
428 	etime = 0;
429 	for (i = 0; i < dk_ndrive; i++) {
430 		t = s.xfer[i];
431 		s.xfer[i] -= s1.xfer[i];
432 		s1.xfer[i] = t;
433 	}
434 	for (i = 0; i < CPUSTATES; i++) {
435 		t = s.time[i];
436 		s.time[i] -= s1.time[i];
437 		s1.time[i] = t;
438 		etime += s.time[i];
439 	}
440 	if (etime == 0.)
441 		etime = 1.;
442 	(void) printf("%2d%2d%2d",
443 	    total.t_rq, total.t_dw + total.t_pw, total.t_sw);
444 #define pgtok(a) ((a)*NBPG >> 10)
445 	(void) printf("%6ld%6ld", pgtok(total.t_avm), pgtok(total.t_free));
446 	(void) printf("%4lu%3lu",
447 	    (rate.v_pgrec - (rate.v_xsfrec+rate.v_xifrec)) / interval,
448 	    (rate.v_xsfrec+rate.v_xifrec) / interval);
449 	(void) printf("%4lu", pgtok(rate.v_pgpgin) / interval);
450 	(void) printf("%4lu%4lu%4d%4lu", pgtok(rate.v_pgpgout) / interval,
451 	    pgtok(rate.v_dfree) / interval,
452 	    pgtok(deficit), rate.v_scan / interval);
453 	etime /= (float)HZ;
454 	for (i = 0; i < dk_ndrive; i++)
455 		if (dr_select[i])
456 			stats(i);
457 	(void) printf("%4lu%4lu%4lu", INTS(rate.v_intr / interval),
458 	    rate.v_syscall / interval, rate.v_swtch / interval);
459 	for(i = 0; i < CPUSTATES; i++) {
460 		float f = stat1(i);
461 		if (i == 0) {		/* US+NI */
462 			i++;
463 			f += stat1(i);
464 		}
465 		(void) printf("%3.0f", f);
466 	}
467 	(void) printf("\n");
468 	(void) fflush(stdout);
469 	interval = 1;
470 	if (iter && --iter == 0)
471 		return;
472 	if (sleeptime) {
473 		sleep((unsigned)sleeptime);
474 		goto loop;
475 	}
476 }
477 
478 void
479 printhdr()
480 {
481 	register int i, j;
482 
483 	(void) printf(" procs     memory              page           ");
484 	i = (ndrives * 3 - 6) / 2;
485 	if (i < 0)
486 		i = 0;
487 	for (j = 0; j < i; j++)
488 		(void) putchar(' ');
489 	(void) printf("faults");
490 	i = ndrives * 3 - 6 - i;
491 	for (j = 0; j < i; j++)
492 		(void) putchar(' ');
493 	(void) printf("               cpu\n");
494 	(void) printf(" r b w   avm   fre  re at  pi  po  fr  de  sr ");
495 	for (i = 0; i < dk_ndrive; i++)
496 		if (dr_select[i])
497 			(void) printf("%c%c ", dr_name[i][0],
498 			    dr_name[i][strlen(dr_name[i]) - 1]);
499 	(void) printf(" in  sy  cs us sy id\n");
500 	lines = 19;
501 }
502 
503 dotimes()
504 {
505 
506 	kread(X_REC, (char *)&s.rectime, sizeof s.rectime);
507 	kread(X_PGIN, (char *)&s.pgintime, sizeof s.pgintime);
508 	kread(X_SUM, (char *)&sum, sizeof sum);
509 	(void) printf("%u reclaims, %u total time (usec)\n",
510 	    sum.v_pgrec, s.rectime);
511 	(void) printf("average: %u usec / reclaim\n", s.rectime / sum.v_pgrec);
512 	(void) printf("\n");
513 	(void) printf("%u page ins, %u total time (msec)\n",
514 	    sum.v_pgin, s.pgintime / 10);
515 	(void) printf("average: %8.1f msec / page in\n",
516 	    s.pgintime / (sum.v_pgin * 10.0));
517 }
518 
519 pct(top, bot)
520 	long top, bot;
521 {
522 
523 	if (bot == 0)
524 		return (0);
525 	return ((top * 100) / bot);
526 }
527 
528 #define	PCT(top, bot) pct((long)(top), (long)(bot))
529 
530 #if defined(tahoe)
531 #include <machine/cpu.h>
532 #endif
533 
534 dosum()
535 {
536 	struct nchstats nchstats;
537 	struct xstats xstats;
538 	long nchtotal;
539 #if defined(tahoe)
540 	struct keystats keystats;
541 #endif
542 
543 	kread(X_SUM, (char *)&sum, sizeof sum);
544 	(void) printf("%9u swap ins\n", sum.v_swpin);
545 	(void) printf("%9u swap outs\n", sum.v_swpout);
546 	(void) printf("%9u pages swapped in\n", sum.v_pswpin / CLSIZE);
547 	(void) printf("%9u pages swapped out\n", sum.v_pswpout / CLSIZE);
548 	(void) printf("%9u total address trans. faults taken\n", sum.v_faults);
549 	(void) printf("%9u page ins\n", sum.v_pgin);
550 	(void) printf("%9u page outs\n", sum.v_pgout);
551 	(void) printf("%9u pages paged in\n", sum.v_pgpgin);
552 	(void) printf("%9u pages paged out\n", sum.v_pgpgout);
553 	(void) printf("%9u sequential process pages freed\n", sum.v_seqfree);
554 	(void) printf("%9u total reclaims (%d%% fast)\n", sum.v_pgrec,
555 	    PCT(sum.v_fastpgrec, sum.v_pgrec));
556 	(void) printf("%9u reclaims from free list\n", sum.v_pgfrec);
557 	(void) printf("%9u intransit blocking page faults\n", sum.v_intrans);
558 	(void) printf("%9u zero fill pages created\n", sum.v_nzfod / CLSIZE);
559 	(void) printf("%9u zero fill page faults\n", sum.v_zfod / CLSIZE);
560 	(void) printf("%9u executable fill pages created\n",
561 	    sum.v_nexfod / CLSIZE);
562 	(void) printf("%9u executable fill page faults\n",
563 	    sum.v_exfod / CLSIZE);
564 	(void) printf("%9u swap text pages found in free list\n",
565 	    sum.v_xsfrec);
566 	(void) printf("%9u inode text pages found in free list\n",
567 	    sum.v_xifrec);
568 	(void) printf("%9u file fill pages created\n", sum.v_nvrfod / CLSIZE);
569 	(void) printf("%9u file fill page faults\n", sum.v_vrfod / CLSIZE);
570 	(void) printf("%9u pages examined by the clock daemon\n", sum.v_scan);
571 	(void) printf("%9u revolutions of the clock hand\n", sum.v_rev);
572 	(void) printf("%9u pages freed by the clock daemon\n",
573 	    sum.v_dfree / CLSIZE);
574 	(void) printf("%9u cpu context switches\n", sum.v_swtch);
575 	(void) printf("%9u device interrupts\n", sum.v_intr);
576 	(void) printf("%9u software interrupts\n", sum.v_soft);
577 #ifdef vax
578 	(void) printf("%9u pseudo-dma dz interrupts\n", sum.v_pdma);
579 #endif
580 	(void) printf("%9u traps\n", sum.v_trap);
581 	(void) printf("%9u system calls\n", sum.v_syscall);
582 	kread(X_NCHSTATS, (char *)&nchstats, sizeof nchstats);
583 	nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
584 	    nchstats.ncs_badhits + nchstats.ncs_falsehits +
585 	    nchstats.ncs_miss + nchstats.ncs_long;
586 	(void) printf("%9ld total name lookups\n", nchtotal);
587 	(void) printf(
588 	    "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
589 	    "", PCT(nchstats.ncs_goodhits, nchtotal),
590 	    PCT(nchstats.ncs_neghits, nchtotal),
591 	    PCT(nchstats.ncs_pass2, nchtotal));
592 	(void) printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
593 	    PCT(nchstats.ncs_badhits, nchtotal),
594 	    PCT(nchstats.ncs_falsehits, nchtotal),
595 	    PCT(nchstats.ncs_long, nchtotal));
596 	kread(X_XSTATS, (char *)&xstats, sizeof xstats);
597 	(void) printf("%9lu total calls to xalloc (cache hits %d%%)\n",
598 	    xstats.alloc, PCT(xstats.alloc_cachehit, xstats.alloc));
599 	(void) printf("%9s sticky %lu flushed %lu unused %lu\n", "",
600 	    xstats.alloc_inuse, xstats.alloc_cacheflush, xstats.alloc_unused);
601 	(void) printf("%9lu total calls to xfree", xstats.free);
602 	(void) printf(" (sticky %lu cached %lu swapped %lu)\n",
603 	    xstats.free_inuse, xstats.free_cache, xstats.free_cacheswap);
604 #if defined(tahoe)
605 	kread(X_CKEYSTATS, (char *)&keystats, sizeof keystats);
606 	(void) printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
607 	    keystats.ks_allocs, "code cache keys allocated",
608 	    PCT(keystats.ks_allocfree, keystats.ks_allocs),
609 	    PCT(keystats.ks_norefs, keystats.ks_allocs),
610 	    PCT(keystats.ks_taken, keystats.ks_allocs),
611 	    PCT(keystats.ks_shared, keystats.ks_allocs));
612 	kread(X_DKEYSTATS, (char *)&keystats, sizeof keystats);
613 	(void) printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
614 	    keystats.ks_allocs, "data cache keys allocated",
615 	    PCT(keystats.ks_allocfree, keystats.ks_allocs),
616 	    PCT(keystats.ks_norefs, keystats.ks_allocs),
617 	    PCT(keystats.ks_taken, keystats.ks_allocs),
618 	    PCT(keystats.ks_shared, keystats.ks_allocs));
619 #endif
620 }
621 
622 doforkst()
623 {
624 
625 	kread(X_FORKSTAT, (char *)&forkstat, sizeof forkstat);
626 	(void) printf("%d forks, %d pages, average=%.2f\n",
627 		forkstat.cntfork, forkstat.sizfork,
628 		(float) forkstat.sizfork / forkstat.cntfork);
629 	(void) printf("%d vforks, %d pages, average=%.2f\n",
630 		forkstat.cntvfork, forkstat.sizvfork,
631 		(float)forkstat.sizvfork / forkstat.cntvfork);
632 }
633 
634 stats(dn)
635 {
636 
637 	if (dn >= dk_ndrive) {
638 		(void) printf("  0");
639 		return;
640 	}
641 	(void) printf("%3.0f", s.xfer[dn]/etime);
642 }
643 
644 double
645 stat1(row)
646 {
647 	double t;
648 	register i;
649 
650 	t = 0;
651 	for(i=0; i<CPUSTATES; i++)
652 		t += s.time[i];
653 	if(t == 0.)
654 		t = 1.;
655 	return(s.time[row]*100./t);
656 }
657 
658 dointr()
659 {
660 	register int nintr, inamlen;
661 	register long *intrcnt, inttotal, uptime = getuptime();
662 	register char *intrname;
663 
664 	nintr = nl[X_EINTRCNT].n_value - nl[X_INTRCNT].n_value;
665 	inamlen = nl[X_EINTRNAMES].n_value - nl[X_INTRNAMES].n_value;
666 	intrcnt = (long *)malloc((size_t)nintr);
667 	intrname = malloc((size_t)inamlen);
668 	if (intrcnt == NULL || intrname == NULL) {
669 		(void) fprintf(stderr, "vmstat: %s.\n", strerror(errno));
670 		exit(9);
671 	}
672 	kread(X_INTRCNT, (char *)intrcnt, (size_t)nintr);
673 	kread(X_INTRNAMES, intrname, (size_t)inamlen);
674 	(void) printf("interrupt      total      rate\n");
675 	inttotal = 0;
676 	nintr /= sizeof(long);
677 	while (--nintr >= 0) {
678 		if (*intrcnt)
679 			(void) printf("%-12s %8ld %8ld\n", intrname,
680 			    *intrcnt, *intrcnt / uptime);
681 		intrname += strlen(intrname) + 1;
682 		inttotal += *intrcnt++;
683 	}
684 	(void) printf("Total        %8ld %8ld\n", inttotal, inttotal / uptime);
685 }
686 
687 /*
688  * These names are defined in <sys/malloc.h>.
689  */
690 char *kmemnames[] = INITKMEMNAMES;
691 
692 domem()
693 {
694 	register struct kmembuckets *kp;
695 	register struct kmemstats *ks;
696 	register int i;
697 	struct kmemstats kmemstats[M_LAST];
698 	struct kmembuckets buckets[MINBUCKET + 16];
699 
700 	kread(X_KMEMBUCKETS, (char *)buckets, sizeof buckets);
701 	(void) printf("Memory statistics by bucket size\n");
702 	(void) printf(
703 	    "    Size   In Use   Free   Requests  HighWater  Couldfree\n");
704 	for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) {
705 		if (kp->kb_calls == 0)
706 			continue;
707 		(void) printf("%8d%9ld%7ld%11ld%8ld%11ld\n", 1 << i,
708 			kp->kb_total - kp->kb_totalfree,
709 			kp->kb_totalfree, kp->kb_calls,
710 			kp->kb_highwat, kp->kb_couldfree);
711 
712 	}
713 	kread(X_KMEMSTAT, (char *)kmemstats, sizeof kmemstats);
714 	(void) printf("Memory statistics by type\n");
715 	(void) printf("\
716      Type   In Use  MemUse   HighUse  Limit  Requests TypeLimit KernLimit\n");
717 	for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
718 		if (ks->ks_calls == 0)
719 			continue;
720 		(void) printf("%10s%7ld%8ldK%9ldK%6ldK%9ld%7u%10u\n",
721 			kmemnames[i] ? kmemnames[i] : "undefined",
722 			ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
723 			(ks->ks_maxused + 1023) / 1024,
724 			(ks->ks_limit + 1023) / 1024, ks->ks_calls,
725 			ks->ks_limblocks, ks->ks_mapblocks);
726 	}
727 }
728 
729 /*
730  * Read the drive names out of kmem.
731  */
732 #ifdef vax
733 #include <uba/ubavar.h>
734 #include <mba/mbavar.h>
735 
736 read_names()
737 {
738 	register char *p;
739 	unsigned long mp, up;
740 	struct mba_device mdev;
741 	struct mba_driver mdrv;
742 	struct uba_device udev;
743 	struct uba_driver udrv;
744 	char name[10];
745 	static char buf[BUFSIZ];
746 
747 	mp = nl[X_MBDINIT].n_value;
748 	up = nl[X_UBDINIT].n_value;
749 	if (mp == 0 && up == 0) {
750 		(void) fprintf(stderr,
751 		    "vmstat: disk init info not in namelist\n");
752 		exit(1);
753 	}
754 	p = buf;
755 	if (mp) for (;; mp += sizeof mdev) {
756 		(void) kvm_read((u_long)mp, (char *)&mdev, sizeof mdev);
757 		if (mdev.mi_driver == 0)
758 			break;
759 		if (mdev.mi_dk < 0 || mdev.mi_alive == 0)
760 			continue;
761 		(void) kvm_read((u_long)mdev.mi_driver,
762 		    (char *)&mdrv, sizeof mdrv);
763 		(void) kvm_read((u_long)mdrv.md_dname, name, sizeof name);
764 		dr_name[mdev.mi_dk] = p;
765 		p += sprintf(p, "%s%d", name, mdev.mi_unit);
766 	}
767 	if (up) for (;; up += sizeof udev) {
768 		(void) kvm_read(up, (char *)&udev, sizeof udev);
769 		if (udev.ui_driver == 0)
770 			break;
771 		if (udev.ui_dk < 0 || udev.ui_alive == 0)
772 			continue;
773 		(void) kvm_read((u_long)udev.ui_driver,
774 		    (char *)&udrv, sizeof udrv);
775 		(void) kvm_read((u_long)udrv.ud_dname, name, sizeof name);
776 		dr_name[udev.ui_dk] = p;
777 		p += sprintf(p, "%s%d", name, udev.ui_unit);
778 	}
779 }
780 #endif
781 
782 #ifdef tahoe
783 #include <tahoe/vba/vbavar.h>
784 
785 /*
786  * Read the drive names out of kmem.
787  */
788 read_names()
789 {
790 	register char *p;
791 	struct vba_device udev, *up;
792 	struct vba_driver udrv;
793 	char name[10];
794 	static char buf[BUFSIZ];
795 
796 	up = (struct vba_device *) nl[X_VBDINIT].n_value;
797 	if (up == 0) {
798 		(void) fprintf(stderr,
799 		    "vmstat: disk init info not in namelist\n");
800 		exit(1);
801 	}
802 	p = buf;
803 	for (;; up += sizeof udev) {
804 		(void) kvm_read(up, (char *)&udev, sizeof udev);
805 		if (udev.ui_driver == 0)
806 			break;
807 		if (udev.ui_dk < 0 || udev.ui_alive == 0)
808 			continue;
809 		(void) kvm_read((u_long)udev.ui_driver,
810 		    (char *)&udrv, sizeof udrv);
811 		(void) kvm_read((u_long)udrv.ud_dname, name, sizeof name);
812 		dr_name[udev.ui_dk] = p;
813 		p += sprintf(p, "%s%d", name, udev.ui_unit);
814 	}
815 }
816 #endif
817 
818 #ifdef hp300
819 #include <hp300/dev/device.h>
820 
821 read_names()
822 {
823 	register char *p;
824 	register u_long hp;
825 	static char buf[BUFSIZ];
826 	struct hp_device hdev;
827 	struct driver hdrv;
828 	char name[10];
829 
830 	hp = nl[X_HPDINIT].n_value;
831 	if (hp == 0) {
832 		(void) fprintf(stderr,
833 		    "vmstat: disk init info not in namelist\n");
834 		exit(1);
835 	}
836 	p = buf;
837 	for (;; hp += sizeof hdev) {
838 		(void) kvm_read(hp, (char *)&hdev, sizeof hdev);
839 		if (hdev.hp_driver == 0)
840 			break;
841 		if (hdev.hp_dk < 0 || hdev.hp_alive == 0)
842 			continue;
843 		(void) kvm_read((u_long)hdev.hp_driver,
844 		    (char *)&hdrv, sizeof hdrv);
845 		(void) kvm_read((u_long)hdrv.d_name, name, sizeof name);
846 		dr_name[hdev.hp_dk] = p;
847 		p += sprintf(p, "%s%d", name, hdev.hp_unit);
848 	}
849 }
850 #endif
851