GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vmstat/vmstat.c Lines: 0 518 0.0 %
Date: 2016-12-06 Branches: 0 312 0.0 %

Line Branch Exec Source
1
/*	$NetBSD: vmstat.c,v 1.29.4.1 1996/06/05 00:21:05 cgd Exp $	*/
2
/*	$OpenBSD: vmstat.c,v 1.139 2015/12/24 03:25:08 mmcc Exp $	*/
3
4
/*
5
 * Copyright (c) 1980, 1986, 1991, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/param.h>	/* MAXCOMLEN */
34
#include <sys/time.h>
35
#include <sys/proc.h>
36
#include <sys/namei.h>
37
#include <sys/malloc.h>
38
#include <sys/fcntl.h>
39
#include <sys/ioctl.h>
40
#include <sys/sysctl.h>
41
#include <sys/device.h>
42
#include <sys/pool.h>
43
#include <sys/sched.h>
44
#include <sys/vmmeter.h>
45
46
#include <time.h>
47
#include <nlist.h>
48
#include <kvm.h>
49
#include <err.h>
50
#include <errno.h>
51
#include <unistd.h>
52
#include <signal.h>
53
#include <stdio.h>
54
#include <ctype.h>
55
#include <stdlib.h>
56
#include <string.h>
57
#include <paths.h>
58
#include <limits.h>
59
#include "dkstats.h"
60
61
struct nlist namelist[] = {
62
#define X_UVMEXP	0		/* sysctl */
63
	{ "_uvmexp" },
64
#define	X_TIME_UPTIME	1
65
	{ "_time_uptime" },
66
#define X_NCHSTATS	2		/* sysctl */
67
	{ "_nchstats" },
68
#define	X_KMEMSTAT	3		/* sysctl */
69
	{ "_kmemstats" },
70
#define	X_KMEMBUCKETS	4		/* sysctl */
71
	{ "_bucket" },
72
#define	X_FORKSTAT	5		/* sysctl */
73
	{ "_forkstat" },
74
#define X_NSELCOLL	6		/* sysctl */
75
	{ "_nselcoll" },
76
#define X_POOLHEAD	7		/* sysctl */
77
	{ "_pool_head" },
78
#define	X_NAPTIME	8
79
	{ "_naptime" },
80
	{ "" },
81
};
82
83
/* Objects defined in dkstats.c */
84
extern struct _disk	cur, last;
85
extern char	**dr_name;
86
extern int	*dk_select, dk_ndrive;
87
88
struct	uvmexp uvmexp, ouvmexp;
89
int		ndrives;
90
91
int	winlines = 20;
92
93
kvm_t *kd;
94
95
#define	FORKSTAT	0x01
96
#define	INTRSTAT	0x02
97
#define	MEMSTAT		0x04
98
#define	SUMSTAT		0x08
99
#define	TIMESTAT	0x10
100
#define	VMSTAT		0x20
101
102
void	cpustats(void);
103
time_t	getuptime(void);
104
void	dkstats(void);
105
void	dointr(void);
106
void	domem(void);
107
void	dopool(void);
108
void	dosum(void);
109
void	dovmstat(u_int, int);
110
void	kread(int, void *, size_t);
111
void	usage(void);
112
void	dotimes(void);
113
void	doforkst(void);
114
void	needhdr(int);
115
int	pct(int64_t, int64_t);
116
void	printhdr(void);
117
118
char	**choosedrives(char **);
119
120
/* Namelist and memory file names. */
121
char	*nlistf, *memf;
122
123
extern char *__progname;
124
125
int verbose = 0;
126
int zflag = 0;
127
128
int
129
main(int argc, char *argv[])
130
{
131
	char errbuf[_POSIX2_LINE_MAX];
132
	int c, todo = 0, reps = 0;
133
	const char *errstr;
134
	u_int interval = 0;
135
136
	while ((c = getopt(argc, argv, "c:fiM:mN:stw:vz")) != -1) {
137
		switch (c) {
138
		case 'c':
139
			reps = strtonum(optarg, 0, INT_MAX, &errstr);
140
			if (errstr)
141
				errx(1, "-c %s: %s", optarg, errstr);
142
			break;
143
		case 'f':
144
			todo |= FORKSTAT;
145
			break;
146
		case 'i':
147
			todo |= INTRSTAT;
148
			break;
149
		case 'M':
150
			memf = optarg;
151
			break;
152
		case 'm':
153
			todo |= MEMSTAT;
154
			break;
155
		case 'N':
156
			nlistf = optarg;
157
			break;
158
		case 's':
159
			todo |= SUMSTAT;
160
			break;
161
		case 't':
162
			todo |= TIMESTAT;
163
			break;
164
		case 'w':
165
			interval = (u_int)strtonum(optarg, 0, 1000, &errstr);
166
			if (errstr)
167
				errx(1, "-w %s: %s", optarg, errstr);
168
			break;
169
		case 'v':
170
			verbose = 1;
171
			break;
172
		case 'z':
173
			zflag = 1;
174
			break;
175
		case '?':
176
		default:
177
			usage();
178
		}
179
	}
180
	argc -= optind;
181
	argv += optind;
182
183
	if (todo == 0)
184
		todo = VMSTAT;
185
186
	if (nlistf != NULL || memf != NULL) {
187
188
		kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
189
		if (kd == 0)
190
			errx(1, "kvm_openfiles: %s", errbuf);
191
192
		if ((c = kvm_nlist(kd, namelist)) != 0) {
193
194
			if (c > 0) {
195
				(void)fprintf(stderr,
196
				    "%s: undefined symbols:", __progname);
197
				for (c = 0;
198
				    c < sizeof(namelist)/sizeof(namelist[0]);
199
				    c++)
200
					if (namelist[c].n_type == 0)
201
						fprintf(stderr, " %s",
202
						    namelist[c].n_name);
203
				(void)fputc('\n', stderr);
204
				exit(1);
205
			} else
206
				errx(1, "kvm_nlist: %s", kvm_geterr(kd));
207
		}
208
	}
209
210
	if (todo & VMSTAT) {
211
		struct winsize winsize;
212
213
		dkinit(0);	/* Initialize disk stats, no disks selected. */
214
		argv = choosedrives(argv);	/* Select disks. */
215
		winsize.ws_row = 0;
216
		(void) ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize);
217
		if (winsize.ws_row > 0)
218
			winlines = winsize.ws_row;
219
220
	}
221
222
#define	BACKWARD_COMPATIBILITY
223
#ifdef	BACKWARD_COMPATIBILITY
224
	if (*argv) {
225
		interval = (u_int)strtonum(*argv, 0, 1000, &errstr);
226
		if (errstr)
227
			errx(1, "interval %s: %s", *argv, errstr);
228
229
		if (*++argv) {
230
			reps = strtonum(*argv, 0, INT_MAX, &errstr);
231
			if (errstr)
232
				errx(1, "reps %s: %s", *argv, errstr);
233
		}
234
	}
235
#endif
236
237
	if (interval) {
238
		if (!reps)
239
			reps = -1;
240
	} else if (reps)
241
		interval = 1;
242
243
	if (todo & FORKSTAT)
244
		doforkst();
245
	if (todo & MEMSTAT) {
246
		domem();
247
		dopool();
248
	}
249
	if (todo & SUMSTAT)
250
		dosum();
251
	if (todo & TIMESTAT)
252
		dotimes();
253
	if (todo & INTRSTAT)
254
		dointr();
255
	if (todo & VMSTAT)
256
		dovmstat(interval, reps);
257
	exit(0);
258
}
259
260
char **
261
choosedrives(char **argv)
262
{
263
	int i;
264
265
	/*
266
	 * Choose drives to be displayed.  Priority goes to (in order) drives
267
	 * supplied as arguments, default drives.  If everything isn't filled
268
	 * in and there are drives not taken care of, display the first few
269
	 * that fit.
270
	 */
271
#define BACKWARD_COMPATIBILITY
272
	for (ndrives = 0; *argv; ++argv) {
273
#ifdef	BACKWARD_COMPATIBILITY
274
		if (isdigit((unsigned char)**argv))
275
			break;
276
#endif
277
		for (i = 0; i < dk_ndrive; i++) {
278
			if (strcmp(dr_name[i], *argv))
279
				continue;
280
			dk_select[i] = 1;
281
			++ndrives;
282
			break;
283
		}
284
		if (i == dk_ndrive)
285
			errx(1, "invalid interval or drive name: %s", *argv);
286
	}
287
	for (i = 0; i < dk_ndrive && ndrives < 2; i++) {
288
		if (dk_select[i])
289
			continue;
290
		dk_select[i] = 1;
291
		++ndrives;
292
	}
293
	return(argv);
294
}
295
296
time_t
297
getuptime(void)
298
{
299
	struct timespec uptime;
300
	time_t time_uptime, naptime;
301
302
	if (nlistf == NULL && memf == NULL) {
303
		if (clock_gettime(CLOCK_UPTIME, &uptime) == -1)
304
			err(1, "clock_gettime");
305
		return (uptime.tv_sec);
306
	}
307
308
	kread(X_NAPTIME, &naptime, sizeof(naptime));
309
	kread(X_TIME_UPTIME, &time_uptime, sizeof(time_uptime));
310
	return (time_uptime - naptime);
311
}
312
313
int	hz;
314
volatile sig_atomic_t hdrcnt;
315
316
void
317
dovmstat(u_int interval, int reps)
318
{
319
	time_t uptime, halfuptime;
320
	struct clockinfo clkinfo;
321
	struct vmtotal total;
322
	size_t size;
323
	int mib[2];
324
325
	uptime = getuptime();
326
	halfuptime = uptime / 2;
327
	(void)signal(SIGCONT, needhdr);
328
329
	mib[0] = CTL_KERN;
330
	mib[1] = KERN_CLOCKRATE;
331
	size = sizeof(clkinfo);
332
	if (sysctl(mib, 2, &clkinfo, &size, NULL, 0) < 0) {
333
		warn("could not read kern.clockrate");
334
		return;
335
	}
336
	hz = clkinfo.stathz;
337
338
	for (hdrcnt = 1;;) {
339
		/* Read new disk statistics */
340
		dkreadstats();
341
		if (!--hdrcnt || last.dk_ndrive != cur.dk_ndrive)
342
			printhdr();
343
		if (nlistf == NULL && memf == NULL) {
344
			size = sizeof(struct uvmexp);
345
			mib[0] = CTL_VM;
346
			mib[1] = VM_UVMEXP;
347
			if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) {
348
				warn("could not get vm.uvmexp");
349
				memset(&uvmexp, 0, sizeof(struct uvmexp));
350
			}
351
		} else {
352
			kread(X_UVMEXP, &uvmexp, sizeof(struct uvmexp));
353
		}
354
		size = sizeof(total);
355
		mib[0] = CTL_VM;
356
		mib[1] = VM_METER;
357
		if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
358
			warn("could not read vm.vmmeter");
359
			memset(&total, 0, sizeof(total));
360
		}
361
		(void)printf(" %u %u %u ",
362
		    total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
363
#define	rate(x)	((unsigned)((((unsigned)x) + halfuptime) / uptime)) /* round */
364
#define pgtok(a) ((a) * ((unsigned int)uvmexp.pagesize >> 10))
365
		(void)printf("%6u %7u ",
366
		    pgtok(uvmexp.active + uvmexp.swpginuse),
367
		    pgtok(uvmexp.free));
368
		(void)printf("%4u ", rate(uvmexp.faults - ouvmexp.faults));
369
		(void)printf("%3u ", rate(uvmexp.pdreact - ouvmexp.pdreact));
370
		(void)printf("%3u ", rate(uvmexp.pageins - ouvmexp.pageins));
371
		(void)printf("%3u %3u ",
372
		    rate(uvmexp.pdpageouts - ouvmexp.pdpageouts), 0);
373
		(void)printf("%3u ", rate(uvmexp.pdscans - ouvmexp.pdscans));
374
		dkstats();
375
		(void)printf("%4u %5u %4u ",
376
		    rate(uvmexp.intrs - ouvmexp.intrs),
377
		    rate(uvmexp.syscalls - ouvmexp.syscalls),
378
		    rate(uvmexp.swtch - ouvmexp.swtch));
379
		cpustats();
380
		(void)printf("\n");
381
		(void)fflush(stdout);
382
		if (reps >= 0 && --reps <= 0)
383
			break;
384
		ouvmexp = uvmexp;
385
		uptime = interval;
386
		/*
387
		 * We round upward to avoid losing low-frequency events
388
		 * (i.e., >= 1 per interval but < 1 per second).
389
		 */
390
		halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2;
391
		(void)sleep(interval);
392
	}
393
}
394
395
void
396
printhdr(void)
397
{
398
	int i;
399
	static int printedhdr;
400
401
	if (printedhdr && !isatty(STDOUT_FILENO))
402
		return;
403
404
	(void)printf(" procs    memory       page%*s", 20, "");
405
	if (ndrives > 0)
406
		(void)printf("%s %*straps          cpu\n",
407
		   ((ndrives > 1) ? "disks" : "disk"),
408
		   ((ndrives > 1) ? ndrives * 4 - 5 : 0), "");
409
	else
410
		(void)printf("%*s  traps           cpu\n",
411
		   ndrives * 3, "");
412
413
	(void)printf(" r b w    avm     fre  flt  re  pi  po  fr  sr ");
414
	for (i = 0; i < dk_ndrive; i++)
415
		if (dk_select[i])
416
			(void)printf("%c%c%c ", dr_name[i][0],
417
			    dr_name[i][1],
418
			    dr_name[i][strlen(dr_name[i]) - 1]);
419
	(void)printf(" int   sys   cs us sy id\n");
420
	hdrcnt = winlines - 2;
421
	printedhdr = 1;
422
}
423
424
/*
425
 * Force a header to be prepended to the next output.
426
 */
427
/* ARGSUSED */
428
void
429
needhdr(int signo)
430
{
431
432
	hdrcnt = 1;
433
}
434
435
void
436
dotimes(void)
437
{
438
	u_int pgintime, rectime;
439
	size_t size;
440
	int mib[2];
441
442
	/* XXX Why are these set to 0 ? This doesn't look right. */
443
	pgintime = 0;
444
	rectime = 0;
445
446
	if (nlistf == NULL && memf == NULL) {
447
		size = sizeof(struct uvmexp);
448
		mib[0] = CTL_VM;
449
		mib[1] = VM_UVMEXP;
450
		if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) {
451
			warn("could not read vm.uvmexp");
452
			memset(&uvmexp, 0, sizeof(struct uvmexp));
453
		}
454
	} else {
455
		kread(X_UVMEXP, &uvmexp, sizeof(struct uvmexp));
456
	}
457
458
	(void)printf("%u reactivates, %u total time (usec)\n",
459
	    uvmexp.pdreact, rectime);
460
	if (uvmexp.pdreact != 0)
461
		(void)printf("average: %u usec / reclaim\n",
462
		    rectime / uvmexp.pdreact);
463
	(void)printf("\n");
464
	(void)printf("%u page ins, %u total time (msec)\n",
465
	    uvmexp.pageins, pgintime / 10);
466
	if (uvmexp.pageins != 0)
467
		(void)printf("average: %8.1f msec / page in\n",
468
		    pgintime / (uvmexp.pageins * 10.0));
469
}
470
471
int
472
pct(int64_t top, int64_t bot)
473
{
474
	int ans;
475
476
	if (bot == 0)
477
		return(0);
478
	ans = top * 100 / bot;
479
	return (ans);
480
}
481
482
void
483
dosum(void)
484
{
485
	struct nchstats nchstats;
486
	int mib[2], nselcoll;
487
	long long nchtotal;
488
	size_t size;
489
490
	if (nlistf == NULL && memf == NULL) {
491
		size = sizeof(struct uvmexp);
492
		mib[0] = CTL_VM;
493
		mib[1] = VM_UVMEXP;
494
		if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) {
495
			warn("could not read vm.uvmexp");
496
			memset(&uvmexp, 0, sizeof(struct uvmexp));
497
		}
498
	} else {
499
		kread(X_UVMEXP, &uvmexp, sizeof(struct uvmexp));
500
	}
501
502
	/* vm_page constants */
503
	(void)printf("%11u bytes per page\n", uvmexp.pagesize);
504
505
	/* vm_page counters */
506
	(void)printf("%11u pages managed\n", uvmexp.npages);
507
	(void)printf("%11u pages free\n", uvmexp.free);
508
	(void)printf("%11u pages active\n", uvmexp.active);
509
	(void)printf("%11u pages inactive\n", uvmexp.inactive);
510
	(void)printf("%11u pages being paged out\n", uvmexp.paging);
511
	(void)printf("%11u pages wired\n", uvmexp.wired);
512
	(void)printf("%11u pages zeroed\n", uvmexp.zeropages);
513
	(void)printf("%11u pages reserved for pagedaemon\n",
514
		     uvmexp.reserve_pagedaemon);
515
	(void)printf("%11u pages reserved for kernel\n",
516
		     uvmexp.reserve_kernel);
517
518
	/* swap */
519
	(void)printf("%11u swap pages\n", uvmexp.swpages);
520
	(void)printf("%11u swap pages in use\n", uvmexp.swpginuse);
521
	(void)printf("%11u total anon's in system\n", uvmexp.nanon);
522
	(void)printf("%11u free anon's\n", uvmexp.nfreeanon);
523
524
	/* stat counters */
525
	(void)printf("%11u page faults\n", uvmexp.faults);
526
	(void)printf("%11u traps\n", uvmexp.traps);
527
	(void)printf("%11u interrupts\n", uvmexp.intrs);
528
	(void)printf("%11u cpu context switches\n", uvmexp.swtch);
529
	(void)printf("%11u fpu context switches\n", uvmexp.fpswtch);
530
	(void)printf("%11u software interrupts\n", uvmexp.softs);
531
	(void)printf("%11u syscalls\n", uvmexp.syscalls);
532
	(void)printf("%11u pagein operations\n", uvmexp.pageins);
533
	(void)printf("%11u forks\n", uvmexp.forks);
534
	(void)printf("%11u forks where vmspace is shared\n",
535
		     uvmexp.forks_sharevm);
536
	(void)printf("%11u kernel map entries\n", uvmexp.kmapent);
537
	(void)printf("%11u zeroed page hits\n", uvmexp.pga_zerohit);
538
	(void)printf("%11u zeroed page misses\n", uvmexp.pga_zeromiss);
539
540
	/* daemon counters */
541
	(void)printf("%11u number of times the pagedaemon woke up\n",
542
		     uvmexp.pdwoke);
543
	(void)printf("%11u revolutions of the clock hand\n", uvmexp.pdrevs);
544
	(void)printf("%11u pages freed by pagedaemon\n", uvmexp.pdfreed);
545
	(void)printf("%11u pages scanned by pagedaemon\n", uvmexp.pdscans);
546
	(void)printf("%11u pages reactivated by pagedaemon\n", uvmexp.pdreact);
547
	(void)printf("%11u busy pages found by pagedaemon\n", uvmexp.pdbusy);
548
549
	if (nlistf == NULL && memf == NULL) {
550
		size = sizeof(nchstats);
551
		mib[0] = CTL_KERN;
552
		mib[1] = KERN_NCHSTATS;
553
		if (sysctl(mib, 2, &nchstats, &size, NULL, 0) < 0) {
554
			warn("could not read kern.nchstats");
555
			memset(&nchstats, 0, sizeof(nchstats));
556
		}
557
	} else {
558
		kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
559
	}
560
561
	nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
562
	    nchstats.ncs_badhits + nchstats.ncs_falsehits +
563
	    nchstats.ncs_miss + nchstats.ncs_long;
564
	(void)printf("%11lld total name lookups\n", nchtotal);
565
	(void)printf("%11s cache hits (%d%% pos + %d%% neg) system %d%% "
566
	    "per-directory\n",
567
	    "", pct(nchstats.ncs_goodhits, nchtotal),
568
	    pct(nchstats.ncs_neghits, nchtotal),
569
	    pct(nchstats.ncs_pass2, nchtotal));
570
	(void)printf("%11s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
571
	    pct(nchstats.ncs_badhits, nchtotal),
572
	    pct(nchstats.ncs_falsehits, nchtotal),
573
	    pct(nchstats.ncs_long, nchtotal));
574
575
	if (nlistf == NULL && memf == NULL) {
576
		size = sizeof(nselcoll);
577
		mib[0] = CTL_KERN;
578
		mib[1] = KERN_NSELCOLL;
579
		if (sysctl(mib, 2, &nselcoll, &size, NULL, 0) < 0) {
580
			warn("could not read kern.nselcoll");
581
			nselcoll = 0;
582
		}
583
	} else {
584
		kread(X_NSELCOLL, &nselcoll, sizeof(nselcoll));
585
	}
586
	(void)printf("%11d select collisions\n", nselcoll);
587
}
588
589
void
590
doforkst(void)
591
{
592
	struct forkstat fks;
593
	size_t size;
594
	int mib[2];
595
596
	if (nlistf == NULL && memf == NULL) {
597
		size = sizeof(struct forkstat);
598
		mib[0] = CTL_KERN;
599
		mib[1] = KERN_FORKSTAT;
600
		if (sysctl(mib, 2, &fks, &size, NULL, 0) < 0) {
601
			warn("could not read kern.forkstat");
602
			memset(&fks, 0, sizeof(struct forkstat));
603
		}
604
	} else {
605
		kread(X_FORKSTAT, &fks, sizeof(struct forkstat));
606
	}
607
608
	(void)printf("%d forks, %d pages, average %.2f\n",
609
	    fks.cntfork, fks.sizfork, (double)fks.sizfork / fks.cntfork);
610
	(void)printf("%d vforks, %d pages, average %.2f\n",
611
	    fks.cntvfork, fks.sizvfork,
612
	    (double)fks.sizvfork / (fks.cntvfork ? fks.cntvfork : 1));
613
	(void)printf("%d __tforks, %d pages, average %.2f\n",
614
	    fks.cnttfork, fks.siztfork,
615
	    (double)fks.siztfork / (fks.cnttfork ? fks.cnttfork : 1));
616
	(void)printf("%d kthread creations, %d pages, average %.2f\n",
617
	    fks.cntkthread, fks.sizkthread,
618
	    (double)fks.sizkthread / (fks.cntkthread ? fks.cntkthread : 1));
619
}
620
621
void
622
dkstats(void)
623
{
624
	int dn, state;
625
	double etime;
626
627
	/* Calculate disk stat deltas. */
628
	dkswap();
629
	etime = 0;
630
	for (state = 0; state < CPUSTATES; ++state) {
631
		etime += cur.cp_time[state];
632
	}
633
	if (etime == 0)
634
		etime = 1;
635
	etime /= hz;
636
	for (dn = 0; dn < dk_ndrive; ++dn) {
637
		if (!dk_select[dn])
638
			continue;
639
		(void)printf("%3.0f ",
640
		    (cur.dk_rxfer[dn] + cur.dk_rxfer[dn]) / etime);
641
	}
642
}
643
644
void
645
cpustats(void)
646
{
647
	double percent, total;
648
	int state;
649
650
	total = 0;
651
	for (state = 0; state < CPUSTATES; ++state)
652
		total += cur.cp_time[state];
653
	if (total)
654
		percent = 100 / total;
655
	else
656
		percent = 0;
657
	(void)printf("%2.0f ", (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * percent);
658
	(void)printf("%2.0f ", (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * percent);
659
	(void)printf("%2.0f", cur.cp_time[CP_IDLE] * percent);
660
}
661
662
void
663
dointr(void)
664
{
665
	int nintr, mib[4], i;
666
	char intrname[128];
667
	u_int64_t inttotal;
668
	time_t uptime;
669
	size_t siz;
670
671
	if (nlistf != NULL || memf != NULL) {
672
		errx(1,
673
		    "interrupt statistics are only available on live kernels");
674
	}
675
676
	uptime = getuptime();
677
678
	mib[0] = CTL_KERN;
679
	mib[1] = KERN_INTRCNT;
680
	mib[2] = KERN_INTRCNT_NUM;
681
	siz = sizeof(nintr);
682
	if (sysctl(mib, 3, &nintr, &siz, NULL, 0) < 0) {
683
		warnx("could not read kern.intrcnt.nintrcnt");
684
		return;
685
	}
686
687
	(void)printf("%-16s %20s %8s\n", "interrupt", "total", "rate");
688
689
	inttotal = 0;
690
	for (i = 0; i < nintr; i++) {
691
		char name[128];
692
		u_quad_t cnt;
693
		int vector;
694
695
		mib[0] = CTL_KERN;
696
		mib[1] = KERN_INTRCNT;
697
		mib[2] = KERN_INTRCNT_NAME;
698
		mib[3] = i;
699
		siz = sizeof(name);
700
		if (sysctl(mib, 4, name, &siz, NULL, 0) < 0) {
701
			warnx("could not read kern.intrcnt.name.%d", i);
702
			return;
703
		}
704
705
		mib[0] = CTL_KERN;
706
		mib[1] = KERN_INTRCNT;
707
		mib[2] = KERN_INTRCNT_VECTOR;
708
		mib[3] = i;
709
		siz = sizeof(vector);
710
		if (sysctl(mib, 4, &vector, &siz, NULL, 0) < 0) {
711
			strlcpy(intrname, name, sizeof(intrname));
712
		} else {
713
			snprintf(intrname, sizeof(intrname), "irq%d/%s",
714
			    vector, name);
715
		}
716
717
		mib[0] = CTL_KERN;
718
		mib[1] = KERN_INTRCNT;
719
		mib[2] = KERN_INTRCNT_CNT;
720
		mib[3] = i;
721
		siz = sizeof(cnt);
722
		if (sysctl(mib, 4, &cnt, &siz, NULL, 0) < 0) {
723
			warnx("could not read kern.intrcnt.cnt.%d", i);
724
			return;
725
		}
726
727
		if (cnt || zflag)
728
			(void)printf("%-16.16s %20llu %8llu\n", intrname,
729
			    cnt, cnt / uptime);
730
		inttotal += cnt;
731
	}
732
733
	(void)printf("%-16s %20llu %8llu\n", "Total", inttotal,
734
	    inttotal / uptime);
735
}
736
737
/*
738
 * These names are defined in <sys/malloc.h>.
739
 */
740
const char *kmemnames[] = INITKMEMNAMES;
741
742
void
743
domem(void)
744
{
745
	struct kmembuckets buckets[MINBUCKET + 16], *kp;
746
	struct kmemstats kmemstats[M_LAST], *ks;
747
	int i, j, len, size, first, mib[4];
748
	u_long totuse = 0, totfree = 0;
749
	char buf[BUFSIZ], *bufp, *ap;
750
	quad_t totreq = 0;
751
	const char *name;
752
	size_t siz;
753
754
	if (memf == NULL && nlistf == NULL) {
755
		mib[0] = CTL_KERN;
756
		mib[1] = KERN_MALLOCSTATS;
757
		mib[2] = KERN_MALLOC_BUCKETS;
758
		siz = sizeof(buf);
759
		if (sysctl(mib, 3, buf, &siz, NULL, 0) < 0) {
760
			warnx("could not read kern.malloc.buckets");
761
			return;
762
		}
763
764
		bufp = buf;
765
		mib[2] = KERN_MALLOC_BUCKET;
766
		siz = sizeof(struct kmembuckets);
767
		i = 0;
768
		while ((ap = strsep(&bufp, ",")) != NULL) {
769
			const char *errstr;
770
771
			mib[3] = strtonum(ap, 0, INT_MAX, &errstr);
772
			if (errstr) {
773
				warnx("kernel lied about %d being a number", mib[3]);
774
				return;
775
			}
776
777
			if (sysctl(mib, 4, &buckets[MINBUCKET + i], &siz,
778
			    NULL, 0) < 0) {
779
				warn("could not read kern.malloc.bucket.%d", mib[3]);
780
				return;
781
			}
782
			i++;
783
		}
784
	} else {
785
		kread(X_KMEMBUCKETS, buckets, sizeof(buckets));
786
	}
787
788
	for (first = 1, i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16;
789
	     i++, kp++) {
790
		if (kp->kb_calls == 0 && !verbose)
791
			continue;
792
		if (first) {
793
			(void)printf("Memory statistics by bucket size\n");
794
			(void)printf(
795
		"    Size   In Use   Free           Requests  HighWater  Couldfree\n");
796
			first = 0;
797
		}
798
		size = 1 << i;
799
		(void)printf("%8d %8llu %6llu %18llu %7llu %10llu\n", size,
800
			(unsigned long long)(kp->kb_total - kp->kb_totalfree),
801
			(unsigned long long)kp->kb_totalfree,
802
			(unsigned long long)kp->kb_calls,
803
			(unsigned long long)kp->kb_highwat,
804
			(unsigned long long)kp->kb_couldfree);
805
		totfree += size * kp->kb_totalfree;
806
	}
807
808
	/*
809
	 * If kmem statistics are not being gathered by the kernel,
810
	 * first will still be 1.
811
	 */
812
	if (first) {
813
		printf(
814
		    "Kmem statistics are not being gathered by the kernel.\n");
815
		return;
816
	}
817
818
	if (memf == NULL && nlistf == NULL) {
819
		memset(kmemstats, 0, sizeof(kmemstats));
820
		for (i = 0; i < M_LAST; i++) {
821
			mib[0] = CTL_KERN;
822
			mib[1] = KERN_MALLOCSTATS;
823
			mib[2] = KERN_MALLOC_KMEMSTATS;
824
			mib[3] = i;
825
			siz = sizeof(struct kmemstats);
826
827
			/*
828
			 * Skip errors -- these are presumed to be unallocated
829
			 * entries.
830
			 */
831
			if (sysctl(mib, 4, &kmemstats[i], &siz, NULL, 0) < 0)
832
				continue;
833
		}
834
	} else {
835
		kread(X_KMEMSTAT, kmemstats, sizeof(kmemstats));
836
	}
837
838
	(void)printf("\nMemory usage type by bucket size\n");
839
	(void)printf("    Size  Type(s)\n");
840
	kp = &buckets[MINBUCKET];
841
	for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) {
842
		if (kp->kb_calls == 0)
843
			continue;
844
		first = 1;
845
		len = 8;
846
		for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
847
			if (ks->ks_calls == 0)
848
				continue;
849
			if ((ks->ks_size & j) == 0)
850
				continue;
851
			name = kmemnames[i] ? kmemnames[i] : "undefined";
852
			len += 2 + strlen(name);
853
			if (first)
854
				printf("%8d  %s", j, name);
855
			else
856
				printf(",");
857
			if (len >= 80) {
858
				printf("\n\t ");
859
				len = 10 + strlen(name);
860
			}
861
			if (!first)
862
				printf(" %s", name);
863
			first = 0;
864
		}
865
		printf("\n");
866
	}
867
868
	(void)printf(
869
	   "\nMemory statistics by type                           Type  Kern\n");
870
	(void)printf(
871
"          Type InUse MemUse HighUse  Limit Requests Limit Limit Size(s)\n");
872
	for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
873
		if (ks->ks_calls == 0)
874
			continue;
875
		(void)printf("%14s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u",
876
		    kmemnames[i] ? kmemnames[i] : "undefined",
877
		    ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
878
		    (ks->ks_maxused + 1023) / 1024,
879
		    (ks->ks_limit + 1023) / 1024, ks->ks_calls,
880
		    ks->ks_limblocks, ks->ks_mapblocks);
881
		first = 1;
882
		for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
883
			if ((ks->ks_size & j) == 0)
884
				continue;
885
			if (first)
886
				printf("  %d", j);
887
			else
888
				printf(",%d", j);
889
			first = 0;
890
		}
891
		printf("\n");
892
		totuse += ks->ks_memuse;
893
		totreq += ks->ks_calls;
894
	}
895
	(void)printf("\nMemory Totals:  In Use    Free    Requests\n");
896
	(void)printf("              %7luK %6luK    %8qu\n",
897
	     (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq);
898
}
899
900
static void
901
print_pool(struct kinfo_pool *pp, char *name)
902
{
903
	static int first = 1;
904
	char maxp[32];
905
	int ovflw;
906
907
	if (first) {
908
		(void)printf("Memory resource pool statistics\n");
909
		(void)printf(
910
		    "%-11s%5s%9s%5s%9s%6s%6s%6s%6s%6s%6s%5s\n",
911
		    "Name",
912
		    "Size",
913
		    "Requests",
914
		    "Fail",
915
		    "InUse",
916
		    "Pgreq",
917
		    "Pgrel",
918
		    "Npage",
919
		    "Hiwat",
920
		    "Minpg",
921
		    "Maxpg",
922
		    "Idle");
923
		first = 0;
924
	}
925
926
	/* Skip unused pools unless verbose output. */
927
	if (pp->pr_nget == 0 && !verbose)
928
		return;
929
930
	if (pp->pr_maxpages == UINT_MAX)
931
		snprintf(maxp, sizeof maxp, "inf");
932
	else
933
		snprintf(maxp, sizeof maxp, "%u", pp->pr_maxpages);
934
/*
935
 * Print single word.  `ovflow' is number of characters didn't fit
936
 * on the last word.  `fmt' is a format string to print this word.
937
 * It must contain asterisk for field width.  `width' is a width
938
 * occupied by this word.  `fixed' is a number of constant chars in
939
 * `fmt'.  `val' is a value to be printed using format string `fmt'.
940
 */
941
#define	PRWORD(ovflw, fmt, width, fixed, val) do {	\
942
	(ovflw) += printf((fmt),			\
943
	    (width) - (fixed) - (ovflw) > 0 ?		\
944
	    (width) - (fixed) - (ovflw) : 0,		\
945
	    (val)) - (width);				\
946
	if ((ovflw) < 0)				\
947
		(ovflw) = 0;				\
948
} while (/* CONSTCOND */0)
949
950
	ovflw = 0;
951
	PRWORD(ovflw, "%-*s", 11, 0, name);
952
	PRWORD(ovflw, " %*u", 5, 1, pp->pr_size);
953
	PRWORD(ovflw, " %*lu", 9, 1, pp->pr_nget);
954
	PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nfail);
955
	PRWORD(ovflw, " %*lu", 9, 1, pp->pr_nget - pp->pr_nput);
956
	PRWORD(ovflw, " %*lu", 6, 1, pp->pr_npagealloc);
957
	PRWORD(ovflw, " %*lu", 6, 1, pp->pr_npagefree);
958
	PRWORD(ovflw, " %*d", 6, 1, pp->pr_npages);
959
	PRWORD(ovflw, " %*d", 6, 1, pp->pr_hiwat);
960
	PRWORD(ovflw, " %*d", 6, 1, pp->pr_minpages);
961
	PRWORD(ovflw, " %*s", 6, 1, maxp);
962
	PRWORD(ovflw, " %*lu\n", 5, 1, pp->pr_nidle);
963
}
964
965
static void dopool_kvm(void);
966
static void dopool_sysctl(void);
967
968
void
969
dopool(void)
970
{
971
	if (nlistf == NULL && memf == NULL)
972
		dopool_sysctl();
973
	else
974
		dopool_kvm();
975
}
976
977
void
978
dopool_sysctl(void)
979
{
980
	int mib[4], npools, i;
981
	long total = 0, inuse = 0;
982
	struct kinfo_pool pool;
983
	size_t size;
984
985
	mib[0] = CTL_KERN;
986
	mib[1] = KERN_POOL;
987
	mib[2] = KERN_POOL_NPOOLS;
988
	size = sizeof(npools);
989
	if (sysctl(mib, 3, &npools, &size, NULL, 0) < 0) {
990
		warn("can't figure out number of pools in kernel");
991
		return;
992
	}
993
994
	for (i = 1; npools; i++) {
995
		char name[32];
996
997
		mib[0] = CTL_KERN;
998
		mib[1] = KERN_POOL;
999
		mib[2] = KERN_POOL_POOL;
1000
		mib[3] = i;
1001
		size = sizeof(pool);
1002
		if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) {
1003
			if (errno == ENOENT)
1004
				continue;
1005
			warn("error getting pool");
1006
			return;
1007
		}
1008
		npools--;
1009
		mib[2] = KERN_POOL_NAME;
1010
		size = sizeof(name);
1011
		if (sysctl(mib, 4, &name, &size, NULL, 0) < 0) {
1012
			warn("error getting pool name");
1013
			return;
1014
		}
1015
		print_pool(&pool, name);
1016
1017
		inuse += (pool.pr_nget - pool.pr_nput) * pool.pr_size;
1018
		total += pool.pr_npages * pool.pr_pgsize;
1019
	}
1020
1021
	inuse /= 1024;
1022
	total /= 1024;
1023
	printf("\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n",
1024
	    inuse, total, (double)(100 * inuse) / total);
1025
}
1026
1027
void
1028
dopool_kvm(void)
1029
{
1030
	SIMPLEQ_HEAD(,pool) pool_head;
1031
	struct pool pool, *pp = &pool;
1032
	struct kinfo_pool pi;
1033
	long total = 0, inuse = 0;
1034
	u_long addr;
1035
1036
	kread(X_POOLHEAD, &pool_head, sizeof(pool_head));
1037
	addr = (u_long)SIMPLEQ_FIRST(&pool_head);
1038
1039
	while (addr != 0) {
1040
		char name[32];
1041
1042
		if (kvm_read(kd, addr, (void *)pp, sizeof *pp) != sizeof *pp) {
1043
			(void)fprintf(stderr,
1044
			    "vmstat: pool chain trashed: %s\n",
1045
			    kvm_geterr(kd));
1046
			exit(1);
1047
		}
1048
		if (kvm_read(kd, (u_long)pp->pr_wchan, name, sizeof name) < 0) {
1049
			(void)fprintf(stderr,
1050
			    "vmstat: pool name trashed: %s\n",
1051
			    kvm_geterr(kd));
1052
			exit(1);
1053
		}
1054
		name[31] = '\0';
1055
1056
		memset(&pi, 0, sizeof(pi));
1057
		pi.pr_size = pp->pr_size;
1058
		pi.pr_pgsize = pp->pr_pgsize;
1059
		pi.pr_itemsperpage = pp->pr_itemsperpage;
1060
		pi.pr_npages = pp->pr_npages;
1061
		pi.pr_minpages = pp->pr_minpages;
1062
		pi.pr_maxpages = pp->pr_maxpages;
1063
		pi.pr_hardlimit = pp->pr_hardlimit;
1064
		pi.pr_nout = pp->pr_nout;
1065
		pi.pr_nitems = pp->pr_nitems;
1066
		pi.pr_nget = pp->pr_nget;
1067
		pi.pr_nput = pp->pr_nput;
1068
		pi.pr_nfail = pp->pr_nfail;
1069
		pi.pr_npagealloc = pp->pr_npagealloc;
1070
		pi.pr_npagefree = pp->pr_npagefree;
1071
		pi.pr_hiwat = pp->pr_hiwat;
1072
		pi.pr_nidle = pp->pr_nidle;
1073
1074
		print_pool(&pi, name);
1075
1076
		inuse += (pi.pr_nget - pi.pr_nput) * pi.pr_size;
1077
		total += pi.pr_npages * pi.pr_pgsize;
1078
1079
		addr = (u_long)SIMPLEQ_NEXT(pp, pr_poollist);
1080
	}
1081
1082
	inuse /= 1024;
1083
	total /= 1024;
1084
	printf("\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n",
1085
	    inuse, total, (double)(100 * inuse) / total);
1086
}
1087
1088
/*
1089
 * kread reads something from the kernel, given its nlist index.
1090
 */
1091
void
1092
kread(int nlx, void *addr, size_t size)
1093
{
1094
	char *sym;
1095
1096
	if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
1097
		sym = namelist[nlx].n_name;
1098
		if (*sym == '_')
1099
			++sym;
1100
		errx(1, "symbol %s not defined", sym);
1101
	}
1102
	if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) {
1103
		sym = namelist[nlx].n_name;
1104
		if (*sym == '_')
1105
			++sym;
1106
		errx(1, "%s: %s", sym, kvm_geterr(kd));
1107
	}
1108
}
1109
1110
void
1111
usage(void)
1112
{
1113
	(void)fprintf(stderr, "usage: %s [-fimstvz] [-c count] [-M core] "
1114
	    "[-N system] [-w wait] [disk ...]\n", __progname);
1115
	exit(1);
1116
}