GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vmstat/vmstat.c Lines: 0 579 0.0 %
Date: 2017-11-13 Branches: 0 255 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.142 2017/05/10 08:37:15 mpi 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("%2u %3u", total.t_rq - 1, total.t_sl);
362
#define	rate(x)	((unsigned)((((unsigned)x) + halfuptime) / uptime)) /* round */
363
#define pgtok(a) ((a) * ((unsigned int)uvmexp.pagesize >> 10))
364
		(void)printf("%5uM %6uM ",
365
		    pgtok(uvmexp.active + uvmexp.swpginuse) / 1024,
366
		    pgtok(uvmexp.free) / 1024);
367
		(void)printf("%4u ", rate(uvmexp.faults - ouvmexp.faults));
368
		(void)printf("%3u ", rate(uvmexp.pdreact - ouvmexp.pdreact));
369
		(void)printf("%3u ", rate(uvmexp.pageins - ouvmexp.pageins));
370
		(void)printf("%3u %3u ",
371
		    rate(uvmexp.pdpageouts - ouvmexp.pdpageouts), 0);
372
		(void)printf("%3u ", rate(uvmexp.pdscans - ouvmexp.pdscans));
373
		dkstats();
374
		(void)printf("%4u %5u %4u ",
375
		    rate(uvmexp.intrs - ouvmexp.intrs),
376
		    rate(uvmexp.syscalls - ouvmexp.syscalls),
377
		    rate(uvmexp.swtch - ouvmexp.swtch));
378
		cpustats();
379
		(void)printf("\n");
380
		(void)fflush(stdout);
381
		if (reps >= 0 && --reps <= 0)
382
			break;
383
		ouvmexp = uvmexp;
384
		uptime = interval;
385
		/*
386
		 * We round upward to avoid losing low-frequency events
387
		 * (i.e., >= 1 per interval but < 1 per second).
388
		 */
389
		halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2;
390
		(void)sleep(interval);
391
	}
392
}
393
394
void
395
printhdr(void)
396
{
397
	int i;
398
	static int printedhdr;
399
400
	if (printedhdr && !isatty(STDOUT_FILENO))
401
		return;
402
403
	(void)printf(" procs    memory       page%*s", 20, "");
404
	if (ndrives > 0)
405
		(void)printf("%s %*straps          cpu\n",
406
		   ((ndrives > 1) ? "disks" : "disk"),
407
		   ((ndrives > 1) ? ndrives * 4 - 5 : 0), "");
408
	else
409
		(void)printf("%*s  traps           cpu\n",
410
		   ndrives * 3, "");
411
412
	(void)printf(" r   s   avm     fre  flt  re  pi  po  fr  sr ");
413
	for (i = 0; i < dk_ndrive; i++)
414
		if (dk_select[i])
415
			(void)printf("%c%c%c ", dr_name[i][0],
416
			    dr_name[i][1],
417
			    dr_name[i][strlen(dr_name[i]) - 1]);
418
	(void)printf(" int   sys   cs us sy id\n");
419
	hdrcnt = winlines - 2;
420
	printedhdr = 1;
421
}
422
423
/*
424
 * Force a header to be prepended to the next output.
425
 */
426
void
427
needhdr(__unused int signo)
428
{
429
430
	hdrcnt = 1;
431
}
432
433
void
434
dotimes(void)
435
{
436
	u_int pgintime, rectime;
437
	size_t size;
438
	int mib[2];
439
440
	/* XXX Why are these set to 0 ? This doesn't look right. */
441
	pgintime = 0;
442
	rectime = 0;
443
444
	if (nlistf == NULL && memf == NULL) {
445
		size = sizeof(struct uvmexp);
446
		mib[0] = CTL_VM;
447
		mib[1] = VM_UVMEXP;
448
		if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) {
449
			warn("could not read vm.uvmexp");
450
			memset(&uvmexp, 0, sizeof(struct uvmexp));
451
		}
452
	} else {
453
		kread(X_UVMEXP, &uvmexp, sizeof(struct uvmexp));
454
	}
455
456
	(void)printf("%u reactivates, %u total time (usec)\n",
457
	    uvmexp.pdreact, rectime);
458
	if (uvmexp.pdreact != 0)
459
		(void)printf("average: %u usec / reclaim\n",
460
		    rectime / uvmexp.pdreact);
461
	(void)printf("\n");
462
	(void)printf("%u page ins, %u total time (msec)\n",
463
	    uvmexp.pageins, pgintime / 10);
464
	if (uvmexp.pageins != 0)
465
		(void)printf("average: %8.1f msec / page in\n",
466
		    pgintime / (uvmexp.pageins * 10.0));
467
}
468
469
int
470
pct(int64_t top, int64_t bot)
471
{
472
	int ans;
473
474
	if (bot == 0)
475
		return(0);
476
	ans = top * 100 / bot;
477
	return (ans);
478
}
479
480
void
481
dosum(void)
482
{
483
	struct nchstats nchstats;
484
	int mib[2], nselcoll;
485
	long long nchtotal;
486
	size_t size;
487
488
	if (nlistf == NULL && memf == NULL) {
489
		size = sizeof(struct uvmexp);
490
		mib[0] = CTL_VM;
491
		mib[1] = VM_UVMEXP;
492
		if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) {
493
			warn("could not read vm.uvmexp");
494
			memset(&uvmexp, 0, sizeof(struct uvmexp));
495
		}
496
	} else {
497
		kread(X_UVMEXP, &uvmexp, sizeof(struct uvmexp));
498
	}
499
500
	/* vm_page constants */
501
	(void)printf("%11u bytes per page\n", uvmexp.pagesize);
502
503
	/* vm_page counters */
504
	(void)printf("%11u pages managed\n", uvmexp.npages);
505
	(void)printf("%11u pages free\n", uvmexp.free);
506
	(void)printf("%11u pages active\n", uvmexp.active);
507
	(void)printf("%11u pages inactive\n", uvmexp.inactive);
508
	(void)printf("%11u pages being paged out\n", uvmexp.paging);
509
	(void)printf("%11u pages wired\n", uvmexp.wired);
510
	(void)printf("%11u pages zeroed\n", uvmexp.zeropages);
511
	(void)printf("%11u pages reserved for pagedaemon\n",
512
		     uvmexp.reserve_pagedaemon);
513
	(void)printf("%11u pages reserved for kernel\n",
514
		     uvmexp.reserve_kernel);
515
516
	/* swap */
517
	(void)printf("%11u swap pages\n", uvmexp.swpages);
518
	(void)printf("%11u swap pages in use\n", uvmexp.swpginuse);
519
	(void)printf("%11u total anon's in system\n", uvmexp.nanon);
520
	(void)printf("%11u free anon's\n", uvmexp.nfreeanon);
521
522
	/* stat counters */
523
	(void)printf("%11u page faults\n", uvmexp.faults);
524
	(void)printf("%11u traps\n", uvmexp.traps);
525
	(void)printf("%11u interrupts\n", uvmexp.intrs);
526
	(void)printf("%11u cpu context switches\n", uvmexp.swtch);
527
	(void)printf("%11u fpu context switches\n", uvmexp.fpswtch);
528
	(void)printf("%11u software interrupts\n", uvmexp.softs);
529
	(void)printf("%11u syscalls\n", uvmexp.syscalls);
530
	(void)printf("%11u pagein operations\n", uvmexp.pageins);
531
	(void)printf("%11u forks\n", uvmexp.forks);
532
	(void)printf("%11u forks where vmspace is shared\n",
533
		     uvmexp.forks_sharevm);
534
	(void)printf("%11u kernel map entries\n", uvmexp.kmapent);
535
	(void)printf("%11u zeroed page hits\n", uvmexp.pga_zerohit);
536
	(void)printf("%11u zeroed page misses\n", uvmexp.pga_zeromiss);
537
538
	/* daemon counters */
539
	(void)printf("%11u number of times the pagedaemon woke up\n",
540
		     uvmexp.pdwoke);
541
	(void)printf("%11u revolutions of the clock hand\n", uvmexp.pdrevs);
542
	(void)printf("%11u pages freed by pagedaemon\n", uvmexp.pdfreed);
543
	(void)printf("%11u pages scanned by pagedaemon\n", uvmexp.pdscans);
544
	(void)printf("%11u pages reactivated by pagedaemon\n", uvmexp.pdreact);
545
	(void)printf("%11u busy pages found by pagedaemon\n", uvmexp.pdbusy);
546
547
	if (nlistf == NULL && memf == NULL) {
548
		size = sizeof(nchstats);
549
		mib[0] = CTL_KERN;
550
		mib[1] = KERN_NCHSTATS;
551
		if (sysctl(mib, 2, &nchstats, &size, NULL, 0) < 0) {
552
			warn("could not read kern.nchstats");
553
			memset(&nchstats, 0, sizeof(nchstats));
554
		}
555
	} else {
556
		kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
557
	}
558
559
	nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
560
	    nchstats.ncs_badhits + nchstats.ncs_falsehits +
561
	    nchstats.ncs_miss + nchstats.ncs_long;
562
	(void)printf("%11lld total name lookups\n", nchtotal);
563
	(void)printf("%11s cache hits (%d%% pos + %d%% neg) system %d%% "
564
	    "per-directory\n",
565
	    "", pct(nchstats.ncs_goodhits, nchtotal),
566
	    pct(nchstats.ncs_neghits, nchtotal),
567
	    pct(nchstats.ncs_pass2, nchtotal));
568
	(void)printf("%11s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
569
	    pct(nchstats.ncs_badhits, nchtotal),
570
	    pct(nchstats.ncs_falsehits, nchtotal),
571
	    pct(nchstats.ncs_long, nchtotal));
572
573
	if (nlistf == NULL && memf == NULL) {
574
		size = sizeof(nselcoll);
575
		mib[0] = CTL_KERN;
576
		mib[1] = KERN_NSELCOLL;
577
		if (sysctl(mib, 2, &nselcoll, &size, NULL, 0) < 0) {
578
			warn("could not read kern.nselcoll");
579
			nselcoll = 0;
580
		}
581
	} else {
582
		kread(X_NSELCOLL, &nselcoll, sizeof(nselcoll));
583
	}
584
	(void)printf("%11d select collisions\n", nselcoll);
585
}
586
587
void
588
doforkst(void)
589
{
590
	struct forkstat fks;
591
	size_t size;
592
	int mib[2];
593
594
	if (nlistf == NULL && memf == NULL) {
595
		size = sizeof(struct forkstat);
596
		mib[0] = CTL_KERN;
597
		mib[1] = KERN_FORKSTAT;
598
		if (sysctl(mib, 2, &fks, &size, NULL, 0) < 0) {
599
			warn("could not read kern.forkstat");
600
			memset(&fks, 0, sizeof(struct forkstat));
601
		}
602
	} else {
603
		kread(X_FORKSTAT, &fks, sizeof(struct forkstat));
604
	}
605
606
	(void)printf("%u forks, %llu pages, average %.2f\n",
607
	    fks.cntfork, fks.sizfork, (double)fks.sizfork / fks.cntfork);
608
	(void)printf("%u vforks, %llu pages, average %.2f\n",
609
	    fks.cntvfork, fks.sizvfork,
610
	    (double)fks.sizvfork / (fks.cntvfork ? fks.cntvfork : 1));
611
	(void)printf("%u __tforks, %llu pages, average %.2f\n",
612
	    fks.cnttfork, fks.siztfork,
613
	    (double)fks.siztfork / (fks.cnttfork ? fks.cnttfork : 1));
614
	(void)printf("%u kthread creations, %llu pages, average %.2f\n",
615
	    fks.cntkthread, fks.sizkthread,
616
	    (double)fks.sizkthread / (fks.cntkthread ? fks.cntkthread : 1));
617
}
618
619
void
620
dkstats(void)
621
{
622
	int dn, state;
623
	double etime;
624
625
	/* Calculate disk stat deltas. */
626
	dkswap();
627
	etime = 0;
628
	for (state = 0; state < CPUSTATES; ++state) {
629
		etime += cur.cp_time[state];
630
	}
631
	if (etime == 0)
632
		etime = 1;
633
	etime /= hz;
634
	for (dn = 0; dn < dk_ndrive; ++dn) {
635
		if (!dk_select[dn])
636
			continue;
637
		(void)printf("%3.0f ",
638
		    (cur.dk_rxfer[dn] + cur.dk_rxfer[dn]) / etime);
639
	}
640
}
641
642
void
643
cpustats(void)
644
{
645
	double percent, total;
646
	int state;
647
648
	total = 0;
649
	for (state = 0; state < CPUSTATES; ++state)
650
		total += cur.cp_time[state];
651
	if (total)
652
		percent = 100 / total;
653
	else
654
		percent = 0;
655
	(void)printf("%2.0f ", (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * percent);
656
	(void)printf("%2.0f ", (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * percent);
657
	(void)printf("%2.0f", cur.cp_time[CP_IDLE] * percent);
658
}
659
660
void
661
dointr(void)
662
{
663
	int nintr, mib[4], i;
664
	char intrname[128];
665
	u_int64_t inttotal;
666
	time_t uptime;
667
	size_t siz;
668
669
	if (nlistf != NULL || memf != NULL) {
670
		errx(1,
671
		    "interrupt statistics are only available on live kernels");
672
	}
673
674
	uptime = getuptime();
675
676
	mib[0] = CTL_KERN;
677
	mib[1] = KERN_INTRCNT;
678
	mib[2] = KERN_INTRCNT_NUM;
679
	siz = sizeof(nintr);
680
	if (sysctl(mib, 3, &nintr, &siz, NULL, 0) < 0) {
681
		warnx("could not read kern.intrcnt.nintrcnt");
682
		return;
683
	}
684
685
	(void)printf("%-16s %20s %8s\n", "interrupt", "total", "rate");
686
687
	inttotal = 0;
688
	for (i = 0; i < nintr; i++) {
689
		char name[128];
690
		uint64_t cnt;
691
		int vector;
692
693
		mib[0] = CTL_KERN;
694
		mib[1] = KERN_INTRCNT;
695
		mib[2] = KERN_INTRCNT_NAME;
696
		mib[3] = i;
697
		siz = sizeof(name);
698
		if (sysctl(mib, 4, name, &siz, NULL, 0) < 0) {
699
			warnx("could not read kern.intrcnt.name.%d", i);
700
			return;
701
		}
702
703
		mib[0] = CTL_KERN;
704
		mib[1] = KERN_INTRCNT;
705
		mib[2] = KERN_INTRCNT_VECTOR;
706
		mib[3] = i;
707
		siz = sizeof(vector);
708
		if (sysctl(mib, 4, &vector, &siz, NULL, 0) < 0) {
709
			strlcpy(intrname, name, sizeof(intrname));
710
		} else {
711
			snprintf(intrname, sizeof(intrname), "irq%d/%s",
712
			    vector, name);
713
		}
714
715
		mib[0] = CTL_KERN;
716
		mib[1] = KERN_INTRCNT;
717
		mib[2] = KERN_INTRCNT_CNT;
718
		mib[3] = i;
719
		siz = sizeof(cnt);
720
		if (sysctl(mib, 4, &cnt, &siz, NULL, 0) < 0) {
721
			warnx("could not read kern.intrcnt.cnt.%d", i);
722
			return;
723
		}
724
725
		if (cnt || zflag)
726
			(void)printf("%-16.16s %20llu %8llu\n", intrname,
727
			    cnt, cnt / uptime);
728
		inttotal += cnt;
729
	}
730
731
	(void)printf("%-16s %20llu %8llu\n", "Total", inttotal,
732
	    inttotal / uptime);
733
}
734
735
/*
736
 * These names are defined in <sys/malloc.h>.
737
 */
738
const char *kmemnames[] = INITKMEMNAMES;
739
740
void
741
domem(void)
742
{
743
	struct kmembuckets buckets[MINBUCKET + 16], *kp;
744
	struct kmemstats kmemstats[M_LAST], *ks;
745
	int i, j, len, size, first, mib[4];
746
	u_long totuse = 0, totfree = 0;
747
	char buf[BUFSIZ], *bufp, *ap;
748
	unsigned long long totreq = 0;
749
	const char *name;
750
	size_t siz;
751
752
	if (memf == NULL && nlistf == NULL) {
753
		mib[0] = CTL_KERN;
754
		mib[1] = KERN_MALLOCSTATS;
755
		mib[2] = KERN_MALLOC_BUCKETS;
756
		siz = sizeof(buf);
757
		if (sysctl(mib, 3, buf, &siz, NULL, 0) < 0) {
758
			warnx("could not read kern.malloc.buckets");
759
			return;
760
		}
761
762
		bufp = buf;
763
		mib[2] = KERN_MALLOC_BUCKET;
764
		siz = sizeof(struct kmembuckets);
765
		i = 0;
766
		while ((ap = strsep(&bufp, ",")) != NULL) {
767
			const char *errstr;
768
769
			mib[3] = strtonum(ap, 0, INT_MAX, &errstr);
770
			if (errstr) {
771
				warnx("kernel lied about %d being a number", mib[3]);
772
				return;
773
			}
774
775
			if (sysctl(mib, 4, &buckets[MINBUCKET + i], &siz,
776
			    NULL, 0) < 0) {
777
				warn("could not read kern.malloc.bucket.%d", mib[3]);
778
				return;
779
			}
780
			i++;
781
		}
782
	} else {
783
		kread(X_KMEMBUCKETS, buckets, sizeof(buckets));
784
	}
785
786
	for (first = 1, i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16;
787
	     i++, kp++) {
788
		if (kp->kb_calls == 0 && !verbose)
789
			continue;
790
		if (first) {
791
			(void)printf("Memory statistics by bucket size\n");
792
			(void)printf(
793
		"    Size   In Use   Free           Requests  HighWater  Couldfree\n");
794
			first = 0;
795
		}
796
		size = 1 << i;
797
		(void)printf("%8d %8llu %6llu %18llu %7llu %10llu\n", size,
798
			(unsigned long long)(kp->kb_total - kp->kb_totalfree),
799
			(unsigned long long)kp->kb_totalfree,
800
			(unsigned long long)kp->kb_calls,
801
			(unsigned long long)kp->kb_highwat,
802
			(unsigned long long)kp->kb_couldfree);
803
		totfree += size * kp->kb_totalfree;
804
	}
805
806
	/*
807
	 * If kmem statistics are not being gathered by the kernel,
808
	 * first will still be 1.
809
	 */
810
	if (first) {
811
		printf(
812
		    "Kmem statistics are not being gathered by the kernel.\n");
813
		return;
814
	}
815
816
	if (memf == NULL && nlistf == NULL) {
817
		memset(kmemstats, 0, sizeof(kmemstats));
818
		for (i = 0; i < M_LAST; i++) {
819
			mib[0] = CTL_KERN;
820
			mib[1] = KERN_MALLOCSTATS;
821
			mib[2] = KERN_MALLOC_KMEMSTATS;
822
			mib[3] = i;
823
			siz = sizeof(struct kmemstats);
824
825
			/*
826
			 * Skip errors -- these are presumed to be unallocated
827
			 * entries.
828
			 */
829
			if (sysctl(mib, 4, &kmemstats[i], &siz, NULL, 0) < 0)
830
				continue;
831
		}
832
	} else {
833
		kread(X_KMEMSTAT, kmemstats, sizeof(kmemstats));
834
	}
835
836
	(void)printf("\nMemory usage type by bucket size\n");
837
	(void)printf("    Size  Type(s)\n");
838
	kp = &buckets[MINBUCKET];
839
	for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) {
840
		if (kp->kb_calls == 0)
841
			continue;
842
		first = 1;
843
		len = 8;
844
		for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
845
			if (ks->ks_calls == 0)
846
				continue;
847
			if ((ks->ks_size & j) == 0)
848
				continue;
849
			name = kmemnames[i] ? kmemnames[i] : "undefined";
850
			len += 2 + strlen(name);
851
			if (first)
852
				printf("%8d  %s", j, name);
853
			else
854
				printf(",");
855
			if (len >= 80) {
856
				printf("\n\t ");
857
				len = 10 + strlen(name);
858
			}
859
			if (!first)
860
				printf(" %s", name);
861
			first = 0;
862
		}
863
		printf("\n");
864
	}
865
866
	(void)printf(
867
	   "\nMemory statistics by type                           Type  Kern\n");
868
	(void)printf(
869
"          Type InUse MemUse HighUse  Limit Requests Limit Limit Size(s)\n");
870
	for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
871
		if (ks->ks_calls == 0)
872
			continue;
873
		(void)printf("%14s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u",
874
		    kmemnames[i] ? kmemnames[i] : "undefined",
875
		    ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
876
		    (ks->ks_maxused + 1023) / 1024,
877
		    (ks->ks_limit + 1023) / 1024, ks->ks_calls,
878
		    ks->ks_limblocks, ks->ks_mapblocks);
879
		first = 1;
880
		for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
881
			if ((ks->ks_size & j) == 0)
882
				continue;
883
			if (first)
884
				printf("  %d", j);
885
			else
886
				printf(",%d", j);
887
			first = 0;
888
		}
889
		printf("\n");
890
		totuse += ks->ks_memuse;
891
		totreq += ks->ks_calls;
892
	}
893
	(void)printf("\nMemory Totals:  In Use    Free    Requests\n");
894
	(void)printf("              %7luK %6luK    %8llu\n",
895
	     (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq);
896
}
897
898
static void
899
print_pool(struct kinfo_pool *pp, char *name)
900
{
901
	static int first = 1;
902
	char maxp[32];
903
	int ovflw;
904
905
	if (first) {
906
		(void)printf("Memory resource pool statistics\n");
907
		(void)printf(
908
		    "%-11s%5s%9s%5s%9s%6s%6s%6s%6s%6s%6s%5s\n",
909
		    "Name",
910
		    "Size",
911
		    "Requests",
912
		    "Fail",
913
		    "InUse",
914
		    "Pgreq",
915
		    "Pgrel",
916
		    "Npage",
917
		    "Hiwat",
918
		    "Minpg",
919
		    "Maxpg",
920
		    "Idle");
921
		first = 0;
922
	}
923
924
	/* Skip unused pools unless verbose output. */
925
	if (pp->pr_nget == 0 && !verbose)
926
		return;
927
928
	if (pp->pr_maxpages == UINT_MAX)
929
		snprintf(maxp, sizeof maxp, "inf");
930
	else
931
		snprintf(maxp, sizeof maxp, "%u", pp->pr_maxpages);
932
/*
933
 * Print single word.  `ovflow' is number of characters didn't fit
934
 * on the last word.  `fmt' is a format string to print this word.
935
 * It must contain asterisk for field width.  `width' is a width
936
 * occupied by this word.  `fixed' is a number of constant chars in
937
 * `fmt'.  `val' is a value to be printed using format string `fmt'.
938
 */
939
#define	PRWORD(ovflw, fmt, width, fixed, val) do {	\
940
	(ovflw) += printf((fmt),			\
941
	    (width) - (fixed) - (ovflw) > 0 ?		\
942
	    (width) - (fixed) - (ovflw) : 0,		\
943
	    (val)) - (width);				\
944
	if ((ovflw) < 0)				\
945
		(ovflw) = 0;				\
946
} while (/* CONSTCOND */0)
947
948
	ovflw = 0;
949
	PRWORD(ovflw, "%-*s", 11, 0, name);
950
	PRWORD(ovflw, " %*u", 5, 1, pp->pr_size);
951
	PRWORD(ovflw, " %*lu", 9, 1, pp->pr_nget);
952
	PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nfail);
953
	PRWORD(ovflw, " %*lu", 9, 1, pp->pr_nget - pp->pr_nput);
954
	PRWORD(ovflw, " %*lu", 6, 1, pp->pr_npagealloc);
955
	PRWORD(ovflw, " %*lu", 6, 1, pp->pr_npagefree);
956
	PRWORD(ovflw, " %*d", 6, 1, pp->pr_npages);
957
	PRWORD(ovflw, " %*d", 6, 1, pp->pr_hiwat);
958
	PRWORD(ovflw, " %*d", 6, 1, pp->pr_minpages);
959
	PRWORD(ovflw, " %*s", 6, 1, maxp);
960
	PRWORD(ovflw, " %*lu\n", 5, 1, pp->pr_nidle);
961
}
962
963
static void dopool_kvm(void);
964
static void dopool_sysctl(void);
965
966
void
967
dopool(void)
968
{
969
	if (nlistf == NULL && memf == NULL)
970
		dopool_sysctl();
971
	else
972
		dopool_kvm();
973
}
974
975
void
976
dopool_sysctl(void)
977
{
978
	int mib[4], npools, i;
979
	long total = 0, inuse = 0;
980
	struct kinfo_pool pool;
981
	size_t size;
982
983
	mib[0] = CTL_KERN;
984
	mib[1] = KERN_POOL;
985
	mib[2] = KERN_POOL_NPOOLS;
986
	size = sizeof(npools);
987
	if (sysctl(mib, 3, &npools, &size, NULL, 0) < 0) {
988
		warn("can't figure out number of pools in kernel");
989
		return;
990
	}
991
992
	for (i = 1; npools; i++) {
993
		char name[32];
994
995
		mib[0] = CTL_KERN;
996
		mib[1] = KERN_POOL;
997
		mib[2] = KERN_POOL_POOL;
998
		mib[3] = i;
999
		size = sizeof(pool);
1000
		if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) {
1001
			if (errno == ENOENT)
1002
				continue;
1003
			warn("error getting pool");
1004
			return;
1005
		}
1006
		npools--;
1007
		mib[2] = KERN_POOL_NAME;
1008
		size = sizeof(name);
1009
		if (sysctl(mib, 4, &name, &size, NULL, 0) < 0) {
1010
			warn("error getting pool name");
1011
			return;
1012
		}
1013
		print_pool(&pool, name);
1014
1015
		inuse += (pool.pr_nget - pool.pr_nput) * pool.pr_size;
1016
		total += pool.pr_npages * pool.pr_pgsize;
1017
	}
1018
1019
	inuse /= 1024;
1020
	total /= 1024;
1021
	printf("\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n",
1022
	    inuse, total, (double)(100 * inuse) / total);
1023
}
1024
1025
void
1026
dopool_kvm(void)
1027
{
1028
	SIMPLEQ_HEAD(,pool) pool_head;
1029
	struct pool pool, *pp = &pool;
1030
	struct kinfo_pool pi;
1031
	long total = 0, inuse = 0;
1032
	u_long addr;
1033
1034
	kread(X_POOLHEAD, &pool_head, sizeof(pool_head));
1035
	addr = (u_long)SIMPLEQ_FIRST(&pool_head);
1036
1037
	while (addr != 0) {
1038
		char name[32];
1039
1040
		if (kvm_read(kd, addr, (void *)pp, sizeof *pp) != sizeof *pp) {
1041
			(void)fprintf(stderr,
1042
			    "vmstat: pool chain trashed: %s\n",
1043
			    kvm_geterr(kd));
1044
			exit(1);
1045
		}
1046
		if (kvm_read(kd, (u_long)pp->pr_wchan, name, sizeof name) < 0) {
1047
			(void)fprintf(stderr,
1048
			    "vmstat: pool name trashed: %s\n",
1049
			    kvm_geterr(kd));
1050
			exit(1);
1051
		}
1052
		name[31] = '\0';
1053
1054
		memset(&pi, 0, sizeof(pi));
1055
		pi.pr_size = pp->pr_size;
1056
		pi.pr_pgsize = pp->pr_pgsize;
1057
		pi.pr_itemsperpage = pp->pr_itemsperpage;
1058
		pi.pr_npages = pp->pr_npages;
1059
		pi.pr_minpages = pp->pr_minpages;
1060
		pi.pr_maxpages = pp->pr_maxpages;
1061
		pi.pr_hardlimit = pp->pr_hardlimit;
1062
		pi.pr_nout = pp->pr_nout;
1063
		pi.pr_nitems = pp->pr_nitems;
1064
		pi.pr_nget = pp->pr_nget;
1065
		pi.pr_nput = pp->pr_nput;
1066
		pi.pr_nfail = pp->pr_nfail;
1067
		pi.pr_npagealloc = pp->pr_npagealloc;
1068
		pi.pr_npagefree = pp->pr_npagefree;
1069
		pi.pr_hiwat = pp->pr_hiwat;
1070
		pi.pr_nidle = pp->pr_nidle;
1071
1072
		print_pool(&pi, name);
1073
1074
		inuse += (pi.pr_nget - pi.pr_nput) * pi.pr_size;
1075
		total += pi.pr_npages * pi.pr_pgsize;
1076
1077
		addr = (u_long)SIMPLEQ_NEXT(pp, pr_poollist);
1078
	}
1079
1080
	inuse /= 1024;
1081
	total /= 1024;
1082
	printf("\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n",
1083
	    inuse, total, (double)(100 * inuse) / total);
1084
}
1085
1086
/*
1087
 * kread reads something from the kernel, given its nlist index.
1088
 */
1089
void
1090
kread(int nlx, void *addr, size_t size)
1091
{
1092
	char *sym;
1093
1094
	if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
1095
		sym = namelist[nlx].n_name;
1096
		if (*sym == '_')
1097
			++sym;
1098
		errx(1, "symbol %s not defined", sym);
1099
	}
1100
	if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) {
1101
		sym = namelist[nlx].n_name;
1102
		if (*sym == '_')
1103
			++sym;
1104
		errx(1, "%s: %s", sym, kvm_geterr(kd));
1105
	}
1106
}
1107
1108
void
1109
usage(void)
1110
{
1111
	(void)fprintf(stderr, "usage: %s [-fimstvz] [-c count] [-M core] "
1112
	    "[-N system] [-w wait] [disk ...]\n", __progname);
1113
	exit(1);
1114
}