Deleted Added
sdiff udiff text old ( 178063 ) new ( 181881 )
full compact
1/*
2 * Copyright (c) 1980, 1986, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1980, 1986, 1991, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#if 0
41#ifndef lint
42static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93";
43#endif /* not lint */
44#endif
45
46#include <sys/cdefs.h>
47__FBSDID("$FreeBSD: head/usr.bin/vmstat/vmstat.c 178063 2008-04-10 09:56:57Z ru $");
48
49#include <sys/param.h>
50#include <sys/time.h>
51#include <sys/proc.h>
52#include <sys/uio.h>
53#include <sys/namei.h>
54#include <sys/malloc.h>
55#include <sys/signal.h>
56#include <sys/fcntl.h>
57#include <sys/ioctl.h>
58#include <sys/resource.h>
59#include <sys/sysctl.h>
60#include <sys/vmmeter.h>
61
62#include <vm/vm_param.h>
63
64#include <ctype.h>
65#include <devstat.h>
66#include <err.h>
67#include <errno.h>
68#include <kvm.h>
69#include <limits.h>
70#include <memstat.h>
71#include <nlist.h>
72#include <paths.h>
73#include <stdio.h>
74#include <stdlib.h>
75#include <string.h>
76#include <sysexits.h>
77#include <time.h>
78#include <unistd.h>
79#include <libutil.h>
80
81static char da[] = "da";
82
83static struct nlist namelist[] = {
84#define X_CPTIME 0
85 { "_cp_time" },
86#define X_SUM 1
87 { "_cnt" },
88#define X_BOOTTIME 2
89 { "_boottime" },
90#define X_HZ 3
91 { "_hz" },
92#define X_STATHZ 4
93 { "_stathz" },
94#define X_NCHSTATS 5
95 { "_nchstats" },
96#define X_INTRNAMES 6
97 { "_intrnames" },
98#define X_EINTRNAMES 7
99 { "_eintrnames" },
100#define X_INTRCNT 8
101 { "_intrcnt" },
102#define X_EINTRCNT 9
103 { "_eintrcnt" },
104#define X_KMEMSTATS 10
105 { "_kmemstatistics" },
106#define X_KMEMZONES 11
107 { "_kmemzones" },
108#ifdef notyet
109#define X_DEFICIT XXX
110 { "_deficit" },
111#define X_REC XXX
112 { "_rectime" },
113#define X_PGIN XXX
114 { "_pgintime" },
115#define X_XSTATS XXX
116 { "_xstats" },
117#define X_END XXX
118#else
119#define X_END 12
120#endif
121 { "" },
122};
123
124static struct statinfo cur, last;
125static int num_devices, maxshowdevs;
126static long generation;
127static struct device_selection *dev_select;
128static int num_selected;
129static struct devstat_match *matches;
130static int num_matches = 0;
131static int num_devices_specified, num_selections;
132static long select_generation;
133static char **specified_devices;
134static devstat_select_mode select_mode;
135
136static struct vmmeter sum, osum;
137
138static int winlines = 20;
139static int aflag;
140static int nflag;
141static int Pflag;
142static int hflag;
143
144static kvm_t *kd;
145
146#define FORKSTAT 0x01
147#define INTRSTAT 0x02
148#define MEMSTAT 0x04
149#define SUMSTAT 0x08
150#define TIMESTAT 0x10
151#define VMSTAT 0x20
152#define ZMEMSTAT 0x40
153
154static void cpustats(void);
155static void pcpustats(int, u_long, int);
156static void devstats(void);
157static void doforkst(void);
158static void dointr(void);
159static void dosum(void);
160static void dovmstat(unsigned int, int);
161static void domemstat_malloc(void);
162static void domemstat_zone(void);
163static void kread(int, void *, size_t);
164static void kreado(int, void *, size_t, size_t);
165static char *kgetstr(const char *);
166static void needhdr(int);
167static void printhdr(int, u_long);
168static void usage(void);
169
170static long pct(long, long);
171static long getuptime(void);
172
173static char **getdrivedata(char **);
174
175int
176main(int argc, char *argv[])
177{
178 int c, todo;
179 unsigned int interval;
180 int reps;
181 char *memf, *nlistf;
182 char errbuf[_POSIX2_LINE_MAX];
183
184 memf = nlistf = NULL;
185 interval = reps = todo = 0;
186 maxshowdevs = 2;
187 hflag = isatty(1);
188 while ((c = getopt(argc, argv, "ac:fhHiM:mN:n:Pp:stw:z")) != -1) {
189 switch (c) {
190 case 'a':
191 aflag++;
192 break;
193 case 'c':
194 reps = atoi(optarg);
195 break;
196 case 'P':
197 Pflag++;
198 break;
199 case 'f':
200 todo |= FORKSTAT;
201 break;
202 case 'h':
203 hflag = 1;
204 break;
205 case 'H':
206 hflag = 0;
207 break;
208 case 'i':
209 todo |= INTRSTAT;
210 break;
211 case 'M':
212 memf = optarg;
213 break;
214 case 'm':
215 todo |= MEMSTAT;
216 break;
217 case 'N':
218 nlistf = optarg;
219 break;
220 case 'n':
221 nflag = 1;
222 maxshowdevs = atoi(optarg);
223 if (maxshowdevs < 0)
224 errx(1, "number of devices %d is < 0",
225 maxshowdevs);
226 break;
227 case 'p':
228 if (devstat_buildmatch(optarg, &matches, &num_matches) != 0)
229 errx(1, "%s", devstat_errbuf);
230 break;
231 case 's':
232 todo |= SUMSTAT;
233 break;
234 case 't':
235#ifdef notyet
236 todo |= TIMESTAT;
237#else
238 errx(EX_USAGE, "sorry, -t is not (re)implemented yet");
239#endif
240 break;
241 case 'w':
242 interval = atoi(optarg);
243 break;
244 case 'z':
245 todo |= ZMEMSTAT;
246 break;
247 case '?':
248 default:
249 usage();
250 }
251 }
252 argc -= optind;
253 argv += optind;
254
255 if (todo == 0)
256 todo = VMSTAT;
257
258 if (memf != NULL) {
259 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
260 if (kd == NULL)
261 errx(1, "kvm_openfiles: %s", errbuf);
262 }
263
264 if (kd != NULL && (c = kvm_nlist(kd, namelist)) != 0) {
265 if (c > 0) {
266 warnx("undefined symbols:");
267 for (c = 0;
268 c < (int)(sizeof(namelist)/sizeof(namelist[0]));
269 c++)
270 if (namelist[c].n_type == 0)
271 (void)fprintf(stderr, " %s",
272 namelist[c].n_name);
273 (void)fputc('\n', stderr);
274 } else
275 warnx("kvm_nlist: %s", kvm_geterr(kd));
276 exit(1);
277 }
278 if (kd && Pflag)
279 errx(1, "Cannot use -P with crash dumps");
280
281 if (todo & VMSTAT) {
282 struct winsize winsize;
283
284 /*
285 * Make sure that the userland devstat version matches the
286 * kernel devstat version. If not, exit and print a
287 * message informing the user of his mistake.
288 */
289 if (devstat_checkversion(NULL) < 0)
290 errx(1, "%s", devstat_errbuf);
291
292
293 argv = getdrivedata(argv);
294 winsize.ws_row = 0;
295 (void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize);
296 if (winsize.ws_row > 0)
297 winlines = winsize.ws_row;
298
299 }
300
301#define BACKWARD_COMPATIBILITY
302#ifdef BACKWARD_COMPATIBILITY
303 if (*argv) {
304 interval = atoi(*argv);
305 if (*++argv)
306 reps = atoi(*argv);
307 }
308#endif
309
310 if (interval) {
311 if (!reps)
312 reps = -1;
313 } else if (reps)
314 interval = 1;
315
316 if (todo & FORKSTAT)
317 doforkst();
318 if (todo & MEMSTAT)
319 domemstat_malloc();
320 if (todo & ZMEMSTAT)
321 domemstat_zone();
322 if (todo & SUMSTAT)
323 dosum();
324#ifdef notyet
325 if (todo & TIMESTAT)
326 dotimes();
327#endif
328 if (todo & INTRSTAT)
329 dointr();
330 if (todo & VMSTAT)
331 dovmstat(interval, reps);
332 exit(0);
333}
334
335static int
336mysysctl(const char *name, void *oldp, size_t *oldlenp,
337 void *newp, size_t newlen)
338{
339 int error;
340
341 error = sysctlbyname(name, oldp, oldlenp, newp, newlen);
342 if (error != 0 && errno != ENOMEM)
343 err(1, "sysctl(%s)", name);
344 return (error);
345}
346
347static char **
348getdrivedata(char **argv)
349{
350 if ((num_devices = devstat_getnumdevs(NULL)) < 0)
351 errx(1, "%s", devstat_errbuf);
352
353 cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
354 last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
355 bzero(cur.dinfo, sizeof(struct devinfo));
356 bzero(last.dinfo, sizeof(struct devinfo));
357
358 if (devstat_getdevs(NULL, &cur) == -1)
359 errx(1, "%s", devstat_errbuf);
360
361 num_devices = cur.dinfo->numdevs;
362 generation = cur.dinfo->generation;
363
364 specified_devices = (char **)malloc(sizeof(char *));
365 for (num_devices_specified = 0; *argv; ++argv) {
366 if (isdigit(**argv))
367 break;
368 num_devices_specified++;
369 specified_devices = (char **)realloc(specified_devices,
370 sizeof(char *) *
371 num_devices_specified);
372 specified_devices[num_devices_specified - 1] = *argv;
373 }
374 dev_select = NULL;
375
376 if (nflag == 0 && maxshowdevs < num_devices_specified)
377 maxshowdevs = num_devices_specified;
378
379 /*
380 * People are generally only interested in disk statistics when
381 * they're running vmstat. So, that's what we're going to give
382 * them if they don't specify anything by default. We'll also give
383 * them any other random devices in the system so that we get to
384 * maxshowdevs devices, if that many devices exist. If the user
385 * specifies devices on the command line, either through a pattern
386 * match or by naming them explicitly, we will give the user only
387 * those devices.
388 */
389 if ((num_devices_specified == 0) && (num_matches == 0)) {
390 if (devstat_buildmatch(da, &matches, &num_matches) != 0)
391 errx(1, "%s", devstat_errbuf);
392
393 select_mode = DS_SELECT_ADD;
394 } else
395 select_mode = DS_SELECT_ONLY;
396
397 /*
398 * At this point, selectdevs will almost surely indicate that the
399 * device list has changed, so we don't look for return values of 0
400 * or 1. If we get back -1, though, there is an error.
401 */
402 if (devstat_selectdevs(&dev_select, &num_selected, &num_selections,
403 &select_generation, generation, cur.dinfo->devices,
404 num_devices, matches, num_matches, specified_devices,
405 num_devices_specified, select_mode,
406 maxshowdevs, 0) == -1)
407 errx(1, "%s", devstat_errbuf);
408
409 return(argv);
410}
411
412static long
413getuptime(void)
414{
415 struct timespec sp;
416 time_t uptime;
417
418 (void)clock_gettime(CLOCK_MONOTONIC, &sp);
419 uptime = sp.tv_sec;
420 if (uptime <= 0 || uptime > 60*60*24*365*10)
421 errx(1, "time makes no sense; namelist must be wrong");
422
423 return(uptime);
424}
425
426static void
427fill_vmmeter(struct vmmeter *vmmp)
428{
429 if (kd != NULL) {
430 kread(X_SUM, vmmp, sizeof(*vmmp));
431 } else {
432 size_t size = sizeof(unsigned int);
433#define GET_VM_STATS(cat, name) \
434 mysysctl("vm.stats." #cat "." #name, &vmmp->name, &size, NULL, 0)
435 /* sys */
436 GET_VM_STATS(sys, v_swtch);
437 GET_VM_STATS(sys, v_trap);
438 GET_VM_STATS(sys, v_syscall);
439 GET_VM_STATS(sys, v_intr);
440 GET_VM_STATS(sys, v_soft);
441
442 /* vm */
443 GET_VM_STATS(vm, v_vm_faults);
444 GET_VM_STATS(vm, v_cow_faults);
445 GET_VM_STATS(vm, v_cow_optim);
446 GET_VM_STATS(vm, v_zfod);
447 GET_VM_STATS(vm, v_ozfod);
448 GET_VM_STATS(vm, v_swapin);
449 GET_VM_STATS(vm, v_swapout);
450 GET_VM_STATS(vm, v_swappgsin);
451 GET_VM_STATS(vm, v_swappgsout);
452 GET_VM_STATS(vm, v_vnodein);
453 GET_VM_STATS(vm, v_vnodeout);
454 GET_VM_STATS(vm, v_vnodepgsin);
455 GET_VM_STATS(vm, v_vnodepgsout);
456 GET_VM_STATS(vm, v_intrans);
457 GET_VM_STATS(vm, v_reactivated);
458 GET_VM_STATS(vm, v_pdwakeups);
459 GET_VM_STATS(vm, v_pdpages);
460 GET_VM_STATS(vm, v_tcached);
461 GET_VM_STATS(vm, v_dfree);
462 GET_VM_STATS(vm, v_pfree);
463 GET_VM_STATS(vm, v_tfree);
464 GET_VM_STATS(vm, v_page_size);
465 GET_VM_STATS(vm, v_page_count);
466 GET_VM_STATS(vm, v_free_reserved);
467 GET_VM_STATS(vm, v_free_target);
468 GET_VM_STATS(vm, v_free_min);
469 GET_VM_STATS(vm, v_free_count);
470 GET_VM_STATS(vm, v_wire_count);
471 GET_VM_STATS(vm, v_active_count);
472 GET_VM_STATS(vm, v_inactive_target);
473 GET_VM_STATS(vm, v_inactive_count);
474 GET_VM_STATS(vm, v_cache_count);
475 GET_VM_STATS(vm, v_cache_min);
476 GET_VM_STATS(vm, v_cache_max);
477 GET_VM_STATS(vm, v_pageout_free_min);
478 GET_VM_STATS(vm, v_interrupt_free_min);
479 /*GET_VM_STATS(vm, v_free_severe);*/
480 GET_VM_STATS(vm, v_forks);
481 GET_VM_STATS(vm, v_vforks);
482 GET_VM_STATS(vm, v_rforks);
483 GET_VM_STATS(vm, v_kthreads);
484 GET_VM_STATS(vm, v_forkpages);
485 GET_VM_STATS(vm, v_vforkpages);
486 GET_VM_STATS(vm, v_rforkpages);
487 GET_VM_STATS(vm, v_kthreadpages);
488#undef GET_VM_STATS
489 }
490}
491
492static void
493fill_vmtotal(struct vmtotal *vmtp)
494{
495 if (kd != NULL) {
496 /* XXX fill vmtp */
497 errx(1, "not implemented");
498 } else {
499 size_t size = sizeof(*vmtp);
500 mysysctl("vm.vmtotal", vmtp, &size, NULL, 0);
501 if (size != sizeof(*vmtp))
502 errx(1, "vm.total size mismatch");
503 }
504}
505
506/* Determine how many cpu columns, and what index they are in kern.cp_times */
507static int
508getcpuinfo(u_long *maskp, int *maxidp)
509{
510 int maxcpu;
511 int maxid;
512 int ncpus;
513 int i, j;
514 int empty;
515 size_t size;
516 long *times;
517 u_long mask;
518
519 if (kd != NULL)
520 errx(1, "not implemented");
521 mask = 0;
522 ncpus = 0;
523 size = sizeof(maxcpu);
524 mysysctl("kern.smp.maxcpus", &maxcpu, &size, NULL, 0);
525 if (size != sizeof(maxcpu))
526 errx(1, "sysctl kern.smp.maxcpus");
527 size = sizeof(long) * maxcpu * CPUSTATES;
528 times = malloc(size);
529 if (times == NULL)
530 err(1, "malloc %zd bytes", size);
531 mysysctl("kern.cp_times", times, &size, NULL, 0);
532 maxid = (size / CPUSTATES / sizeof(long)) - 1;
533 for (i = 0; i <= maxid; i++) {
534 empty = 1;
535 for (j = 0; empty && j < CPUSTATES; j++) {
536 if (times[i * CPUSTATES + j] != 0)
537 empty = 0;
538 }
539 if (!empty) {
540 mask |= (1ul << i);
541 ncpus++;
542 }
543 }
544 if (maskp)
545 *maskp = mask;
546 if (maxidp)
547 *maxidp = maxid;
548 return (ncpus);
549}
550
551
552static void
553prthuman(u_int64_t val, int size)
554{
555 char buf[10];
556 int flags;
557
558 if (size < 5 || size > 9)
559 errx(1, "doofus");
560 flags = HN_B | HN_NOSPACE | HN_DECIMAL;
561 humanize_number(buf, size, val, "", HN_AUTOSCALE, flags);
562 printf("%*s", size, buf);
563}
564
565static int hz, hdrcnt;
566
567static long *cur_cp_times;
568static long *last_cp_times;
569static size_t size_cp_times;
570
571static void
572dovmstat(unsigned int interval, int reps)
573{
574 struct vmtotal total;
575 time_t uptime, halfuptime;
576 struct devinfo *tmp_dinfo;
577 size_t size;
578 int ncpus, maxid;
579 u_long cpumask;
580
581 uptime = getuptime();
582 halfuptime = uptime / 2;
583 (void)signal(SIGCONT, needhdr);
584
585 if (kd != NULL) {
586 if (namelist[X_STATHZ].n_type != 0 &&
587 namelist[X_STATHZ].n_value != 0)
588 kread(X_STATHZ, &hz, sizeof(hz));
589 if (!hz)
590 kread(X_HZ, &hz, sizeof(hz));
591 } else {
592 struct clockinfo clockrate;
593
594 size = sizeof(clockrate);
595 mysysctl("kern.clockrate", &clockrate, &size, NULL, 0);
596 if (size != sizeof(clockrate))
597 errx(1, "clockrate size mismatch");
598 hz = clockrate.hz;
599 }
600
601 if (Pflag) {
602 ncpus = getcpuinfo(&cpumask, &maxid);
603 size_cp_times = sizeof(long) * (maxid + 1) * CPUSTATES;
604 cur_cp_times = malloc(size_cp_times);
605 last_cp_times = malloc(size_cp_times);
606 bzero(cur_cp_times, size_cp_times);
607 bzero(last_cp_times, size_cp_times);
608 }
609 for (hdrcnt = 1;;) {
610 if (!--hdrcnt)
611 printhdr(ncpus, cpumask);
612 if (kd != NULL) {
613 kread(X_CPTIME, cur.cp_time, sizeof(cur.cp_time));
614 } else {
615 size = sizeof(cur.cp_time);
616 mysysctl("kern.cp_time", &cur.cp_time, &size, NULL, 0);
617 if (size != sizeof(cur.cp_time))
618 errx(1, "cp_time size mismatch");
619 }
620 if (Pflag) {
621 size = size_cp_times;
622 mysysctl("kern.cp_times", cur_cp_times, &size, NULL, 0);
623 if (size != size_cp_times)
624 errx(1, "cp_times mismatch");
625 }
626
627 tmp_dinfo = last.dinfo;
628 last.dinfo = cur.dinfo;
629 cur.dinfo = tmp_dinfo;
630 last.snap_time = cur.snap_time;
631
632 /*
633 * Here what we want to do is refresh our device stats.
634 * getdevs() returns 1 when the device list has changed.
635 * If the device list has changed, we want to go through
636 * the selection process again, in case a device that we
637 * were previously displaying has gone away.
638 */
639 switch (devstat_getdevs(NULL, &cur)) {
640 case -1:
641 errx(1, "%s", devstat_errbuf);
642 break;
643 case 1: {
644 int retval;
645
646 num_devices = cur.dinfo->numdevs;
647 generation = cur.dinfo->generation;
648
649 retval = devstat_selectdevs(&dev_select, &num_selected,
650 &num_selections, &select_generation,
651 generation, cur.dinfo->devices,
652 num_devices, matches, num_matches,
653 specified_devices,
654 num_devices_specified, select_mode,
655 maxshowdevs, 0);
656 switch (retval) {
657 case -1:
658 errx(1, "%s", devstat_errbuf);
659 break;
660 case 1:
661 printhdr(ncpus, cpumask);
662 break;
663 default:
664 break;
665 }
666 }
667 default:
668 break;
669 }
670
671 fill_vmmeter(&sum);
672 fill_vmtotal(&total);
673 (void)printf("%2d %1d %1d",
674 total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
675#define vmstat_pgtok(a) ((a) * (sum.v_page_size >> 10))
676#define rate(x) (((x) + halfuptime) / uptime) /* round */
677 if (hflag) {
678 printf(" ");
679 prthuman(total.t_avm * (u_int64_t)sum.v_page_size, 7);
680 printf(" ");
681 prthuman(total.t_free * (u_int64_t)sum.v_page_size, 6);
682 printf(" ");
683 } else {
684 printf(" %7d ", vmstat_pgtok(total.t_avm));
685 printf(" %6d ", vmstat_pgtok(total.t_free));
686 }
687 (void)printf("%5lu ",
688 (unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults));
689 (void)printf("%3lu ",
690 (unsigned long)rate(sum.v_reactivated - osum.v_reactivated));
691 (void)printf("%3lu ",
692 (unsigned long)rate(sum.v_swapin + sum.v_vnodein -
693 (osum.v_swapin + osum.v_vnodein)));
694 (void)printf("%3lu ",
695 (unsigned long)rate(sum.v_swapout + sum.v_vnodeout -
696 (osum.v_swapout + osum.v_vnodeout)));
697 (void)printf("%5lu ",
698 (unsigned long)rate(sum.v_tfree - osum.v_tfree));
699 (void)printf("%3lu ",
700 (unsigned long)rate(sum.v_pdpages - osum.v_pdpages));
701 devstats();
702 (void)printf("%4lu %4lu %4lu",
703 (unsigned long)rate(sum.v_intr - osum.v_intr),
704 (unsigned long)rate(sum.v_syscall - osum.v_syscall),
705 (unsigned long)rate(sum.v_swtch - osum.v_swtch));
706 if (Pflag)
707 pcpustats(ncpus, cpumask, maxid);
708 else
709 cpustats();
710 (void)printf("\n");
711 (void)fflush(stdout);
712 if (reps >= 0 && --reps <= 0)
713 break;
714 osum = sum;
715 uptime = interval;
716 /*
717 * We round upward to avoid losing low-frequency events
718 * (i.e., >= 1 per interval but < 1 per second).
719 */
720 if (interval != 1)
721 halfuptime = (uptime + 1) / 2;
722 else
723 halfuptime = 0;
724 (void)sleep(interval);
725 }
726}
727
728static void
729printhdr(int ncpus, u_long cpumask)
730{
731 int i, num_shown;
732
733 num_shown = (num_selected < maxshowdevs) ? num_selected : maxshowdevs;
734 (void)printf(" procs memory page%*s", 19, "");
735 if (num_shown > 1)
736 (void)printf(" disks %*s", num_shown * 4 - 7, "");
737 else if (num_shown == 1)
738 (void)printf("disk");
739 (void)printf(" faults ");
740 if (Pflag) {
741 for (i = 0; i < ncpus; i++) {
742 if (cpumask & (1ul << i))
743 printf("cpu%-2d ", i);
744 }
745 printf("\n");
746 } else
747 printf("cpu\n");
748 (void)printf(" r b w avm fre flt re pi po fr sr ");
749 for (i = 0; i < num_devices; i++)
750 if ((dev_select[i].selected)
751 && (dev_select[i].selected <= maxshowdevs))
752 (void)printf("%c%c%d ", dev_select[i].device_name[0],
753 dev_select[i].device_name[1],
754 dev_select[i].unit_number);
755 (void)printf(" in sy cs");
756 if (Pflag) {
757 for (i = 0; i < ncpus; i++)
758 printf(" us sy id");
759 printf("\n");
760 } else
761 printf(" us sy id\n");
762 hdrcnt = winlines - 2;
763}
764
765/*
766 * Force a header to be prepended to the next output.
767 */
768static void
769needhdr(int dummy __unused)
770{
771
772 hdrcnt = 1;
773}
774
775#ifdef notyet
776static void
777dotimes(void)
778{
779 unsigned int pgintime, rectime;
780
781 kread(X_REC, &rectime, sizeof(rectime));
782 kread(X_PGIN, &pgintime, sizeof(pgintime));
783 kread(X_SUM, &sum, sizeof(sum));
784 (void)printf("%u reclaims, %u total time (usec)\n",
785 sum.v_pgrec, rectime);
786 (void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec);
787 (void)printf("\n");
788 (void)printf("%u page ins, %u total time (msec)\n",
789 sum.v_pgin, pgintime / 10);
790 (void)printf("average: %8.1f msec / page in\n",
791 pgintime / (sum.v_pgin * 10.0));
792}
793#endif
794
795static long
796pct(long top, long bot)
797{
798 long ans;
799
800 if (bot == 0)
801 return(0);
802 ans = (quad_t)top * 100 / bot;
803 return (ans);
804}
805
806#define PCT(top, bot) pct((long)(top), (long)(bot))
807
808static void
809dosum(void)
810{
811 struct nchstats lnchstats;
812 long nchtotal;
813
814 fill_vmmeter(&sum);
815 (void)printf("%9u cpu context switches\n", sum.v_swtch);
816 (void)printf("%9u device interrupts\n", sum.v_intr);
817 (void)printf("%9u software interrupts\n", sum.v_soft);
818 (void)printf("%9u traps\n", sum.v_trap);
819 (void)printf("%9u system calls\n", sum.v_syscall);
820 (void)printf("%9u kernel threads created\n", sum.v_kthreads);
821 (void)printf("%9u fork() calls\n", sum.v_forks);
822 (void)printf("%9u vfork() calls\n", sum.v_vforks);
823 (void)printf("%9u rfork() calls\n", sum.v_rforks);
824 (void)printf("%9u swap pager pageins\n", sum.v_swapin);
825 (void)printf("%9u swap pager pages paged in\n", sum.v_swappgsin);
826 (void)printf("%9u swap pager pageouts\n", sum.v_swapout);
827 (void)printf("%9u swap pager pages paged out\n", sum.v_swappgsout);
828 (void)printf("%9u vnode pager pageins\n", sum.v_vnodein);
829 (void)printf("%9u vnode pager pages paged in\n", sum.v_vnodepgsin);
830 (void)printf("%9u vnode pager pageouts\n", sum.v_vnodeout);
831 (void)printf("%9u vnode pager pages paged out\n", sum.v_vnodepgsout);
832 (void)printf("%9u page daemon wakeups\n", sum.v_pdwakeups);
833 (void)printf("%9u pages examined by the page daemon\n", sum.v_pdpages);
834 (void)printf("%9u pages reactivated\n", sum.v_reactivated);
835 (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults);
836 (void)printf("%9u copy-on-write optimized faults\n", sum.v_cow_optim);
837 (void)printf("%9u zero fill pages zeroed\n", sum.v_zfod);
838 (void)printf("%9u zero fill pages prezeroed\n", sum.v_ozfod);
839 (void)printf("%9u intransit blocking page faults\n", sum.v_intrans);
840 (void)printf("%9u total VM faults taken\n", sum.v_vm_faults);
841 (void)printf("%9u pages affected by kernel thread creation\n", sum.v_kthreadpages);
842 (void)printf("%9u pages affected by fork()\n", sum.v_forkpages);
843 (void)printf("%9u pages affected by vfork()\n", sum.v_vforkpages);
844 (void)printf("%9u pages affected by rfork()\n", sum.v_rforkpages);
845 (void)printf("%9u pages cached\n", sum.v_tcached);
846 (void)printf("%9u pages freed\n", sum.v_tfree);
847 (void)printf("%9u pages freed by daemon\n", sum.v_dfree);
848 (void)printf("%9u pages freed by exiting processes\n", sum.v_pfree);
849 (void)printf("%9u pages active\n", sum.v_active_count);
850 (void)printf("%9u pages inactive\n", sum.v_inactive_count);
851 (void)printf("%9u pages in VM cache\n", sum.v_cache_count);
852 (void)printf("%9u pages wired down\n", sum.v_wire_count);
853 (void)printf("%9u pages free\n", sum.v_free_count);
854 (void)printf("%9u bytes per page\n", sum.v_page_size);
855 if (kd != NULL) {
856 kread(X_NCHSTATS, &lnchstats, sizeof(lnchstats));
857 } else {
858 size_t size = sizeof(lnchstats);
859 mysysctl("vfs.cache.nchstats", &lnchstats, &size, NULL, 0);
860 if (size != sizeof(lnchstats))
861 errx(1, "vfs.cache.nchstats size mismatch");
862 }
863 nchtotal = lnchstats.ncs_goodhits + lnchstats.ncs_neghits +
864 lnchstats.ncs_badhits + lnchstats.ncs_falsehits +
865 lnchstats.ncs_miss + lnchstats.ncs_long;
866 (void)printf("%9ld total name lookups\n", nchtotal);
867 (void)printf(
868 "%9s cache hits (%ld%% pos + %ld%% neg) system %ld%% per-directory\n",
869 "", PCT(lnchstats.ncs_goodhits, nchtotal),
870 PCT(lnchstats.ncs_neghits, nchtotal),
871 PCT(lnchstats.ncs_pass2, nchtotal));
872 (void)printf("%9s deletions %ld%%, falsehits %ld%%, toolong %ld%%\n", "",
873 PCT(lnchstats.ncs_badhits, nchtotal),
874 PCT(lnchstats.ncs_falsehits, nchtotal),
875 PCT(lnchstats.ncs_long, nchtotal));
876}
877
878static void
879doforkst(void)
880{
881 fill_vmmeter(&sum);
882 (void)printf("%u forks, %u pages, average %.2f\n",
883 sum.v_forks, sum.v_forkpages,
884 sum.v_forks == 0 ? 0.0 :
885 (double)sum.v_forkpages / sum.v_forks);
886 (void)printf("%u vforks, %u pages, average %.2f\n",
887 sum.v_vforks, sum.v_vforkpages,
888 sum.v_vforks == 0 ? 0.0 :
889 (double)sum.v_vforkpages / sum.v_vforks);
890 (void)printf("%u rforks, %u pages, average %.2f\n",
891 sum.v_rforks, sum.v_rforkpages,
892 sum.v_rforks == 0 ? 0.0 :
893 (double)sum.v_rforkpages / sum.v_rforks);
894}
895
896static void
897devstats(void)
898{
899 int dn, state;
900 long double transfers_per_second;
901 long double busy_seconds;
902 long tmp;
903
904 for (state = 0; state < CPUSTATES; ++state) {
905 tmp = cur.cp_time[state];
906 cur.cp_time[state] -= last.cp_time[state];
907 last.cp_time[state] = tmp;
908 }
909
910 busy_seconds = cur.snap_time - last.snap_time;
911
912 for (dn = 0; dn < num_devices; dn++) {
913 int di;
914
915 if ((dev_select[dn].selected == 0)
916 || (dev_select[dn].selected > maxshowdevs))
917 continue;
918
919 di = dev_select[dn].position;
920
921 if (devstat_compute_statistics(&cur.dinfo->devices[di],
922 &last.dinfo->devices[di], busy_seconds,
923 DSM_TRANSFERS_PER_SECOND, &transfers_per_second,
924 DSM_NONE) != 0)
925 errx(1, "%s", devstat_errbuf);
926
927 (void)printf("%3.0Lf ", transfers_per_second);
928 }
929}
930
931static void
932percent(double pct, int *over)
933{
934 char buf[10];
935 int l;
936
937 l = snprintf(buf, sizeof(buf), "%.0f", pct);
938 if (l == 1 && *over) {
939 printf("%s", buf);
940 (*over)--;
941 } else
942 printf("%2s", buf);
943 if (l > 2)
944 (*over)++;
945}
946
947static void
948cpustats(void)
949{
950 int state, over;
951 double lpct, total;
952
953 total = 0;
954 for (state = 0; state < CPUSTATES; ++state)
955 total += cur.cp_time[state];
956 if (total)
957 lpct = 100.0 / total;
958 else
959 lpct = 0.0;
960 over = 0;
961 printf(" ");
962 percent((cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * lpct, &over);
963 printf(" ");
964 percent((cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * lpct, &over);
965 printf(" ");
966 percent(cur.cp_time[CP_IDLE] * lpct, &over);
967}
968
969static void
970pcpustats(int ncpus, u_long cpumask, int maxid)
971{
972 int state, i;
973 double lpct, total;
974 long tmp;
975 int over;
976
977 /* devstats does this for cp_time */
978 for (i = 0; i <= maxid; i++) {
979 if ((cpumask & (1ul << i)) == 0)
980 continue;
981 for (state = 0; state < CPUSTATES; ++state) {
982 tmp = cur_cp_times[i * CPUSTATES + state];
983 cur_cp_times[i * CPUSTATES + state] -= last_cp_times[i * CPUSTATES + state];
984 last_cp_times[i * CPUSTATES + state] = tmp;
985 }
986 }
987
988 over = 0;
989 for (i = 0; i <= maxid; i++) {
990 if ((cpumask & (1ul << i)) == 0)
991 continue;
992 total = 0;
993 for (state = 0; state < CPUSTATES; ++state)
994 total += cur_cp_times[i * CPUSTATES + state];
995 if (total)
996 lpct = 100.0 / total;
997 else
998 lpct = 0.0;
999 printf(" ");
1000 percent((cur_cp_times[i * CPUSTATES + CP_USER] +
1001 cur_cp_times[i * CPUSTATES + CP_NICE]) * lpct, &over);
1002 printf(" ");
1003 percent((cur_cp_times[i * CPUSTATES + CP_SYS] +
1004 cur_cp_times[i * CPUSTATES + CP_INTR]) * lpct, &over);
1005 printf(" ");
1006 percent(cur_cp_times[i * CPUSTATES + CP_IDLE] * lpct, &over);
1007 }
1008}
1009
1010static void
1011dointr(void)
1012{
1013 unsigned long *intrcnt, uptime;
1014 uint64_t inttotal;
1015 size_t clen, inamlen, intrcntlen, istrnamlen;
1016 unsigned int i, nintr;
1017 char *intrname, *tintrname;
1018
1019 uptime = getuptime();
1020 if (kd != NULL) {
1021 intrcntlen = namelist[X_EINTRCNT].n_value -
1022 namelist[X_INTRCNT].n_value;
1023 inamlen = namelist[X_EINTRNAMES].n_value -
1024 namelist[X_INTRNAMES].n_value;
1025 if ((intrcnt = malloc(intrcntlen)) == NULL ||
1026 (intrname = malloc(inamlen)) == NULL)
1027 err(1, "malloc()");
1028 kread(X_INTRCNT, intrcnt, intrcntlen);
1029 kread(X_INTRNAMES, intrname, inamlen);
1030 } else {
1031 for (intrcnt = NULL, intrcntlen = 1024; ; intrcntlen *= 2) {
1032 if ((intrcnt = reallocf(intrcnt, intrcntlen)) == NULL)
1033 err(1, "reallocf()");
1034 if (mysysctl("hw.intrcnt",
1035 intrcnt, &intrcntlen, NULL, 0) == 0)
1036 break;
1037 }
1038 for (intrname = NULL, inamlen = 1024; ; inamlen *= 2) {
1039 if ((intrname = reallocf(intrname, inamlen)) == NULL)
1040 err(1, "reallocf()");
1041 if (mysysctl("hw.intrnames",
1042 intrname, &inamlen, NULL, 0) == 0)
1043 break;
1044 }
1045 }
1046 nintr = intrcntlen / sizeof(unsigned long);
1047 tintrname = intrname;
1048 istrnamlen = strlen("interrupt");
1049 for (i = 0; i < nintr; i++) {
1050 clen = strlen(tintrname);
1051 if (clen > istrnamlen)
1052 istrnamlen = clen;
1053 tintrname += clen + 1;
1054 }
1055 (void)printf("%-*s %20s %10s\n", istrnamlen, "interrupt", "total",
1056 "rate");
1057 inttotal = 0;
1058 for (i = 0; i < nintr; i++) {
1059 if (intrname[0] != '\0' && (*intrcnt != 0 || aflag))
1060 (void)printf("%-*s %20lu %10lu\n", istrnamlen, intrname,
1061 *intrcnt, *intrcnt / uptime);
1062 intrname += strlen(intrname) + 1;
1063 inttotal += *intrcnt++;
1064 }
1065 (void)printf("%-*s %20llu %10llu\n", istrnamlen, "Total",
1066 (long long)inttotal, (long long)(inttotal / uptime));
1067}
1068
1069static void
1070domemstat_malloc(void)
1071{
1072 struct memory_type_list *mtlp;
1073 struct memory_type *mtp;
1074 int error, first, i;
1075
1076 mtlp = memstat_mtl_alloc();
1077 if (mtlp == NULL) {
1078 warn("memstat_mtl_alloc");
1079 return;
1080 }
1081 if (kd == NULL) {
1082 if (memstat_sysctl_malloc(mtlp, 0) < 0) {
1083 warnx("memstat_sysctl_malloc: %s",
1084 memstat_strerror(memstat_mtl_geterror(mtlp)));
1085 return;
1086 }
1087 } else {
1088 if (memstat_kvm_malloc(mtlp, kd) < 0) {
1089 error = memstat_mtl_geterror(mtlp);
1090 if (error == MEMSTAT_ERROR_KVM)
1091 warnx("memstat_kvm_malloc: %s",
1092 kvm_geterr(kd));
1093 else
1094 warnx("memstat_kvm_malloc: %s",
1095 memstat_strerror(error));
1096 }
1097 }
1098 printf("%13s %5s %6s %7s %8s Size(s)\n", "Type", "InUse", "MemUse",
1099 "HighUse", "Requests");
1100 for (mtp = memstat_mtl_first(mtlp); mtp != NULL;
1101 mtp = memstat_mtl_next(mtp)) {
1102 if (memstat_get_numallocs(mtp) == 0 &&
1103 memstat_get_count(mtp) == 0)
1104 continue;
1105 printf("%13s %5lld %5lldK %7s %8lld ",
1106 memstat_get_name(mtp), memstat_get_count(mtp),
1107 ((int64_t)memstat_get_bytes(mtp) + 1023) / 1024, "-",
1108 memstat_get_numallocs(mtp));
1109 first = 1;
1110 for (i = 0; i < 32; i++) {
1111 if (memstat_get_sizemask(mtp) & (1 << i)) {
1112 if (!first)
1113 printf(",");
1114 printf("%d", 1 << (i + 4));
1115 first = 0;
1116 }
1117 }
1118 printf("\n");
1119 }
1120 memstat_mtl_free(mtlp);
1121}
1122
1123static void
1124domemstat_zone(void)
1125{
1126 struct memory_type_list *mtlp;
1127 struct memory_type *mtp;
1128 char name[MEMTYPE_MAXNAME + 1];
1129 int error;
1130
1131 mtlp = memstat_mtl_alloc();
1132 if (mtlp == NULL) {
1133 warn("memstat_mtl_alloc");
1134 return;
1135 }
1136 if (kd == NULL) {
1137 if (memstat_sysctl_uma(mtlp, 0) < 0) {
1138 warnx("memstat_sysctl_uma: %s",
1139 memstat_strerror(memstat_mtl_geterror(mtlp)));
1140 return;
1141 }
1142 } else {
1143 if (memstat_kvm_uma(mtlp, kd) < 0) {
1144 error = memstat_mtl_geterror(mtlp);
1145 if (error == MEMSTAT_ERROR_KVM)
1146 warnx("memstat_kvm_uma: %s",
1147 kvm_geterr(kd));
1148 else
1149 warnx("memstat_kvm_uma: %s",
1150 memstat_strerror(error));
1151 }
1152 }
1153 printf("%-20s %8s %8s %8s %8s %8s %8s\n\n", "ITEM", "SIZE",
1154 "LIMIT", "USED", "FREE", "REQUESTS", "FAILURES");
1155 for (mtp = memstat_mtl_first(mtlp); mtp != NULL;
1156 mtp = memstat_mtl_next(mtp)) {
1157 strlcpy(name, memstat_get_name(mtp), MEMTYPE_MAXNAME);
1158 strcat(name, ":");
1159 printf("%-20s %8llu, %8llu, %8llu, %8llu, %8llu, %8llu\n", name,
1160 memstat_get_size(mtp), memstat_get_countlimit(mtp),
1161 memstat_get_count(mtp), memstat_get_free(mtp),
1162 memstat_get_numallocs(mtp), memstat_get_failures(mtp));
1163 }
1164 memstat_mtl_free(mtlp);
1165 printf("\n");
1166}
1167
1168/*
1169 * kread reads something from the kernel, given its nlist index.
1170 */
1171static void
1172kreado(int nlx, void *addr, size_t size, size_t offset)
1173{
1174 const char *sym;
1175
1176 if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
1177 sym = namelist[nlx].n_name;
1178 if (*sym == '_')
1179 ++sym;
1180 errx(1, "symbol %s not defined", sym);
1181 }
1182 if ((size_t)kvm_read(kd, namelist[nlx].n_value + offset, addr,
1183 size) != size) {
1184 sym = namelist[nlx].n_name;
1185 if (*sym == '_')
1186 ++sym;
1187 errx(1, "%s: %s", sym, kvm_geterr(kd));
1188 }
1189}
1190
1191static void
1192kread(int nlx, void *addr, size_t size)
1193{
1194 kreado(nlx, addr, size, 0);
1195}
1196
1197static char *
1198kgetstr(const char *strp)
1199{
1200 int n = 0, size = 1;
1201 char *ret = NULL;
1202
1203 do {
1204 if (size == n + 1) {
1205 ret = realloc(ret, size);
1206 if (ret == NULL)
1207 err(1, "%s: realloc", __func__);
1208 size *= 2;
1209 }
1210 if (kvm_read(kd, (u_long)strp + n, &ret[n], 1) != 1)
1211 errx(1, "%s: %s", __func__, kvm_geterr(kd));
1212 } while (ret[n++] != '\0');
1213 return (ret);
1214}
1215
1216static void
1217usage(void)
1218{
1219 (void)fprintf(stderr, "%s%s",
1220 "usage: vmstat [-afHhimPsz] [-c count] [-M core [-N system]] [-w wait]\n",
1221 " [-n devs] [-p type,if,pass] [disks]\n");
1222 exit(1);
1223}