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