xref: /original-bsd/usr.bin/vmstat/vmstat.c (revision 2301fdfb)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)vmstat.c	5.9 (Berkeley) 02/27/88";
15 #endif not lint
16 
17 #include <stdio.h>
18 #include <ctype.h>
19 #include <nlist.h>
20 
21 #include <sys/param.h>
22 #include <sys/file.h>
23 #include <sys/vm.h>
24 #include <sys/dkstat.h>
25 #include <sys/buf.h>
26 #include <sys/dir.h>
27 #include <sys/inode.h>
28 #include <sys/namei.h>
29 #include <sys/text.h>
30 #include <sys/malloc.h>
31 
32 struct nlist nl[] = {
33 #define	X_CPTIME	0
34 	{ "_cp_time" },
35 #define	X_RATE		1
36 	{ "_rate" },
37 #define X_TOTAL		2
38 	{ "_total" },
39 #define	X_DEFICIT	3
40 	{ "_deficit" },
41 #define	X_FORKSTAT	4
42 	{ "_forkstat" },
43 #define X_SUM		5
44 	{ "_sum" },
45 #define	X_FIRSTFREE	6
46 	{ "_firstfree" },
47 #define	X_MAXFREE	7
48 	{ "_maxfree" },
49 #define	X_BOOTTIME	8
50 	{ "_boottime" },
51 #define	X_DKXFER	9
52 	{ "_dk_xfer" },
53 #define X_REC		10
54 	{ "_rectime" },
55 #define X_PGIN		11
56 	{ "_pgintime" },
57 #define X_HZ		12
58 	{ "_hz" },
59 #define X_PHZ		13
60 	{ "_phz" },
61 #define X_NCHSTATS	14
62 	{ "_nchstats" },
63 #define	X_INTRNAMES	15
64 	{ "_intrnames" },
65 #define	X_EINTRNAMES	16
66 	{ "_eintrnames" },
67 #define	X_INTRCNT	17
68 	{ "_intrcnt" },
69 #define	X_EINTRCNT	18
70 	{ "_eintrcnt" },
71 #define	X_DK_NDRIVE	19
72 	{ "_dk_ndrive" },
73 #define	X_XSTATS	20
74 	{ "_xstats" },
75 #define	X_KMEMSTAT	21
76 	{ "_kmemstats" },
77 #define	X_KMEMBUCKETS	22
78 	{ "_bucket" },
79 #ifdef vax
80 #define X_MBDINIT	(X_XSTATS+1)
81 	{ "_mbdinit" },
82 #define X_UBDINIT	(X_XSTATS+2)
83 	{ "_ubdinit" },
84 #endif
85 #ifdef tahoe
86 #define	X_VBDINIT	(X_XSTATS+1)
87 	{ "_vbdinit" },
88 #define	X_CKEYSTATS	(X_XSTATS+2)
89 	{ "_ckeystats" },
90 #define	X_DKEYSTATS	(X_XSTATS+3)
91 	{ "_dkeystats" },
92 #endif
93 	{ "" },
94 };
95 
96 char	**dr_name;
97 int	*dr_select;
98 int	dk_ndrive;
99 int	ndrives = 0;
100 #ifdef vax
101 char	*defdrives[] = { "hp0", "hp1", "hp2",  0 };
102 #else
103 char	*defdrives[] = { 0 };
104 #endif
105 double	stat1();
106 int	firstfree, maxfree;
107 int	hz;
108 int	phz;
109 int	HZ;
110 
111 struct {
112 	int	busy;
113 	long	time[CPUSTATES];
114 	long	*xfer;
115 	struct	vmmeter Rate;
116 	struct	vmtotal	Total;
117 	struct	vmmeter Sum;
118 	struct	forkstat Forkstat;
119 	unsigned rectime;
120 	unsigned pgintime;
121 } s, s1, z;
122 #define	rate		s.Rate
123 #define	total		s.Total
124 #define	sum		s.Sum
125 #define	forkstat	s.Forkstat
126 
127 struct	vmmeter osum;
128 int	deficit;
129 double	etime;
130 int 	mf;
131 time_t	now, boottime;
132 int	printhdr();
133 int	lines = 1;
134 
135 #define	INTS(x)	((x) - (hz + phz))
136 
137 main(argc, argv)
138 	int argc;
139 	char **argv;
140 {
141 	extern char *ctime();
142 	register i;
143 	int iter, nintv, iflag = 0;
144 	long t;
145 	char *arg, **cp, buf[BUFSIZ];
146 
147 	nlist("/vmunix", nl);
148 	if(nl[0].n_type == 0) {
149 		fprintf(stderr, "no /vmunix namelist\n");
150 		exit(1);
151 	}
152 	mf = open("/dev/kmem", 0);
153 	if(mf < 0) {
154 		fprintf(stderr, "cannot open /dev/kmem\n");
155 		exit(1);
156 	}
157 	iter = 0;
158 	argc--, argv++;
159 	while (argc>0 && argv[0][0]=='-') {
160 		char *cp = *argv++;
161 		argc--;
162 		while (*++cp) switch (*cp) {
163 
164 		case 't':
165 			dotimes();
166 			exit(0);
167 
168 		case 'z':
169 			close(mf);
170 			mf = open("/dev/kmem", 2);
171 			lseek(mf, (long)nl[X_SUM].n_value, L_SET);
172 			write(mf, &z.Sum, sizeof z.Sum);
173 			exit(0);
174 
175 		case 'f':
176 			doforkst();
177 			exit(0);
178 
179 		case 'm':
180 			domem();
181 			exit(0);
182 
183 		case 's':
184 			dosum();
185 			exit(0);
186 
187 		case 'i':
188 			iflag++;
189 			break;
190 
191 		default:
192 			fprintf(stderr,
193 			    "usage: vmstat [ -fsim ] [ interval ] [ count]\n");
194 			exit(1);
195 		}
196 	}
197 	lseek(mf, (long)nl[X_FIRSTFREE].n_value, L_SET);
198 	read(mf, &firstfree, sizeof firstfree);
199 	lseek(mf, (long)nl[X_MAXFREE].n_value, L_SET);
200 	read(mf, &maxfree, sizeof maxfree);
201 	lseek(mf, (long)nl[X_BOOTTIME].n_value, L_SET);
202 	read(mf, &boottime, sizeof boottime);
203 	lseek(mf, (long)nl[X_HZ].n_value, L_SET);
204 	read(mf, &hz, sizeof hz);
205 	if (nl[X_PHZ].n_value != 0) {
206 		lseek(mf, (long)nl[X_PHZ].n_value, L_SET);
207 		read(mf, &phz, sizeof phz);
208 	}
209 	HZ = phz ? phz : hz;
210 	if (nl[X_DK_NDRIVE].n_value == 0) {
211 		fprintf(stderr, "dk_ndrive undefined in system\n");
212 		exit(1);
213 	}
214 	lseek(mf, nl[X_DK_NDRIVE].n_value, L_SET);
215 	read(mf, &dk_ndrive, sizeof (dk_ndrive));
216 	if (dk_ndrive <= 0) {
217 		fprintf(stderr, "dk_ndrive %d\n", dk_ndrive);
218 		exit(1);
219 	}
220 	dr_select = (int *)calloc(dk_ndrive, sizeof (int));
221 	dr_name = (char **)calloc(dk_ndrive, sizeof (char *));
222 #define	allocate(e, t) \
223     s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
224     s1./**/e = (t *)calloc(dk_ndrive, sizeof (t));
225 	allocate(xfer, long);
226 	for (arg = buf, i = 0; i < dk_ndrive; i++) {
227 		dr_name[i] = arg;
228 		sprintf(dr_name[i], "dk%d", i);
229 		arg += strlen(dr_name[i]) + 1;
230 	}
231 	read_names();
232 	time(&now);
233 	nintv = now - boottime;
234 	if (nintv <= 0 || nintv > 60*60*24*365*10) {
235 		fprintf(stderr,
236 		    "Time makes no sense... namelist must be wrong.\n");
237 		exit(1);
238 	}
239 	if (iflag) {
240 		dointr(nintv);
241 		exit(0);
242 	}
243 	/*
244 	 * Choose drives to be displayed.  Priority
245 	 * goes to (in order) drives supplied as arguments,
246 	 * default drives.  If everything isn't filled
247 	 * in and there are drives not taken care of,
248 	 * display the first few that fit.
249 	 */
250 	ndrives = 0;
251 	while (argc > 0 && !isdigit(argv[0][0])) {
252 		for (i = 0; i < dk_ndrive; i++) {
253 			if (strcmp(dr_name[i], argv[0]))
254 				continue;
255 			dr_select[i] = 1;
256 			ndrives++;
257 		}
258 		argc--, argv++;
259 	}
260 	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
261 		if (dr_select[i])
262 			continue;
263 		for (cp = defdrives; *cp; cp++)
264 			if (strcmp(dr_name[i], *cp) == 0) {
265 				dr_select[i] = 1;
266 				ndrives++;
267 				break;
268 			}
269 	}
270 	for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
271 		if (dr_select[i])
272 			continue;
273 		dr_select[i] = 1;
274 		ndrives++;
275 	}
276 	if (argc > 1)
277 		iter = atoi(argv[1]);
278 	signal(SIGCONT, printhdr);
279 loop:
280 	if (--lines == 0)
281 		printhdr();
282 	lseek(mf, (long)nl[X_CPTIME].n_value, L_SET);
283  	read(mf, s.time, sizeof s.time);
284 	lseek(mf, (long)nl[X_DKXFER].n_value, L_SET);
285 	read(mf, s.xfer, dk_ndrive * sizeof (long));
286 	if (nintv != 1)
287 		lseek(mf, (long)nl[X_SUM].n_value, L_SET);
288 	else
289 		lseek(mf, (long)nl[X_RATE].n_value, L_SET);
290 	read(mf, &rate, sizeof rate);
291 	lseek(mf, (long)nl[X_TOTAL].n_value, L_SET);
292 	read(mf, &total, sizeof total);
293 	osum = sum;
294 	lseek(mf, (long)nl[X_SUM].n_value, L_SET);
295 	read(mf, &sum, sizeof sum);
296 	lseek(mf, (long)nl[X_DEFICIT].n_value, L_SET);
297 	read(mf, &deficit, sizeof deficit);
298 	etime = 0;
299 	for (i=0; i < dk_ndrive; i++) {
300 		t = s.xfer[i];
301 		s.xfer[i] -= s1.xfer[i];
302 		s1.xfer[i] = t;
303 	}
304 	for (i=0; i < CPUSTATES; i++) {
305 		t = s.time[i];
306 		s.time[i] -= s1.time[i];
307 		s1.time[i] = t;
308 		etime += s.time[i];
309 	}
310 	if(etime == 0.)
311 		etime = 1.;
312 	printf("%2d%2d%2d", total.t_rq, total.t_dw+total.t_pw, total.t_sw);
313 #define pgtok(a) ((a)*NBPG/1024)
314 	printf("%6d%6d", pgtok(total.t_avm), pgtok(total.t_free));
315 	printf("%4d%3d", (rate.v_pgrec - (rate.v_xsfrec+rate.v_xifrec))/nintv,
316 	    (rate.v_xsfrec+rate.v_xifrec)/nintv);
317 	printf("%4d", pgtok(rate.v_pgpgin)/nintv);
318 	printf("%4d%4d%4d%4d", pgtok(rate.v_pgpgout)/nintv,
319 	    pgtok(rate.v_dfree)/nintv, pgtok(deficit), rate.v_scan/nintv);
320 	etime /= (float)HZ;
321 	for (i = 0; i < dk_ndrive; i++)
322 		if (dr_select[i])
323 			stats(i);
324 	printf("%4d%4d%4d", INTS(rate.v_intr/nintv), rate.v_syscall/nintv,
325 	    rate.v_swtch/nintv);
326 	for(i=0; i<CPUSTATES; i++) {
327 		float f = stat1(i);
328 		if (i == 0) {		/* US+NI */
329 			i++;
330 			f += stat1(i);
331 		}
332 		printf("%3.0f", f);
333 	}
334 	printf("\n");
335 	fflush(stdout);
336 	nintv = 1;
337 	if (--iter &&argc > 0) {
338 		sleep(atoi(argv[0]));
339 		goto loop;
340 	}
341 }
342 
343 printhdr()
344 {
345 	register int i, j;
346 
347 	printf(" procs     memory              page           ");
348 	i = (ndrives * 3 - 6) / 2;
349 	if (i < 0)
350 		i = 0;
351 	for (j = 0; j < i; j++)
352 		putchar(' ');
353 	printf("faults");
354 	i = ndrives * 3 - 6 - i;
355 	for (j = 0; j < i; j++)
356 		putchar(' ');
357 	printf("               cpu\n");
358 	printf(" r b w   avm   fre  re at  pi  po  fr  de  sr ");
359 	for (i = 0; i < dk_ndrive; i++)
360 		if (dr_select[i])
361 			printf("%c%c ", dr_name[i][0], dr_name[i][2]);
362 	printf(" in  sy  cs us sy id\n");
363 	lines = 19;
364 }
365 
366 dotimes()
367 {
368 
369 	lseek(mf, (long)nl[X_REC].n_value, L_SET);
370 	read(mf, &s.rectime, sizeof s.rectime);
371 	lseek(mf, (long)nl[X_PGIN].n_value, L_SET);
372 	read(mf, &s.pgintime, sizeof s.pgintime);
373 	lseek(mf, (long)nl[X_SUM].n_value, L_SET);
374 	read(mf, &sum, sizeof sum);
375 	printf("%d reclaims, %d total time (usec)\n", sum.v_pgrec, s.rectime);
376 	printf("average: %d usec / reclaim\n", s.rectime/sum.v_pgrec);
377 	printf("\n");
378 	printf("%d page ins, %d total time (msec)\n",sum.v_pgin, s.pgintime/10);
379 	printf("average: %8.1f msec / page in\n", s.pgintime/(sum.v_pgin*10.0));
380 }
381 
382 #if defined(tahoe)
383 #include <tahoe/cpu.h>
384 #endif
385 
386 dosum()
387 {
388 	struct nchstats nchstats;
389 	struct xstats xstats;
390 	long nchtotal;
391 #if defined(tahoe)
392 	struct keystats keystats;
393 #endif
394 
395 	lseek(mf, (long)nl[X_SUM].n_value, L_SET);
396 	read(mf, &sum, sizeof sum);
397 	printf("%9d swap ins\n", sum.v_swpin);
398 	printf("%9d swap outs\n", sum.v_swpout);
399 	printf("%9d pages swapped in\n", sum.v_pswpin / CLSIZE);
400 	printf("%9d pages swapped out\n", sum.v_pswpout / CLSIZE);
401 	printf("%9d total address trans. faults taken\n", sum.v_faults);
402 	printf("%9d page ins\n", sum.v_pgin);
403 	printf("%9d page outs\n", sum.v_pgout);
404 	printf("%9d pages paged in\n", sum.v_pgpgin);
405 	printf("%9d pages paged out\n", sum.v_pgpgout);
406 	printf("%9d sequential process pages freed\n", sum.v_seqfree);
407 	printf("%9d total reclaims (%d%% fast)\n", sum.v_pgrec,
408 	    pct(sum.v_fastpgrec, sum.v_pgrec));
409 	printf("%9d reclaims from free list\n", sum.v_pgfrec);
410 	printf("%9d intransit blocking page faults\n", sum.v_intrans);
411 	printf("%9d zero fill pages created\n", sum.v_nzfod / CLSIZE);
412 	printf("%9d zero fill page faults\n", sum.v_zfod / CLSIZE);
413 	printf("%9d executable fill pages created\n", sum.v_nexfod / CLSIZE);
414 	printf("%9d executable fill page faults\n", sum.v_exfod / CLSIZE);
415 	printf("%9d swap text pages found in free list\n", sum.v_xsfrec);
416 	printf("%9d inode text pages found in free list\n", sum.v_xifrec);
417 	printf("%9d file fill pages created\n", sum.v_nvrfod / CLSIZE);
418 	printf("%9d file fill page faults\n", sum.v_vrfod / CLSIZE);
419 	printf("%9d pages examined by the clock daemon\n", sum.v_scan);
420 	printf("%9d revolutions of the clock hand\n", sum.v_rev);
421 	printf("%9d pages freed by the clock daemon\n", sum.v_dfree / CLSIZE);
422 	printf("%9d cpu context switches\n", sum.v_swtch);
423 	printf("%9d device interrupts\n", sum.v_intr);
424 	printf("%9d software interrupts\n", sum.v_soft);
425 #ifdef vax
426 	printf("%9d pseudo-dma dz interrupts\n", sum.v_pdma);
427 #endif
428 	printf("%9d traps\n", sum.v_trap);
429 	printf("%9d system calls\n", sum.v_syscall);
430 	lseek(mf, (long)nl[X_NCHSTATS].n_value, 0);
431 	read(mf, &nchstats, sizeof nchstats);
432 	nchtotal = nchstats.ncs_goodhits + nchstats.ncs_badhits +
433 	    nchstats.ncs_falsehits + nchstats.ncs_miss + nchstats.ncs_long;
434 	printf("%9d total name lookups", nchtotal);
435 	printf(" (cache hits %d%% system %d%% per-process)\n",
436 	    pct(nchstats.ncs_goodhits, nchtotal),
437 	    pct(nchstats.ncs_pass2, nchtotal));
438 	printf("%9s badhits %d, falsehits %d, toolong %d\n", "",
439 	    nchstats.ncs_badhits, nchstats.ncs_falsehits, nchstats.ncs_long);
440 	lseek(mf, (long)nl[X_XSTATS].n_value, 0);
441 	read(mf, &xstats, sizeof xstats);
442 	printf("%9d total calls to xalloc (cache hits %d%%)\n",
443 	    xstats.alloc, pct(xstats.alloc_cachehit, xstats.alloc));
444 	printf("%9s sticky %d flushed %d unused %d\n", "",
445 	    xstats.alloc_inuse, xstats.alloc_cacheflush, xstats.alloc_unused);
446 	printf("%9d total calls to xfree", xstats.free);
447 	printf(" (sticky %d cached %d swapped %d)\n",
448 	    xstats.free_inuse, xstats.free_cache, xstats.free_cacheswap);
449 #if defined(tahoe)
450 	lseek(mf, (long)nl[X_CKEYSTATS].n_value, 0);
451 	read(mf, &keystats, sizeof keystats);
452 	printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
453 	    keystats.ks_allocs, "code cache keys allocated",
454 	    pct(keystats.ks_allocfree, keystats.ks_allocs),
455 	    pct(keystats.ks_norefs, keystats.ks_allocs),
456 	    pct(keystats.ks_taken, keystats.ks_allocs),
457 	    pct(keystats.ks_shared, keystats.ks_allocs));
458 	lseek(mf, (long)nl[X_DKEYSTATS].n_value, 0);
459 	read(mf, &keystats, sizeof keystats);
460 	printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
461 	    keystats.ks_allocs, "data cache keys allocated",
462 	    pct(keystats.ks_allocfree, keystats.ks_allocs),
463 	    pct(keystats.ks_norefs, keystats.ks_allocs),
464 	    pct(keystats.ks_taken, keystats.ks_allocs),
465 	    pct(keystats.ks_shared, keystats.ks_allocs));
466 #endif
467 }
468 
469 doforkst()
470 {
471 
472 	lseek(mf, (long)nl[X_FORKSTAT].n_value, L_SET);
473 	read(mf, &forkstat, sizeof forkstat);
474 	printf("%d forks, %d pages, average=%.2f\n",
475 		forkstat.cntfork, forkstat.sizfork,
476 		(float) forkstat.sizfork / forkstat.cntfork);
477 	printf("%d vforks, %d pages, average=%.2f\n",
478 		forkstat.cntvfork, forkstat.sizvfork,
479 		(float)forkstat.sizvfork / forkstat.cntvfork);
480 }
481 
482 stats(dn)
483 {
484 
485 	if (dn >= dk_ndrive) {
486 		printf("  0");
487 		return;
488 	}
489 	printf("%3.0f", s.xfer[dn]/etime);
490 }
491 
492 double
493 stat1(row)
494 {
495 	double t;
496 	register i;
497 
498 	t = 0;
499 	for(i=0; i<CPUSTATES; i++)
500 		t += s.time[i];
501 	if(t == 0.)
502 		t = 1.;
503 	return(s.time[row]*100./t);
504 }
505 
506 pct(top, bot)
507 {
508 
509 	if (bot == 0)
510 		return (0);
511 	return ((top * 100) / bot);
512 }
513 
514 dointr(nintv)
515 {
516 	int nintr, inttotal;
517 	long *intrcnt;
518 	char *intrname, *malloc();
519 
520 	nintr = (nl[X_EINTRCNT].n_value - nl[X_INTRCNT].n_value) / sizeof(long);
521 	intrcnt = (long *) malloc(nl[X_EINTRCNT].n_value -
522 		nl[X_INTRCNT].n_value);
523 	intrname = malloc(nl[X_EINTRNAMES].n_value - nl[X_INTRNAMES].n_value);
524 	if (intrcnt == NULL || intrname == NULL) {
525 		fprintf(stderr, "vmstat: out of memory\n");
526 		exit(9);
527 	}
528 	lseek(mf, (long)nl[X_INTRCNT].n_value, L_SET);
529 	read(mf, intrcnt, nintr * sizeof (long));
530 	lseek(mf, (long)nl[X_INTRNAMES].n_value, L_SET);
531 	read(mf, intrname, nl[X_EINTRNAMES].n_value - nl[X_INTRNAMES].n_value);
532 	printf("interrupt      total      rate\n");
533 	inttotal = 0;
534 	while (nintr--) {
535 		if (*intrcnt)
536 			printf("%-12s %8ld %8ld\n", intrname,
537 			    *intrcnt, *intrcnt / nintv);
538 		intrname += strlen(intrname) + 1;
539 		inttotal += *intrcnt++;
540 	}
541 	printf("Total        %8ld %8ld\n", inttotal, inttotal / nintv);
542 }
543 
544 /*
545  * These names must be kept in sync with
546  * the types defined in <sys/malloc.h>.
547  */
548 char *kmemnames[] = {
549 	"free",		/* M_FREE */
550 	"mbuf",		/* M_MBUF */
551 	"devbuf",	/* M_DEVBUF */
552 	"socket",	/* M_SOCKET */
553 	"pcb",		/* M_PCB */
554 	"routetbl",	/* M_RTABLE */
555 	"hosttbl",	/* M_HTABLE */
556 	"fragtbl",	/* M_FTABLE */
557 	"zombie",	/* M_ZOMBIE */
558 	"ifaddr",	/* M_IFADDR */
559 	"soopts",	/* M_SOOPTS */
560 	"soname",	/* M_SONAME */
561 	"namei",	/* M_NAMEI */
562 	"gprof",	/* M_GPROF */
563 	"ioctlops",	/* M_IOCTLOPS */
564 	"superblk",	/* M_SUPERBLK */
565 	"cred",		/* M_CRED */
566 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
567 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
568 	"temp",		/* M_TEMP */
569 };
570 
571 domem()
572 {
573 	struct kmemstats kmemstats[M_LAST];
574 	struct kmembuckets buckets[MINBUCKET + 16];
575 	register struct kmembuckets *kp;
576 	register struct kmemstats *ks;
577 	int i;
578 
579 	lseek(mf, (long)nl[X_KMEMBUCKETS].n_value, L_SET);
580 	read(mf, buckets, sizeof buckets);
581 	printf("Memory statistics by bucket size\n");
582 	printf("    Size   In Use   Free   Requests  HighWater  Couldfree\n");
583 	for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) {
584 		if (kp->kb_calls == 0)
585 			continue;
586 		printf("%8d%9d%7d%11d%8d%11d\n", 1 << i,
587 			kp->kb_total - kp->kb_totalfree,
588 			kp->kb_totalfree, kp->kb_calls,
589 			kp->kb_highwat, kp->kb_couldfree);
590 
591 	}
592 	lseek(mf, (long)nl[X_KMEMSTAT].n_value, L_SET);
593 	read(mf, kmemstats, sizeof kmemstats);
594 	printf("Memory statistics by type\n");
595 	printf("     Type   In Use  MemUse   HighUse  Limit  Requests %s\n",
596 		"TypeLimit KernLimit");
597 	for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
598 		if (ks->ks_calls == 0)
599 			continue;
600 		printf("%10s%7d%8dK%9dK%6dK%9d%7d%10d\n",
601 			kmemnames[i] ? kmemnames[i] : "undefined",
602 			ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
603 			(ks->ks_maxused + 1023) / 1024,
604 			(ks->ks_limit + 1023) / 1024, ks->ks_calls,
605 			ks->ks_limblocks, ks->ks_mapblocks);
606 	}
607 }
608 
609 #define steal(where, var) \
610 	lseek(mf, where, L_SET); read(mf, &var, sizeof var);
611 /*
612  * Read the drive names out of kmem.
613  */
614 #ifdef vax
615 #include <vaxuba/ubavar.h>
616 #include <vaxmba/mbavar.h>
617 
618 read_names()
619 {
620 	struct mba_device mdev;
621 	register struct mba_device *mp;
622 	struct mba_driver mdrv;
623 	short two_char;
624 	char *cp = (char *) &two_char;
625 	struct uba_device udev, *up;
626 	struct uba_driver udrv;
627 
628 	mp = (struct mba_device *) nl[X_MBDINIT].n_value;
629 	up = (struct uba_device *) nl[X_UBDINIT].n_value;
630 	if (up == 0) {
631 		fprintf(stderr, "vmstat: Disk init info not in namelist\n");
632 		exit(1);
633 	}
634 	if (mp) for (;;) {
635 		steal(mp++, mdev);
636 		if (mdev.mi_driver == 0)
637 			break;
638 		if (mdev.mi_dk < 0 || mdev.mi_alive == 0)
639 			continue;
640 		steal(mdev.mi_driver, mdrv);
641 		steal(mdrv.md_dname, two_char);
642 		sprintf(dr_name[mdev.mi_dk], "%c%c%d",
643 		    cp[0], cp[1], mdev.mi_unit);
644 	}
645 	for (;;) {
646 		steal(up++, udev);
647 		if (udev.ui_driver == 0)
648 			break;
649 		if (udev.ui_dk < 0 || udev.ui_alive == 0)
650 			continue;
651 		steal(udev.ui_driver, udrv);
652 		steal(udrv.ud_dname, two_char);
653 		sprintf(dr_name[udev.ui_dk], "%c%c%d",
654 		    cp[0], cp[1], udev.ui_unit);
655 	}
656 }
657 #endif
658 
659 #ifdef tahoe
660 #include <tahoevba/vbavar.h>
661 
662 /*
663  * Read the drive names out of kmem.
664  */
665 read_names()
666 {
667 	struct vba_device udev, *up;
668 	struct vba_driver udrv;
669 	short two_char;
670 	char *cp = (char *)&two_char;
671 
672 	up = (struct vba_device *) nl[X_VBDINIT].n_value;
673 	if (up == 0) {
674 		fprintf(stderr, "vmstat: Disk init info not in namelist\n");
675 		exit(1);
676 	}
677 	for (;;) {
678 		steal(up++, udev);
679 		if (udev.ui_driver == 0)
680 			break;
681 		if (udev.ui_dk < 0 || udev.ui_alive == 0)
682 			continue;
683 		steal(udev.ui_driver, udrv);
684 		steal(udrv.ud_dname, two_char);
685 		sprintf(dr_name[udev.ui_dk], "%c%c%d",
686 		     cp[0], cp[1], udev.ui_unit);
687 	}
688 }
689 #endif
690