vmstat.c revision 1.45 1 /* $NetBSD: vmstat.c,v 1.45 1998/02/13 05:10:32 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Copyright (c) 1980, 1986, 1991, 1993
42 * The Regents of the University of California. All rights reserved.
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement:
54 * This product includes software developed by the University of
55 * California, Berkeley and its contributors.
56 * 4. Neither the name of the University nor the names of its contributors
57 * may be used to endorse or promote products derived from this software
58 * without specific prior written permission.
59 *
60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 * SUCH DAMAGE.
71 */
72
73 #include <sys/cdefs.h>
74 #ifndef lint
75 __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1991, 1993\n\
76 The Regents of the University of California. All rights reserved.\n");
77 #endif /* not lint */
78
79 #ifndef lint
80 #if 0
81 static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95";
82 #else
83 __RCSID("$NetBSD: vmstat.c,v 1.45 1998/02/13 05:10:32 thorpej Exp $");
84 #endif
85 #endif /* not lint */
86
87 #include <sys/param.h>
88 #include <sys/time.h>
89 #include <sys/proc.h>
90 #include <sys/user.h>
91 #include <sys/dkstat.h>
92 #include <sys/buf.h>
93 #include <sys/namei.h>
94 #include <sys/malloc.h>
95 #include <sys/fcntl.h>
96 #include <sys/ioctl.h>
97 #include <sys/sysctl.h>
98 #include <sys/device.h>
99 #include <vm/vm.h>
100 #include <err.h>
101 #include <time.h>
102 #include <nlist.h>
103 #include <kvm.h>
104 #include <errno.h>
105 #include <unistd.h>
106 #include <signal.h>
107 #include <stdio.h>
108 #include <ctype.h>
109 #include <stdlib.h>
110 #include <string.h>
111 #include <paths.h>
112 #include <limits.h>
113 #include "dkstats.h"
114
115 #if defined(UVM)
116 #include <uvm/uvm_stat.h>
117 #endif
118
119 struct nlist namelist[] = {
120 #define X_CPTIME 0
121 { "_cp_time" },
122 #define X_BOOTTIME 1
123 { "_boottime" },
124 #define X_HZ 2
125 { "_hz" },
126 #define X_STATHZ 3
127 { "_stathz" },
128 #define X_NCHSTATS 4
129 { "_nchstats" },
130 #define X_INTRNAMES 5
131 { "_intrnames" },
132 #define X_EINTRNAMES 6
133 { "_eintrnames" },
134 #define X_INTRCNT 7
135 { "_intrcnt" },
136 #define X_EINTRCNT 8
137 { "_eintrcnt" },
138 #define X_KMEMSTAT 9
139 { "_kmemstats" },
140 #define X_KMEMBUCKETS 10
141 { "_bucket" },
142 #define X_ALLEVENTS 11
143 { "_allevents" },
144 #if defined(UVM)
145 #define X_END 12
146 #else
147 #define X_SUM 12
148 { "_cnt" },
149 #define X_END 13
150 #endif
151 #if defined(pc532)
152 #define X_IVT (X_END)
153 { "_ivt" },
154 #endif
155 { "" },
156 };
157
158 /* Objects defined in dkstats.c */
159 extern struct _disk cur;
160 extern char **dr_name;
161 extern int *dk_select, dk_ndrive;
162
163 #if defined(UVM)
164 struct uvmexp uvmexp, ouvmexp;
165 #else
166 struct vmmeter sum, osum;
167 #endif
168 int ndrives;
169
170 int winlines = 20;
171
172 kvm_t *kd;
173
174 #define FORKSTAT 0x01
175 #define INTRSTAT 0x02
176 #define MEMSTAT 0x04
177 #define SUMSTAT 0x08
178 #define VMSTAT 0x20
179 #if defined(UVM)
180 #define HISTLIST 0x40
181 #define HISTDUMP 0x80
182 #endif
183
184 void cpustats __P((void));
185 void dkstats __P((void));
186 void dointr __P((void));
187 void domem __P((void));
188 void dosum __P((void));
189 void dovmstat __P((u_int, int));
190 void kread __P((int, void *, size_t));
191 void needhdr __P((int));
192 long getuptime __P((void));
193 void printhdr __P((void));
194 long pct __P((long, long));
195 void usage __P((void));
196 void doforkst __P((void));
197
198 #if defined(UVM)
199 void hist_traverse __P((int, const char *));
200 void hist_dodump __P((struct uvm_history *));
201 #endif
202
203 int main __P((int, char **));
204 char **choosedrives __P((char **));
205
206 extern int dkinit __P((int));
207 extern void dkreadstats __P((void));
208 extern void dkswap __P((void));
209
210 /* Namelist and memory file names. */
211 char *nlistf, *memf;
212
213 int
214 main(argc, argv)
215 int argc;
216 char **argv;
217 {
218 extern int optind;
219 extern char *optarg;
220 int c, todo;
221 u_int interval;
222 int reps;
223 char errbuf[_POSIX2_LINE_MAX];
224 #if defined(UVM)
225 const char *histname = NULL;
226 #endif
227
228 memf = nlistf = NULL;
229 interval = reps = todo = 0;
230 #if defined(UVM)
231 while ((c = getopt(argc, argv, "c:fh:HilM:mN:stw:")) != -1) {
232 #else
233 while ((c = getopt(argc, argv, "c:fiM:mN:stw:")) != -1) {
234 #endif
235 switch (c) {
236 case 'c':
237 reps = atoi(optarg);
238 break;
239 case 'f':
240 todo |= FORKSTAT;
241 break;
242 #if defined(UVM)
243 case 'h':
244 histname = optarg;
245 /* FALLTHROUGH */
246 case 'H':
247 todo |= HISTDUMP;
248 break;
249 #endif
250 case 'i':
251 todo |= INTRSTAT;
252 break;
253 #if defined(UVM)
254 case 'l':
255 todo |= HISTLIST;
256 break;
257 #endif
258 case 'M':
259 memf = optarg;
260 break;
261 case 'm':
262 todo |= MEMSTAT;
263 break;
264 case 'N':
265 nlistf = optarg;
266 break;
267 case 's':
268 todo |= SUMSTAT;
269 break;
270 case 'w':
271 interval = atoi(optarg);
272 break;
273 case '?':
274 default:
275 usage();
276 }
277 }
278 argc -= optind;
279 argv += optind;
280
281 if (todo == 0)
282 todo = VMSTAT;
283
284 /*
285 * Discard setgid privileges if not the running kernel so that bad
286 * guys can't print interesting stuff from kernel memory.
287 */
288 if (nlistf != NULL || memf != NULL)
289 setgid(getgid());
290
291 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
292 if (kd == 0) {
293 (void)fprintf(stderr,
294 "vmstat: kvm_openfiles: %s\n", errbuf);
295 exit(1);
296 }
297
298 if ((c = kvm_nlist(kd, namelist)) != 0) {
299 if (c > 0) {
300 (void)fprintf(stderr,
301 "vmstat: undefined symbols:");
302 for (c = 0;
303 c < sizeof(namelist)/sizeof(namelist[0]); c++)
304 if (namelist[c].n_type == 0)
305 fprintf(stderr, " %s",
306 namelist[c].n_name);
307 (void)fputc('\n', stderr);
308 } else
309 (void)fprintf(stderr, "vmstat: kvm_nlist: %s\n",
310 kvm_geterr(kd));
311 exit(1);
312 }
313
314 if (todo & VMSTAT) {
315 struct winsize winsize;
316
317 dkinit(0); /* Initialize disk stats, no disks selected. */
318 argv = choosedrives(argv); /* Select disks. */
319 winsize.ws_row = 0;
320 (void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize);
321 if (winsize.ws_row > 0)
322 winlines = winsize.ws_row;
323
324 }
325
326 #define BACKWARD_COMPATIBILITY
327 #ifdef BACKWARD_COMPATIBILITY
328 if (*argv) {
329 interval = atoi(*argv);
330 if (*++argv)
331 reps = atoi(*argv);
332 }
333 #endif
334
335 if (interval) {
336 if (!reps)
337 reps = -1;
338 } else if (reps)
339 interval = 1;
340
341 #if defined(UVM)
342 if (todo & (HISTLIST|HISTDUMP)) {
343 if ((todo & (HISTLIST|HISTDUMP)) == (HISTLIST|HISTDUMP))
344 errx(1, "you may list or dump, but not both!");
345 hist_traverse(todo, histname);
346 }
347 #endif
348 if (todo & FORKSTAT)
349 doforkst();
350 if (todo & MEMSTAT)
351 domem();
352 if (todo & SUMSTAT)
353 dosum();
354 if (todo & INTRSTAT)
355 dointr();
356 if (todo & VMSTAT)
357 dovmstat(interval, reps);
358 exit(0);
359 }
360
361 char **
362 choosedrives(argv)
363 char **argv;
364 {
365 int i;
366
367 /*
368 * Choose drives to be displayed. Priority goes to (in order) drives
369 * supplied as arguments, default drives. If everything isn't filled
370 * in and there are drives not taken care of, display the first few
371 * that fit.
372 */
373 #define BACKWARD_COMPATIBILITY
374 for (ndrives = 0; *argv; ++argv) {
375 #ifdef BACKWARD_COMPATIBILITY
376 if (isdigit(**argv))
377 break;
378 #endif
379 for (i = 0; i < dk_ndrive; i++) {
380 if (strcmp(dr_name[i], *argv))
381 continue;
382 dk_select[i] = 1;
383 ++ndrives;
384 break;
385 }
386 }
387 for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
388 if (dk_select[i])
389 continue;
390 dk_select[i] = 1;
391 ++ndrives;
392 }
393 return(argv);
394 }
395
396 long
397 getuptime()
398 {
399 static time_t now;
400 static struct timeval boottime;
401 time_t uptime;
402
403 if (boottime.tv_sec == 0)
404 kread(X_BOOTTIME, &boottime, sizeof(boottime));
405 (void)time(&now);
406 uptime = now - boottime.tv_sec;
407 if (uptime <= 0 || uptime > 60*60*24*365*10) {
408 (void)fprintf(stderr,
409 "vmstat: time makes no sense; namelist must be wrong.\n");
410 exit(1);
411 }
412 return(uptime);
413 }
414
415 int hz, hdrcnt;
416
417 void
418 dovmstat(interval, reps)
419 u_int interval;
420 int reps;
421 {
422 struct vmtotal total;
423 time_t uptime, halfuptime;
424 int mib[2];
425 size_t size;
426 int pagesize = getpagesize();
427
428 uptime = getuptime();
429 halfuptime = uptime / 2;
430 (void)signal(SIGCONT, needhdr);
431
432 if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0)
433 kread(X_STATHZ, &hz, sizeof(hz));
434 if (!hz)
435 kread(X_HZ, &hz, sizeof(hz));
436
437 for (hdrcnt = 1;;) {
438 if (!--hdrcnt)
439 printhdr();
440 /* Read new disk statistics */
441 dkreadstats();
442 #if defined(UVM)
443 size = sizeof(uvmexp);
444 mib[0] = CTL_VM;
445 mib[1] = VM_UVMEXP;
446 if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) {
447 printf("can't get uvmexp: %s\n", strerror(errno));
448 bzero(&uvmexp, sizeof(uvmexp));
449 }
450 #else
451 kread(X_SUM, &sum, sizeof(sum));
452 #endif
453 size = sizeof(total);
454 mib[0] = CTL_VM;
455 mib[1] = VM_METER;
456 if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
457 printf("Can't get kerninfo: %s\n", strerror(errno));
458 bzero(&total, sizeof(total));
459 }
460 (void)printf("%2d%2d%2d",
461 total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
462 #define pgtok(a) (long)((a) * (pagesize >> 10))
463 #define rate(x) (u_long)(((x) + halfuptime) / uptime) /* round */
464 (void)printf("%6ld%6ld ",
465 pgtok(total.t_avm), pgtok(total.t_free));
466 #if defined(UVM)
467 (void)printf("%4lu ", rate(uvmexp.faults - ouvmexp.faults));
468 (void)printf("%3lu ", rate(uvmexp.pdreact - ouvmexp.pdreact));
469 (void)printf("%3lu ", rate(uvmexp.pgswapin - ouvmexp.pgswapin));
470 (void)printf("%4lu ",
471 rate(uvmexp.pgswapout - ouvmexp.pgswapout));
472 (void)printf("%4lu ", rate(uvmexp.pdfreed - ouvmexp.pdfreed));
473 (void)printf("%4lu ", rate(uvmexp.pdscans - ouvmexp.pdscans));
474 dkstats();
475 (void)printf("%4lu %4lu %3lu ",
476 rate(uvmexp.intrs - ouvmexp.intrs),
477 rate(uvmexp.syscalls - ouvmexp.syscalls),
478 rate(uvmexp.swtch - ouvmexp.swtch));
479 cpustats();
480 (void)printf("\n");
481 (void)fflush(stdout);
482 if (reps >= 0 && --reps <= 0)
483 break;
484 ouvmexp = uvmexp;
485 #else
486 (void)printf("%4lu ", rate(sum.v_faults - osum.v_faults));
487 (void)printf("%3lu ",
488 rate(sum.v_reactivated - osum.v_reactivated));
489 (void)printf("%3lu ", rate(sum.v_pageins - osum.v_pageins));
490 (void)printf("%3lu %3lu ",
491 rate(sum.v_pageouts - osum.v_pageouts), (u_long)0);
492 (void)printf("%3lu ", rate(sum.v_scan - osum.v_scan));
493 dkstats();
494 (void)printf("%4lu %4lu %3lu ",
495 rate(sum.v_intr - osum.v_intr),
496 rate(sum.v_syscall - osum.v_syscall),
497 rate(sum.v_swtch - osum.v_swtch));
498 cpustats();
499 (void)printf("\n");
500 (void)fflush(stdout);
501 if (reps >= 0 && --reps <= 0)
502 break;
503 osum = sum;
504 #endif
505 uptime = interval;
506 /*
507 * We round upward to avoid losing low-frequency events
508 * (i.e., >= 1 per interval but < 1 per second).
509 */
510 halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2;
511 (void)sleep(interval);
512 }
513 }
514
515 void
516 printhdr()
517 {
518 int i;
519
520 #if defined(UVM)
521 (void)printf(" procs memory page%*s", 23, "");
522 #else
523 (void)printf(" procs memory page%*s", 20, "");
524 #endif
525 if (ndrives > 0)
526 (void)printf("%s %*sfaults cpu\n",
527 ((ndrives > 1) ? "disks" : "disk"),
528 ((ndrives > 1) ? ndrives * 3 - 4 : 0), "");
529 else
530 (void)printf("%*s faults cpu\n",
531 ndrives * 3, "");
532
533 #if defined(UVM)
534 (void)printf(" r b w avm fre flt re pi po fr sr ");
535 #else
536 (void)printf(" r b w avm fre flt re pi po fr sr ");
537 #endif
538 for (i = 0; i < dk_ndrive; i++)
539 if (dk_select[i])
540 (void)printf("%c%c ", dr_name[i][0],
541 dr_name[i][strlen(dr_name[i]) - 1]);
542 (void)printf(" in sy cs us sy id\n");
543 hdrcnt = winlines - 2;
544 }
545
546 /*
547 * Force a header to be prepended to the next output.
548 */
549 void
550 needhdr(dummy)
551 int dummy;
552 {
553
554 hdrcnt = 1;
555 }
556
557 long
558 pct(top, bot)
559 long top, bot;
560 {
561 long ans;
562
563 if (bot == 0)
564 return(0);
565 ans = (quad_t)top * 100 / bot;
566 return (ans);
567 }
568
569 #define PCT(top, bot) (int)pct((long)(top), (long)(bot))
570
571 void
572 dosum()
573 {
574 struct nchstats nchstats;
575 long nchtotal;
576
577 #if defined(UVM)
578 int mib[2];
579 size_t size;
580
581 size = sizeof(uvmexp);
582 mib[0] = CTL_VM;
583 mib[1] = VM_UVMEXP;
584 if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) {
585 printf("can't get uvmexp: %s\n", strerror(errno));
586 bzero(&uvmexp, sizeof(uvmexp));
587 }
588
589 (void)printf("%9u bytes per page\n", uvmexp.pagesize);
590
591 (void)printf("%9u pages managed\n", uvmexp.npages);
592 (void)printf("%9u pages free\n", uvmexp.free);
593 (void)printf("%9u pages active\n", uvmexp.active);
594 (void)printf("%9u pages inactive\n", uvmexp.inactive);
595 (void)printf("%9u pages paging\n", uvmexp.paging);
596 (void)printf("%9u pages wired\n", uvmexp.wired);
597 (void)printf("%9u reserve pagedaemon pages\n",
598 uvmexp.reserve_pagedaemon);
599 (void)printf("%9u reserve kernel pages\n", uvmexp.reserve_kernel);
600
601 (void)printf("%9u minimum free pages\n", uvmexp.freemin);
602 (void)printf("%9u target free pages\n", uvmexp.freetarg);
603 (void)printf("%9u target inactive pages\n", uvmexp.inactarg);
604 (void)printf("%9u maximum wired pages\n", uvmexp.wiredmax);
605
606 (void)printf("%9u swap devices\n", uvmexp.nswapdev);
607 (void)printf("%9u swap pages\n", uvmexp.swpages);
608 (void)printf("%9u swap pages in use\n", uvmexp.swpginuse);
609 (void)printf("%9u swap allocations\n", uvmexp.nswget);
610 (void)printf("%9u anons\n", uvmexp.nanon);
611 (void)printf("%9u free anons\n", uvmexp.nfreeanon);
612
613 (void)printf("%9u total faults taken\n", uvmexp.faults);
614 (void)printf("%9u traps\n", uvmexp.traps);
615 (void)printf("%9u device interrupts\n", uvmexp.intrs);
616 (void)printf("%9u cpu context switches\n", uvmexp.swtch);
617 (void)printf("%9u software interrupts\n", uvmexp.softs);
618 (void)printf("%9u system calls\n", uvmexp.syscalls);
619 (void)printf("%9u pagein requests\n", uvmexp.pageins / CLSIZE);
620 (void)printf("%9u pageout requests\n", uvmexp.pdpageouts / CLSIZE);
621 (void)printf("%9u swap ins\n", uvmexp.swapins);
622 (void)printf("%9u swap outs\n", uvmexp.swapouts);
623 (void)printf("%9u pages swapped in\n", uvmexp.pgswapin / CLSIZE);
624 (void)printf("%9u pages swapped out\n", uvmexp.pgswapout / CLSIZE);
625 (void)printf("%9u forks total\n", uvmexp.forks);
626 (void)printf("%9u forks blocked parent\n", uvmexp.forks_ppwait);
627 (void)printf("%9u forks shared address space with parent\n",
628 uvmexp.forks_sharevm);
629
630 (void)printf("%9u faults with no memory\n", uvmexp.fltnoram);
631 (void)printf("%9u faults with no anons\n", uvmexp.fltnoanon);
632 (void)printf("%9u faults had to wait on pages\n", uvmexp.fltpgwait);
633 (void)printf("%9u faults found released page\n", uvmexp.fltpgrele);
634 (void)printf("%9u faults relock (%u ok)\n", uvmexp.fltrelck,
635 uvmexp.fltrelckok);
636 (void)printf("%9u anon page faults\n", uvmexp.fltanget);
637 (void)printf("%9u anon retry faults\n", uvmexp.fltanretry);
638 (void)printf("%9u amap copy faults\n", uvmexp.fltamcopy);
639 (void)printf("%9u neighbour anon page faults\n", uvmexp.fltnamap);
640 (void)printf("%9u neighbour object page faults\n", uvmexp.fltnomap);
641 (void)printf("%9u locked pager get faults\n", uvmexp.fltlget);
642 (void)printf("%9u unlocked pager get faults\n", uvmexp.fltget);
643 (void)printf("%9u anon faults\n", uvmexp.flt_anon);
644 (void)printf("%9u anon copy on write faults\n", uvmexp.flt_acow);
645 (void)printf("%9u object faults\n", uvmexp.flt_obj);
646 (void)printf("%9u promote copy faults\n", uvmexp.flt_prcopy);
647 (void)printf("%9u promote zero fill faults\n", uvmexp.flt_przero);
648
649 (void)printf("%9u times daemon wokeup\n",uvmexp.pdwoke);
650 (void)printf("%9u revolutions of the clock hand\n", uvmexp.pdrevs);
651 (void)printf("%9u times daemon attempted swapout\n", uvmexp.pdswout);
652 (void)printf("%9u pages freed by daemon\n", uvmexp.pdfreed);
653 (void)printf("%9u pages scanned by daemon\n", uvmexp.pdscans);
654 (void)printf("%9u anonymous pages scanned by daemon\n", uvmexp.pdanscan);
655 (void)printf("%9u object pages scanned by daemon\n", uvmexp.pdobscan);
656 (void)printf("%9u pages reactivated\n", uvmexp.pdreact);
657 (void)printf("%9u pages found busy by daemon\n", uvmexp.pdbusy);
658 (void)printf("%9u total pending pageouts\n", uvmexp.pdpending);
659 (void)printf("%9u pages deactivated\n", uvmexp.pddeact);
660 #else
661 kread(X_SUM, &sum, sizeof(sum));
662 (void)printf("%9u cpu context switches\n", sum.v_swtch);
663 (void)printf("%9u device interrupts\n", sum.v_intr);
664 (void)printf("%9u software interrupts\n", sum.v_soft);
665 (void)printf("%9u traps\n", sum.v_trap);
666 (void)printf("%9u system calls\n", sum.v_syscall);
667 (void)printf("%9u total faults taken\n", sum.v_faults);
668 (void)printf("%9u swap ins\n", sum.v_swpin);
669 (void)printf("%9u swap outs\n", sum.v_swpout);
670 (void)printf("%9u pages swapped in\n", sum.v_pswpin / CLSIZE);
671 (void)printf("%9u pages swapped out\n", sum.v_pswpout / CLSIZE);
672 (void)printf("%9u page ins\n", sum.v_pageins);
673 (void)printf("%9u page outs\n", sum.v_pageouts);
674 (void)printf("%9u pages paged in\n", sum.v_pgpgin);
675 (void)printf("%9u pages paged out\n", sum.v_pgpgout);
676 (void)printf("%9u pages reactivated\n", sum.v_reactivated);
677 (void)printf("%9u intransit blocking page faults\n", sum.v_intrans);
678 (void)printf("%9u zero fill pages created\n", sum.v_nzfod / CLSIZE);
679 (void)printf("%9u zero fill page faults\n", sum.v_zfod / CLSIZE);
680 (void)printf("%9u pages examined by the clock daemon\n", sum.v_scan);
681 (void)printf("%9u revolutions of the clock hand\n", sum.v_rev);
682 (void)printf("%9u VM object cache lookups\n", sum.v_lookups);
683 (void)printf("%9u VM object hits\n", sum.v_hits);
684 (void)printf("%9u total VM faults taken\n", sum.v_vm_faults);
685 (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults);
686 (void)printf("%9u pages freed by daemon\n", sum.v_dfree);
687 (void)printf("%9u pages freed by exiting processes\n", sum.v_pfree);
688 (void)printf("%9u pages free\n", sum.v_free_count);
689 (void)printf("%9u pages wired down\n", sum.v_wire_count);
690 (void)printf("%9u pages active\n", sum.v_active_count);
691 (void)printf("%9u pages inactive\n", sum.v_inactive_count);
692 (void)printf("%9u bytes per page\n", sum.v_page_size);
693 (void)printf("%9u target inactive pages\n", sum.v_inactive_target);
694 (void)printf("%9u target free pages\n", sum.v_free_target);
695 (void)printf("%9u minimum free pages\n", sum.v_free_min);
696 #endif
697 kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
698 nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
699 nchstats.ncs_badhits + nchstats.ncs_falsehits +
700 nchstats.ncs_miss + nchstats.ncs_long;
701 (void)printf("%9ld total name lookups\n", nchtotal);
702 (void)printf(
703 "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
704 "", PCT(nchstats.ncs_goodhits, nchtotal),
705 PCT(nchstats.ncs_neghits, nchtotal),
706 PCT(nchstats.ncs_pass2, nchtotal));
707 (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
708 PCT(nchstats.ncs_badhits, nchtotal),
709 PCT(nchstats.ncs_falsehits, nchtotal),
710 PCT(nchstats.ncs_long, nchtotal));
711 }
712
713 void
714 doforkst()
715 {
716 #if defined(UVM)
717 int mib[2];
718 size_t size;
719
720 size = sizeof(uvmexp);
721 mib[0] = CTL_VM;
722 mib[1] = VM_UVMEXP;
723 if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) {
724 printf("can't get uvmexp: %s\n", strerror(errno));
725 bzero(&uvmexp, sizeof(uvmexp));
726 }
727 (void)printf("%u forks total\n", uvmexp.forks);
728 (void)printf("%u forks blocked parent\n", uvmexp.forks_ppwait);
729 (void)printf("%u forks shared address space with parent\n",
730 uvmexp.forks_sharevm);
731 #else
732
733 kread(X_SUM, &sum, sizeof(sum));
734 (void)printf("%u forks total\n", sum.v_forks);
735 (void)printf("%u forks blocked parent\n", sum.v_forks_ppwait);
736 (void)printf("%u forks shared address space with parent\n",
737 sum.v_forks_sharevm);
738 #endif
739 }
740
741 void
742 dkstats()
743 {
744 int dn, state;
745 double etime;
746
747 /* Calculate disk stat deltas. */
748 dkswap();
749 etime = 0;
750 for (state = 0; state < CPUSTATES; ++state) {
751 etime += cur.cp_time[state];
752 }
753 if (etime == 0)
754 etime = 1;
755 etime /= hz;
756 for (dn = 0; dn < dk_ndrive; ++dn) {
757 if (!dk_select[dn])
758 continue;
759 (void)printf("%2.0f ", cur.dk_xfer[dn] / etime);
760 }
761 }
762
763 void
764 cpustats()
765 {
766 int state;
767 double pct, total;
768
769 total = 0;
770 for (state = 0; state < CPUSTATES; ++state)
771 total += cur.cp_time[state];
772 if (total)
773 pct = 100 / total;
774 else
775 pct = 0;
776 (void)printf("%2.0f ", (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * pct);
777 (void)printf("%2.0f ", (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * pct);
778 (void)printf("%2.0f", cur.cp_time[CP_IDLE] * pct);
779 }
780
781 #if defined(pc532)
782 /* To get struct iv ...*/
783 #define _KERNEL
784 #include <machine/psl.h>
785 #undef _KERNEL
786 void
787 dointr()
788 {
789 long i, j, inttotal, uptime;
790 static char iname[64];
791 struct iv ivt[32], *ivp = ivt;
792
793 iname[63] = '\0';
794 uptime = getuptime();
795 kread(X_IVT, ivp, sizeof(ivt));
796
797 for (i = 0; i < 2; i++) {
798 (void)printf("%sware interrupts:\n", i ? "\nsoft" : "hard");
799 (void)printf("interrupt total rate\n");
800 inttotal = 0;
801 for (j = 0; j < 16; j++, ivp++) {
802 if (ivp->iv_vec && ivp->iv_use && ivp->iv_cnt) {
803 if (kvm_read(kd, (u_long)ivp->iv_use, iname, 63) != 63) {
804 (void)fprintf(stderr, "vmstat: iv_use: %s\n",
805 kvm_geterr(kd));
806 exit(1);
807 }
808 (void)printf("%-12s %8ld %8ld\n", iname,
809 ivp->iv_cnt, ivp->iv_cnt / uptime);
810 inttotal += ivp->iv_cnt;
811 }
812 }
813 (void)printf("Total %8ld %8ld\n",
814 inttotal, inttotal / uptime);
815 }
816 }
817 #else
818 void
819 dointr()
820 {
821 long *intrcnt, inttotal, uptime;
822 int nintr, inamlen;
823 char *intrname;
824 struct evcntlist allevents;
825 struct evcnt evcnt, *evptr;
826 struct device dev;
827
828 uptime = getuptime();
829 nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value;
830 inamlen =
831 namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value;
832 intrcnt = malloc((size_t)nintr);
833 intrname = malloc((size_t)inamlen);
834 if (intrcnt == NULL || intrname == NULL) {
835 (void)fprintf(stderr, "vmstat: %s.\n", strerror(errno));
836 exit(1);
837 }
838 kread(X_INTRCNT, intrcnt, (size_t)nintr);
839 kread(X_INTRNAMES, intrname, (size_t)inamlen);
840 (void)printf("interrupt total rate\n");
841 inttotal = 0;
842 nintr /= sizeof(long);
843 while (--nintr >= 0) {
844 if (*intrcnt)
845 (void)printf("%-14s %8ld %8ld\n", intrname,
846 *intrcnt, *intrcnt / uptime);
847 intrname += strlen(intrname) + 1;
848 inttotal += *intrcnt++;
849 }
850 kread(X_ALLEVENTS, &allevents, sizeof allevents);
851 evptr = allevents.tqh_first;
852 while (evptr) {
853 if (kvm_read(kd, (long)evptr, (void *)&evcnt,
854 sizeof evcnt) != sizeof evcnt) {
855 (void)fprintf(stderr, "vmstat: event chain trashed: %s\n",
856 kvm_geterr(kd));
857 exit(1);
858 }
859 if (kvm_read(kd, (long)evcnt.ev_dev, (void *)&dev,
860 sizeof dev) != sizeof dev) {
861 (void)fprintf(stderr, "vmstat: event chain trashed: %s\n",
862 kvm_geterr(kd));
863 exit(1);
864 }
865 if (evcnt.ev_count)
866 (void)printf("%-14s %8ld %8ld\n", dev.dv_xname,
867 (long)evcnt.ev_count, evcnt.ev_count / uptime);
868 inttotal += evcnt.ev_count++;
869
870 evptr = evcnt.ev_list.tqe_next;
871 }
872 (void)printf("Total %8ld %8ld\n", inttotal, inttotal / uptime);
873 }
874 #endif
875
876 /*
877 * These names are defined in <sys/malloc.h>.
878 */
879 char *kmemnames[] = INITKMEMNAMES;
880
881 void
882 domem()
883 {
884 struct kmembuckets *kp;
885 struct kmemstats *ks;
886 int i, j;
887 int len, size, first;
888 long totuse = 0, totfree = 0, totreq = 0;
889 char *name;
890 struct kmemstats kmemstats[M_LAST];
891 struct kmembuckets buckets[MINBUCKET + 16];
892
893 kread(X_KMEMBUCKETS, buckets, sizeof(buckets));
894 for (first = 1, i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16;
895 i++, kp++) {
896 if (kp->kb_calls == 0)
897 continue;
898 if (first) {
899 (void)printf("Memory statistics by bucket size\n");
900 (void)printf(
901 " Size In Use Free Requests HighWater Couldfree\n");
902 first = 0;
903 }
904 size = 1 << i;
905 (void)printf("%8d %8ld %6ld %10ld %7ld %10ld\n", size,
906 kp->kb_total - kp->kb_totalfree,
907 kp->kb_totalfree, kp->kb_calls,
908 kp->kb_highwat, kp->kb_couldfree);
909 totfree += size * kp->kb_totalfree;
910 }
911
912 /*
913 * If kmem statistics are not being gathered by the kernel,
914 * first will still be 1.
915 */
916 if (first) {
917 printf(
918 "Kmem statistics are not being gathered by the kernel.\n");
919 return;
920 }
921
922 kread(X_KMEMSTAT, kmemstats, sizeof(kmemstats));
923 (void)printf("\nMemory usage type by bucket size\n");
924 (void)printf(" Size Type(s)\n");
925 kp = &buckets[MINBUCKET];
926 for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) {
927 if (kp->kb_calls == 0)
928 continue;
929 first = 1;
930 len = 8;
931 for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
932 if (ks->ks_calls == 0)
933 continue;
934 if ((ks->ks_size & j) == 0)
935 continue;
936 if (kmemnames[i] == 0) {
937 kmemnames[i] = malloc(10);
938 /* strlen("undef/")+3+1);*/
939 snprintf(kmemnames[i], 10, "undef/%d", i);
940 /* same 10 as above!!! */
941 }
942 name = kmemnames[i];
943 len += 2 + strlen(name);
944 if (first)
945 printf("%8d %s", j, name);
946 else
947 printf(",");
948 if (len >= 80) {
949 printf("\n\t ");
950 len = 10 + strlen(name);
951 }
952 if (!first)
953 printf(" %s", name);
954 first = 0;
955 }
956 printf("\n");
957 }
958
959 (void)printf(
960 "\nMemory statistics by type Type Kern\n");
961 (void)printf(
962 " Type InUse MemUse HighUse Limit Requests Limit Limit Size(s)\n");
963 for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
964 if (ks->ks_calls == 0)
965 continue;
966 (void)printf("%14s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u",
967 kmemnames[i] ? kmemnames[i] : "undefined",
968 ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
969 (ks->ks_maxused + 1023) / 1024,
970 (ks->ks_limit + 1023) / 1024, ks->ks_calls,
971 ks->ks_limblocks, ks->ks_mapblocks);
972 first = 1;
973 for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
974 if ((ks->ks_size & j) == 0)
975 continue;
976 if (first)
977 printf(" %d", j);
978 else
979 printf(",%d", j);
980 first = 0;
981 }
982 printf("\n");
983 totuse += ks->ks_memuse;
984 totreq += ks->ks_calls;
985 }
986 (void)printf("\nMemory Totals: In Use Free Requests\n");
987 (void)printf(" %7ldK %6ldK %8ld\n",
988 (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq);
989 }
990
991 /*
992 * kread reads something from the kernel, given its nlist index.
993 */
994 void
995 kread(nlx, addr, size)
996 int nlx;
997 void *addr;
998 size_t size;
999 {
1000 char *sym;
1001
1002 if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
1003 sym = namelist[nlx].n_name;
1004 if (*sym == '_')
1005 ++sym;
1006 (void)fprintf(stderr,
1007 "vmstat: symbol %s not defined\n", sym);
1008 exit(1);
1009 }
1010 if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) {
1011 sym = namelist[nlx].n_name;
1012 if (*sym == '_')
1013 ++sym;
1014 (void)fprintf(stderr, "vmstat: %s: %s\n", sym, kvm_geterr(kd));
1015 exit(1);
1016 }
1017 }
1018
1019 #if defined(UVM)
1020 struct nlist histnl[] = {
1021 { "_uvm_histories" },
1022 #define X_UVM_HISTORIES 0
1023 { NULL },
1024 };
1025
1026 /*
1027 * Traverse the UVM history buffers, performing the requested action.
1028 *
1029 * Note, we assume that if we're not listing, we're dumping.
1030 */
1031 void
1032 hist_traverse(todo, histname)
1033 int todo;
1034 const char *histname;
1035 {
1036 struct uvm_history_head histhead;
1037 struct uvm_history hist, *histkva;
1038 char *name = NULL;
1039 size_t namelen = 0;
1040
1041 if (kvm_nlist(kd, histnl) != 0) {
1042 printf("UVM history is not compiled into the kernel.\n");
1043 return;
1044 }
1045
1046 if (kvm_read(kd, histnl[X_UVM_HISTORIES].n_value, &histhead,
1047 sizeof(histhead)) != sizeof(histhead)) {
1048 warnx("unable to read %s: %s",
1049 histnl[X_UVM_HISTORIES].n_name, kvm_geterr(kd));
1050 return;
1051 }
1052
1053 if (histhead.lh_first == NULL) {
1054 printf("No active UVM history logs.\n");
1055 return;
1056 }
1057
1058 if (todo & HISTLIST)
1059 printf("Active UVM histories:");
1060
1061 for (histkva = histhead.lh_first; histkva != NULL;
1062 histkva = hist.list.le_next) {
1063 if (kvm_read(kd, (u_long)histkva, &hist, sizeof(hist)) !=
1064 sizeof(hist)) {
1065 warnx("unable to read history at %p: %s",
1066 histkva, kvm_geterr(kd));
1067 goto out;
1068 }
1069
1070 if (hist.namelen > namelen) {
1071 if (name != NULL)
1072 free(name);
1073 namelen = hist.namelen;
1074 if ((name = malloc(namelen + 1)) == NULL)
1075 err(1, "malloc history name");
1076 }
1077
1078 if (kvm_read(kd, (u_long)hist.name, name, namelen) !=
1079 namelen) {
1080 warnx("unable to read history name at %p: %s",
1081 hist.name, kvm_geterr(kd));
1082 goto out;
1083 }
1084 name[namelen] = '\0';
1085 if (todo & HISTLIST)
1086 printf(" %s", name);
1087 else {
1088 /*
1089 * If we're dumping all histories, do it, else
1090 * check to see if this is the one we want.
1091 */
1092 if (histname == NULL || strcmp(histname, name) == 0) {
1093 if (histname == NULL)
1094 printf("\nUVM history `%s':\n", name);
1095 hist_dodump(&hist);
1096 }
1097 }
1098 }
1099
1100 if (todo & HISTLIST)
1101 printf("\n");
1102
1103 out:
1104 if (name != NULL)
1105 free(name);
1106 }
1107
1108 /*
1109 * Actually dump the history buffer at the specified KVA.
1110 */
1111 void
1112 hist_dodump(histp)
1113 struct uvm_history *histp;
1114 {
1115 struct uvm_history_ent *histents, *e;
1116 size_t histsize;
1117 char *fmt = NULL, *fn = NULL;
1118 size_t fmtlen = 0, fnlen = 0;
1119 int i;
1120
1121 histsize = sizeof(struct uvm_history_ent) * histp->n;
1122
1123 if ((histents = malloc(histsize)) == NULL)
1124 err(1, "malloc history entries");
1125
1126 memset(histents, 0, histsize);
1127
1128 if (kvm_read(kd, (u_long)histp->e, histents, histsize) != histsize) {
1129 warnx("unable to read history entries at %p: %s",
1130 histp->e, kvm_geterr(kd));
1131 goto out;
1132 }
1133
1134 i = histp->f;
1135 do {
1136 e = &histents[i];
1137 if (e->fmt != NULL) {
1138 if (e->fmtlen > fmtlen) {
1139 if (fmt != NULL)
1140 free(fmt);
1141 fmtlen = e->fmtlen;
1142 if ((fmt = malloc(fmtlen + 1)) == NULL)
1143 err(1, "malloc printf format");
1144 }
1145 if (e->fnlen > fnlen) {
1146 if (fn != NULL)
1147 free(fn);
1148 fnlen = e->fnlen;
1149 if ((fn = malloc(fnlen + 1)) == NULL)
1150 err(1, "malloc function name");
1151 }
1152
1153 if (kvm_read(kd, (u_long)e->fmt, fmt, fmtlen)
1154 != fmtlen) {
1155 warnx("unable to read printf format "
1156 "at %p: %s", e->fmt, kvm_geterr(kd));
1157 goto out;
1158 }
1159 fmt[fmtlen] = '\0';
1160
1161 if (kvm_read(kd, (u_long)e->fn, fn, fnlen) != fnlen) {
1162 warnx("unable to read function name "
1163 "at %p: %s", e->fn, kvm_geterr(kd));
1164 goto out;
1165 }
1166 fn[fnlen] = '\0';
1167
1168 printf("%06ld.%06ld ", e->tv.tv_sec, e->tv.tv_usec);
1169 printf("%s#%ld: ", fn, e->call);
1170 printf(fmt, e->v[0], e->v[1], e->v[2], e->v[3]);
1171 printf("\n");
1172 }
1173 i = (i + 1) % histp->n;
1174 } while (i != histp->f);
1175
1176 out:
1177 free(histents);
1178 if (fmt != NULL)
1179 free(fmt);
1180 if (fn != NULL)
1181 free(fn);
1182 }
1183 #endif /* UVM */
1184
1185 void
1186 usage()
1187 {
1188 #if defined(UVM)
1189 (void)fprintf(stderr,
1190 "usage: vmstat [-fHilms] [-h histname] [-c count] [-M core] \
1191 [-N system] [-w wait] [disks]\n");
1192 #else
1193 (void)fprintf(stderr,
1194 "usage: vmstat [-fims] [-c count] [-M core] \
1195 [-N system] [-w wait] [disks]\n");
1196 #endif /* UVM */
1197 exit(1);
1198 }
1199