vmstat.c revision 1.24 1 /* $NetBSD: vmstat.c,v 1.24 1995/09/24 06:34:47 phil Exp $ */
2
3 /*
4 * Copyright (c) 1980, 1986, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 static char copyright[] =
38 "@(#) Copyright (c) 1980, 1986, 1991, 1993\n\
39 The Regents of the University of California. All rights reserved.\n";
40 #endif /* not lint */
41
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93";
45 #else
46 static char rcsid[] = "$NetBSD: vmstat.c,v 1.24 1995/09/24 06:34:47 phil Exp $";
47 #endif
48 #endif /* not lint */
49
50 #include <sys/param.h>
51 #include <sys/time.h>
52 #include <sys/proc.h>
53 #include <sys/user.h>
54 #include <sys/dkstat.h>
55 #include <sys/buf.h>
56 #include <sys/namei.h>
57 #include <sys/malloc.h>
58 #include <sys/fcntl.h>
59 #include <sys/ioctl.h>
60 #include <sys/sysctl.h>
61 #include <sys/device.h>
62 #include <vm/vm.h>
63 #include <time.h>
64 #include <nlist.h>
65 #include <kvm.h>
66 #include <errno.h>
67 #include <unistd.h>
68 #include <signal.h>
69 #include <stdio.h>
70 #include <ctype.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <paths.h>
74 #include <limits.h>
75
76 #define NEWVM /* XXX till old has been updated or purged */
77 struct nlist namelist[] = {
78 #define X_CPTIME 0
79 { "_cp_time" },
80 #define X_DK_NDRIVE 1
81 { "_dk_ndrive" },
82 #define X_SUM 2
83 { "_cnt" },
84 #define X_BOOTTIME 3
85 { "_boottime" },
86 #define X_DKXFER 4
87 { "_dk_xfer" },
88 #define X_HZ 5
89 { "_hz" },
90 #define X_STATHZ 6
91 { "_stathz" },
92 #define X_NCHSTATS 7
93 { "_nchstats" },
94 #define X_INTRNAMES 8
95 { "_intrnames" },
96 #define X_EINTRNAMES 9
97 { "_eintrnames" },
98 #define X_INTRCNT 10
99 { "_intrcnt" },
100 #define X_EINTRCNT 11
101 { "_eintrcnt" },
102 #define X_KMEMSTAT 12
103 { "_kmemstats" },
104 #define X_KMEMBUCKETS 13
105 { "_bucket" },
106 #define X_ALLEVENTS 14
107 { "_allevents" },
108 #ifdef notdef
109 #define X_DEFICIT 15
110 { "_deficit" },
111 #define X_FORKSTAT 16
112 { "_forkstat" },
113 #define X_REC 17
114 { "_rectime" },
115 #define X_PGIN 18
116 { "_pgintime" },
117 #define X_XSTATS 19
118 { "_xstats" },
119 #define X_END 20
120 #else
121 #define X_END 15
122 #endif
123 #if defined(hp300) || defined(luna68k)
124 #define X_HPDINIT (X_END)
125 { "_hp_dinit" },
126 #endif
127 #ifdef mips
128 #define X_SCSI_DINIT (X_END)
129 { "_scsi_dinit" },
130 #endif
131 #ifdef tahoe
132 #define X_VBDINIT (X_END)
133 { "_vbdinit" },
134 #define X_CKEYSTATS (X_END+1)
135 { "_ckeystats" },
136 #define X_DKEYSTATS (X_END+2)
137 { "_dkeystats" },
138 #endif
139 #if defined(pc532)
140 #define X_IVT (X_END)
141 { "_ivt" },
142 #endif
143 { "" },
144 };
145
146 struct _disk {
147 long time[CPUSTATES];
148 long *xfer;
149 } cur, last;
150
151 struct vmmeter sum, osum;
152 char **dr_name;
153 int *dr_select, dk_ndrive, ndrives;
154
155 int winlines = 20;
156
157 kvm_t *kd;
158
159 #define FORKSTAT 0x01
160 #define INTRSTAT 0x02
161 #define MEMSTAT 0x04
162 #define SUMSTAT 0x08
163 #define TIMESTAT 0x10
164 #define VMSTAT 0x20
165
166 #include "names.c" /* disk names -- machine dependent */
167
168 void cpustats(), dkstats(), dointr(), domem(), dosum();
169 void dovmstat(), kread(), usage();
170 #ifdef notdef
171 void dotimes(), doforkst();
172 #endif
173
174 main(argc, argv)
175 register int argc;
176 register char **argv;
177 {
178 extern int optind;
179 extern char *optarg;
180 register int c, todo;
181 u_int interval;
182 int reps;
183 char *memf, *nlistf;
184 char errbuf[_POSIX2_LINE_MAX];
185
186 memf = nlistf = NULL;
187 interval = reps = todo = 0;
188 while ((c = getopt(argc, argv, "c:fiM:mN:stw:")) != EOF) {
189 switch (c) {
190 case 'c':
191 reps = atoi(optarg);
192 break;
193 #ifndef notdef
194 case 'f':
195 todo |= FORKSTAT;
196 break;
197 #endif
198 case 'i':
199 todo |= INTRSTAT;
200 break;
201 case 'M':
202 memf = optarg;
203 break;
204 case 'm':
205 todo |= MEMSTAT;
206 break;
207 case 'N':
208 nlistf = optarg;
209 break;
210 case 's':
211 todo |= SUMSTAT;
212 break;
213 #ifndef notdef
214 case 't':
215 todo |= TIMESTAT;
216 break;
217 #endif
218 case 'w':
219 interval = atoi(optarg);
220 break;
221 case '?':
222 default:
223 usage();
224 }
225 }
226 argc -= optind;
227 argv += optind;
228
229 if (todo == 0)
230 todo = VMSTAT;
231
232 /*
233 * Discard setgid privileges if not the running kernel so that bad
234 * guys can't print interesting stuff from kernel memory.
235 */
236 if (nlistf != NULL || memf != NULL)
237 setgid(getgid());
238
239 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
240 if (kd == 0) {
241 (void)fprintf(stderr,
242 "vmstat: kvm_openfiles: %s\n", errbuf);
243 exit(1);
244 }
245
246 if ((c = kvm_nlist(kd, namelist)) != 0) {
247 if (c > 0) {
248 (void)fprintf(stderr,
249 "vmstat: undefined symbols:");
250 for (c = 0;
251 c < sizeof(namelist)/sizeof(namelist[0]); c++)
252 if (namelist[c].n_type == 0)
253 fprintf(stderr, " %s",
254 namelist[c].n_name);
255 (void)fputc('\n', stderr);
256 } else
257 (void)fprintf(stderr, "vmstat: kvm_nlist: %s\n",
258 kvm_geterr(kd));
259 exit(1);
260 }
261
262 if (todo & VMSTAT) {
263 char **getdrivedata();
264 struct winsize winsize;
265
266 argv = getdrivedata(argv);
267 winsize.ws_row = 0;
268 (void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize);
269 if (winsize.ws_row > 0)
270 winlines = winsize.ws_row;
271
272 }
273
274 #define BACKWARD_COMPATIBILITY
275 #ifdef BACKWARD_COMPATIBILITY
276 if (*argv) {
277 interval = atoi(*argv);
278 if (*++argv)
279 reps = atoi(*argv);
280 }
281 #endif
282
283 if (interval) {
284 if (!reps)
285 reps = -1;
286 } else if (reps)
287 interval = 1;
288
289 #ifdef notdef
290 if (todo & FORKSTAT)
291 doforkst();
292 #endif
293 if (todo & MEMSTAT)
294 domem();
295 if (todo & SUMSTAT)
296 dosum();
297 #ifdef notdef
298 if (todo & TIMESTAT)
299 dotimes();
300 #endif
301 if (todo & INTRSTAT)
302 dointr();
303 if (todo & VMSTAT)
304 dovmstat(interval, reps);
305 exit(0);
306 }
307
308 char **
309 getdrivedata(argv)
310 char **argv;
311 {
312 register int i;
313 register char **cp;
314 char buf[30];
315
316 kread(X_DK_NDRIVE, &dk_ndrive, sizeof(dk_ndrive));
317 if (dk_ndrive <= 0) {
318 (void)fprintf(stderr, "vmstat: dk_ndrive %d\n", dk_ndrive);
319 exit(1);
320 }
321 dr_select = calloc((size_t)dk_ndrive, sizeof(int));
322 dr_name = calloc((size_t)dk_ndrive, sizeof(char *));
323 for (i = 0; i < dk_ndrive; i++)
324 dr_name[i] = NULL;
325 cur.xfer = calloc((size_t)dk_ndrive, sizeof(long));
326 last.xfer = calloc((size_t)dk_ndrive, sizeof(long));
327 if (!read_names())
328 exit (1);
329 for (i = 0; i < dk_ndrive; i++)
330 if (dr_name[i] == NULL) {
331 (void)sprintf(buf, "??%d", i);
332 dr_name[i] = strdup(buf);
333 }
334
335 /*
336 * Choose drives to be displayed. Priority goes to (in order) drives
337 * supplied as arguments, default drives. If everything isn't filled
338 * in and there are drives not taken care of, display the first few
339 * that fit.
340 */
341 #define BACKWARD_COMPATIBILITY
342 for (ndrives = 0; *argv; ++argv) {
343 #ifdef BACKWARD_COMPATIBILITY
344 if (isdigit(**argv))
345 break;
346 #endif
347 for (i = 0; i < dk_ndrive; i++) {
348 if (strcmp(dr_name[i], *argv))
349 continue;
350 dr_select[i] = 1;
351 ++ndrives;
352 break;
353 }
354 }
355 for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
356 if (dr_select[i])
357 continue;
358 for (cp = defdrives; *cp; cp++)
359 if (strcmp(dr_name[i], *cp) == 0) {
360 dr_select[i] = 1;
361 ++ndrives;
362 break;
363 }
364 }
365 for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
366 if (dr_select[i])
367 continue;
368 dr_select[i] = 1;
369 ++ndrives;
370 }
371 return(argv);
372 }
373
374 long
375 getuptime()
376 {
377 static time_t now, boottime;
378 time_t uptime;
379
380 if (boottime == 0)
381 kread(X_BOOTTIME, &boottime, sizeof(boottime));
382 (void)time(&now);
383 uptime = now - boottime;
384 if (uptime <= 0 || uptime > 60*60*24*365*10) {
385 (void)fprintf(stderr,
386 "vmstat: time makes no sense; namelist must be wrong.\n");
387 exit(1);
388 }
389 return(uptime);
390 }
391
392 int hz, hdrcnt;
393
394 void
395 dovmstat(interval, reps)
396 u_int interval;
397 int reps;
398 {
399 struct vmtotal total;
400 time_t uptime, halfuptime;
401 void needhdr();
402 int mib[2];
403 size_t size;
404
405 uptime = getuptime();
406 halfuptime = uptime / 2;
407 (void)signal(SIGCONT, needhdr);
408
409 if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0)
410 kread(X_STATHZ, &hz, sizeof(hz));
411 if (!hz)
412 kread(X_HZ, &hz, sizeof(hz));
413
414 for (hdrcnt = 1;;) {
415 if (!--hdrcnt)
416 printhdr();
417 kread(X_CPTIME, cur.time, sizeof(cur.time));
418 kread(X_DKXFER, cur.xfer, sizeof(*cur.xfer) * dk_ndrive);
419 kread(X_SUM, &sum, sizeof(sum));
420 size = sizeof(total);
421 mib[0] = CTL_VM;
422 mib[1] = VM_METER;
423 if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
424 printf("Can't get kerninfo: %s\n", strerror(errno));
425 bzero(&total, sizeof(total));
426 }
427 (void)printf("%2d%2d%2d",
428 total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
429 #define pgtok(a) ((a) * sum.v_page_size >> 10)
430 #define rate(x) (((x) + halfuptime) / uptime) /* round */
431 (void)printf("%6ld%6ld ",
432 pgtok(total.t_avm), pgtok(total.t_free));
433 #ifdef NEWVM
434 (void)printf("%4lu ", rate(sum.v_faults - osum.v_faults));
435 (void)printf("%3lu ",
436 rate(sum.v_reactivated - osum.v_reactivated));
437 (void)printf("%3lu ", rate(sum.v_pageins - osum.v_pageins));
438 (void)printf("%3lu %3lu ",
439 rate(sum.v_pageouts - osum.v_pageouts), 0);
440 #else
441 (void)printf("%3lu %2lu ",
442 rate(sum.v_pgrec - (sum.v_xsfrec+sum.v_xifrec) -
443 (osum.v_pgrec - (osum.v_xsfrec+osum.v_xifrec))),
444 rate(sum.v_xsfrec + sum.v_xifrec -
445 osum.v_xsfrec - osum.v_xifrec));
446 (void)printf("%3lu ",
447 rate(pgtok(sum.v_pgpgin - osum.v_pgpgin)));
448 (void)printf("%3lu %3lu ",
449 rate(pgtok(sum.v_pgpgout - osum.v_pgpgout)),
450 rate(pgtok(sum.v_dfree - osum.v_dfree)));
451 (void)printf("%3d ", pgtok(deficit));
452 #endif
453 (void)printf("%3lu ", rate(sum.v_scan - osum.v_scan));
454 dkstats();
455 (void)printf("%4lu %4lu %3lu ",
456 rate(sum.v_intr - osum.v_intr),
457 rate(sum.v_syscall - osum.v_syscall),
458 rate(sum.v_swtch - osum.v_swtch));
459 cpustats();
460 (void)printf("\n");
461 (void)fflush(stdout);
462 if (reps >= 0 && --reps <= 0)
463 break;
464 osum = sum;
465 uptime = interval;
466 /*
467 * We round upward to avoid losing low-frequency events
468 * (i.e., >= 1 per interval but < 1 per second).
469 */
470 halfuptime = (uptime + 1) / 2;
471 (void)sleep(interval);
472 }
473 }
474
475 printhdr()
476 {
477 register int i;
478
479 (void)printf(" procs memory page%*s", 20, "");
480 if (ndrives > 1)
481 (void)printf("disks %*s faults cpu\n",
482 ndrives * 3 - 6, "");
483 else
484 (void)printf("%*s faults cpu\n", ndrives * 3, "");
485 #ifndef NEWVM
486 (void)printf(" r b w avm fre re at pi po fr de sr ");
487 #else
488 (void)printf(" r b w avm fre flt re pi po fr sr ");
489 #endif
490 for (i = 0; i < dk_ndrive; i++)
491 if (dr_select[i])
492 (void)printf("%c%c ", dr_name[i][0],
493 dr_name[i][strlen(dr_name[i]) - 1]);
494 (void)printf(" in sy cs us sy id\n");
495 hdrcnt = winlines - 2;
496 }
497
498 /*
499 * Force a header to be prepended to the next output.
500 */
501 void
502 needhdr()
503 {
504
505 hdrcnt = 1;
506 }
507
508 #ifdef notdef
509 void
510 dotimes()
511 {
512 u_int pgintime, rectime;
513
514 kread(X_REC, &rectime, sizeof(rectime));
515 kread(X_PGIN, &pgintime, sizeof(pgintime));
516 kread(X_SUM, &sum, sizeof(sum));
517 (void)printf("%u reclaims, %u total time (usec)\n",
518 sum.v_pgrec, rectime);
519 (void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec);
520 (void)printf("\n");
521 (void)printf("%u page ins, %u total time (msec)\n",
522 sum.v_pgin, pgintime / 10);
523 (void)printf("average: %8.1f msec / page in\n",
524 pgintime / (sum.v_pgin * 10.0));
525 }
526 #endif
527
528 pct(top, bot)
529 long top, bot;
530 {
531 long ans;
532
533 if (bot == 0)
534 return(0);
535 ans = (quad_t)top * 100 / bot;
536 return (ans);
537 }
538
539 #define PCT(top, bot) pct((long)(top), (long)(bot))
540
541 #if defined(tahoe)
542 #include <machine/cpu.h>
543 #endif
544
545 void
546 dosum()
547 {
548 struct nchstats nchstats;
549 #ifndef NEWVM
550 struct xstats xstats;
551 #endif
552 long nchtotal;
553 #if defined(tahoe)
554 struct keystats keystats;
555 #endif
556
557 kread(X_SUM, &sum, sizeof(sum));
558 (void)printf("%9u cpu context switches\n", sum.v_swtch);
559 (void)printf("%9u device interrupts\n", sum.v_intr);
560 (void)printf("%9u software interrupts\n", sum.v_soft);
561 (void)printf("%9u traps\n", sum.v_trap);
562 (void)printf("%9u system calls\n", sum.v_syscall);
563 (void)printf("%9u total faults taken\n", sum.v_faults);
564 (void)printf("%9u swap ins\n", sum.v_swpin);
565 (void)printf("%9u swap outs\n", sum.v_swpout);
566 (void)printf("%9u pages swapped in\n", sum.v_pswpin / CLSIZE);
567 (void)printf("%9u pages swapped out\n", sum.v_pswpout / CLSIZE);
568 (void)printf("%9u page ins\n", sum.v_pageins);
569 (void)printf("%9u page outs\n", sum.v_pageouts);
570 (void)printf("%9u pages paged in\n", sum.v_pgpgin);
571 (void)printf("%9u pages paged out\n", sum.v_pgpgout);
572 (void)printf("%9u pages reactivated\n", sum.v_reactivated);
573 (void)printf("%9u intransit blocking page faults\n", sum.v_intrans);
574 (void)printf("%9u zero fill pages created\n", sum.v_nzfod / CLSIZE);
575 (void)printf("%9u zero fill page faults\n", sum.v_zfod / CLSIZE);
576 (void)printf("%9u pages examined by the clock daemon\n", sum.v_scan);
577 (void)printf("%9u revolutions of the clock hand\n", sum.v_rev);
578 #ifdef NEWVM
579 (void)printf("%9u VM object cache lookups\n", sum.v_lookups);
580 (void)printf("%9u VM object hits\n", sum.v_hits);
581 (void)printf("%9u total VM faults taken\n", sum.v_vm_faults);
582 (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults);
583 (void)printf("%9u pages freed by daemon\n", sum.v_dfree);
584 (void)printf("%9u pages freed by exiting processes\n", sum.v_pfree);
585 (void)printf("%9u pages free\n", sum.v_free_count);
586 (void)printf("%9u pages wired down\n", sum.v_wire_count);
587 (void)printf("%9u pages active\n", sum.v_active_count);
588 (void)printf("%9u pages inactive\n", sum.v_inactive_count);
589 (void)printf("%9u bytes per page\n", sum.v_page_size);
590 #else
591 (void)printf("%9u sequential process pages freed\n", sum.v_seqfree);
592 (void)printf("%9u total reclaims (%d%% fast)\n", sum.v_pgrec,
593 PCT(sum.v_fastpgrec, sum.v_pgrec));
594 (void)printf("%9u reclaims from free list\n", sum.v_pgfrec);
595 (void)printf("%9u executable fill pages created\n",
596 sum.v_nexfod / CLSIZE);
597 (void)printf("%9u executable fill page faults\n",
598 sum.v_exfod / CLSIZE);
599 (void)printf("%9u swap text pages found in free list\n",
600 sum.v_xsfrec);
601 (void)printf("%9u inode text pages found in free list\n",
602 sum.v_xifrec);
603 (void)printf("%9u file fill pages created\n", sum.v_nvrfod / CLSIZE);
604 (void)printf("%9u file fill page faults\n", sum.v_vrfod / CLSIZE);
605 (void)printf("%9u pages freed by the clock daemon\n",
606 sum.v_dfree / CLSIZE);
607 #endif
608 kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
609 nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
610 nchstats.ncs_badhits + nchstats.ncs_falsehits +
611 nchstats.ncs_miss + nchstats.ncs_long;
612 (void)printf("%9ld total name lookups\n", nchtotal);
613 (void)printf(
614 "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
615 "", PCT(nchstats.ncs_goodhits, nchtotal),
616 PCT(nchstats.ncs_neghits, nchtotal),
617 PCT(nchstats.ncs_pass2, nchtotal));
618 (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
619 PCT(nchstats.ncs_badhits, nchtotal),
620 PCT(nchstats.ncs_falsehits, nchtotal),
621 PCT(nchstats.ncs_long, nchtotal));
622 #ifndef NEWVM
623 kread(X_XSTATS, &xstats, sizeof(xstats));
624 (void)printf("%9lu total calls to xalloc (cache hits %d%%)\n",
625 xstats.alloc, PCT(xstats.alloc_cachehit, xstats.alloc));
626 (void)printf("%9s sticky %lu flushed %lu unused %lu\n", "",
627 xstats.alloc_inuse, xstats.alloc_cacheflush, xstats.alloc_unused);
628 (void)printf("%9lu total calls to xfree", xstats.free);
629 (void)printf(" (sticky %lu cached %lu swapped %lu)\n",
630 xstats.free_inuse, xstats.free_cache, xstats.free_cacheswap);
631 #endif
632 #if defined(tahoe)
633 kread(X_CKEYSTATS, &keystats, sizeof(keystats));
634 (void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
635 keystats.ks_allocs, "code cache keys allocated",
636 PCT(keystats.ks_allocfree, keystats.ks_allocs),
637 PCT(keystats.ks_norefs, keystats.ks_allocs),
638 PCT(keystats.ks_taken, keystats.ks_allocs),
639 PCT(keystats.ks_shared, keystats.ks_allocs));
640 kread(X_DKEYSTATS, &keystats, sizeof(keystats));
641 (void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n",
642 keystats.ks_allocs, "data cache keys allocated",
643 PCT(keystats.ks_allocfree, keystats.ks_allocs),
644 PCT(keystats.ks_norefs, keystats.ks_allocs),
645 PCT(keystats.ks_taken, keystats.ks_allocs),
646 PCT(keystats.ks_shared, keystats.ks_allocs));
647 #endif
648 }
649
650 #ifdef notdef
651 void
652 doforkst()
653 {
654 struct forkstat fks;
655
656 kread(X_FORKSTAT, &fks, sizeof(struct forkstat));
657 (void)printf("%d forks, %d pages, average %.2f\n",
658 fks.cntfork, fks.sizfork, (double)fks.sizfork / fks.cntfork);
659 (void)printf("%d vforks, %d pages, average %.2f\n",
660 fks.cntvfork, fks.sizvfork, (double)fks.sizvfork / fks.cntvfork);
661 }
662 #endif
663
664 void
665 dkstats()
666 {
667 register int dn, state;
668 double etime;
669 long tmp;
670
671 for (dn = 0; dn < dk_ndrive; ++dn) {
672 tmp = cur.xfer[dn];
673 cur.xfer[dn] -= last.xfer[dn];
674 last.xfer[dn] = tmp;
675 }
676 etime = 0;
677 for (state = 0; state < CPUSTATES; ++state) {
678 tmp = cur.time[state];
679 cur.time[state] -= last.time[state];
680 last.time[state] = tmp;
681 etime += cur.time[state];
682 }
683 if (etime == 0)
684 etime = 1;
685 etime /= hz;
686 for (dn = 0; dn < dk_ndrive; ++dn) {
687 if (!dr_select[dn])
688 continue;
689 (void)printf("%2.0f ", cur.xfer[dn] / etime);
690 }
691 }
692
693 void
694 cpustats()
695 {
696 register int state;
697 double pct, total;
698
699 total = 0;
700 for (state = 0; state < CPUSTATES; ++state)
701 total += cur.time[state];
702 if (total)
703 pct = 100 / total;
704 else
705 pct = 0;
706 (void)printf("%2.0f ", (cur.time[CP_USER] + cur.time[CP_NICE]) * pct);
707 (void)printf("%2.0f ", (cur.time[CP_SYS] + cur.time[CP_INTR]) * pct);
708 (void)printf("%2.0f", cur.time[CP_IDLE] * pct);
709 }
710
711 #if defined(pc532)
712 /* To get struct iv ...*/
713 #define _KERNEL
714 #include <machine/psl.h>
715 #undef _KERNEL
716 void
717 dointr()
718 {
719 register long i, j, inttotal, uptime;
720 static char iname[64];
721 struct iv ivt[32], *ivp = ivt;
722
723 iname[63] = '\0';
724 uptime = getuptime();
725 kread(X_IVT, ivp, sizeof(ivt));
726
727 for (i = 0; i < 2; i++) {
728 (void)printf("%sware interrupts:\n", i ? "\nsoft" : "hard");
729 (void)printf("interrupt total rate\n");
730 inttotal = 0;
731 for (j = 0; j < 16; j++, ivp++) {
732 if (ivp->iv_vec && ivp->iv_use && ivp->iv_cnt) {
733 if (kvm_read(kd, (u_long)ivp->iv_use, iname, 63) != 63) {
734 (void)fprintf(stderr, "vmstat: iv_use: %s\n",
735 kvm_geterr(kd));
736 exit(1);
737 }
738 (void)printf("%-12s %8ld %8ld\n", iname,
739 ivp->iv_cnt, ivp->iv_cnt / uptime);
740 inttotal += ivp->iv_cnt;
741 }
742 }
743 (void)printf("Total %8ld %8ld\n",
744 inttotal, inttotal / uptime);
745 }
746 }
747 #else
748 void
749 dointr()
750 {
751 register long *intrcnt, inttotal, uptime;
752 register int nintr, inamlen;
753 register char *intrname;
754 struct evcnt evcnt, *allevents;
755 struct device dev;
756
757 uptime = getuptime();
758 nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value;
759 inamlen =
760 namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value;
761 intrcnt = malloc((size_t)nintr);
762 intrname = malloc((size_t)inamlen);
763 if (intrcnt == NULL || intrname == NULL) {
764 (void)fprintf(stderr, "vmstat: %s.\n", strerror(errno));
765 exit(1);
766 }
767 kread(X_INTRCNT, intrcnt, (size_t)nintr);
768 kread(X_INTRNAMES, intrname, (size_t)inamlen);
769 (void)printf("interrupt total rate\n");
770 inttotal = 0;
771 nintr /= sizeof(long);
772 while (--nintr >= 0) {
773 if (*intrcnt)
774 (void)printf("%-12s %8ld %8ld\n", intrname,
775 *intrcnt, *intrcnt / uptime);
776 intrname += strlen(intrname) + 1;
777 inttotal += *intrcnt++;
778 }
779 kread(X_ALLEVENTS, &allevents, sizeof allevents);
780 while (allevents) {
781 if (kvm_read(kd, (long)allevents, (void *)&evcnt,
782 sizeof evcnt) != sizeof evcnt) {
783 (void)fprintf(stderr, "vmstat: event chain trashed\n",
784 kvm_geterr(kd));
785 exit(1);
786 }
787 if (strcmp(evcnt.ev_name, "intr") == 0) {
788 if (kvm_read(kd, (long)evcnt.ev_dev, (void *)&dev,
789 sizeof dev) != sizeof dev) {
790 (void)fprintf(stderr, "vmstat: event chain trashed\n",
791 kvm_geterr(kd));
792 exit(1);
793 }
794 if (evcnt.ev_count)
795 (void)printf("%-12s %8ld %8ld\n", dev.dv_xname,
796 evcnt.ev_count, evcnt.ev_count / uptime);
797 }
798 allevents = evcnt.ev_next;
799 }
800 (void)printf("Total %8ld %8ld\n", inttotal, inttotal / uptime);
801 }
802 #endif
803
804 /*
805 * These names are defined in <sys/malloc.h>.
806 */
807 char *kmemnames[] = INITKMEMNAMES;
808
809 void
810 domem()
811 {
812 register struct kmembuckets *kp;
813 register struct kmemstats *ks;
814 register int i, j;
815 int len, size, first;
816 long totuse = 0, totfree = 0, totreq = 0;
817 char *name;
818 struct kmemstats kmemstats[M_LAST];
819 struct kmembuckets buckets[MINBUCKET + 16];
820
821 kread(X_KMEMBUCKETS, buckets, sizeof(buckets));
822 (void)printf("Memory statistics by bucket size\n");
823 (void)printf(
824 " Size In Use Free Requests HighWater Couldfree\n");
825 for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) {
826 if (kp->kb_calls == 0)
827 continue;
828 size = 1 << i;
829 (void)printf("%8d %8ld %6ld %10ld %7ld %10ld\n", size,
830 kp->kb_total - kp->kb_totalfree,
831 kp->kb_totalfree, kp->kb_calls,
832 kp->kb_highwat, kp->kb_couldfree);
833 totfree += size * kp->kb_totalfree;
834 }
835
836 kread(X_KMEMSTAT, kmemstats, sizeof(kmemstats));
837 (void)printf("\nMemory usage type by bucket size\n");
838 (void)printf(" Size Type(s)\n");
839 kp = &buckets[MINBUCKET];
840 for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) {
841 if (kp->kb_calls == 0)
842 continue;
843 first = 1;
844 len = 8;
845 for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
846 if (ks->ks_calls == 0)
847 continue;
848 if ((ks->ks_size & j) == 0)
849 continue;
850 name = kmemnames[i] ? kmemnames[i] : "undefined";
851 len += 2 + strlen(name);
852 if (first)
853 printf("%8d %s", j, name);
854 else
855 printf(",");
856 if (len >= 80) {
857 printf("\n\t ");
858 len = 10 + strlen(name);
859 }
860 if (!first)
861 printf(" %s", name);
862 first = 0;
863 }
864 printf("\n");
865 }
866
867 (void)printf(
868 "\nMemory statistics by type Type Kern\n");
869 (void)printf(
870 " Type InUse MemUse HighUse Limit Requests Limit Limit Size(s)\n");
871 for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
872 if (ks->ks_calls == 0)
873 continue;
874 (void)printf("%12s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u",
875 kmemnames[i] ? kmemnames[i] : "undefined",
876 ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
877 (ks->ks_maxused + 1023) / 1024,
878 (ks->ks_limit + 1023) / 1024, ks->ks_calls,
879 ks->ks_limblocks, ks->ks_mapblocks);
880 first = 1;
881 for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
882 if ((ks->ks_size & j) == 0)
883 continue;
884 if (first)
885 printf(" %d", j);
886 else
887 printf(",%d", j);
888 first = 0;
889 }
890 printf("\n");
891 totuse += ks->ks_memuse;
892 totreq += ks->ks_calls;
893 }
894 (void)printf("\nMemory Totals: In Use Free Requests\n");
895 (void)printf(" %7ldK %6ldK %8ld\n",
896 (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq);
897 }
898
899 /*
900 * kread reads something from the kernel, given its nlist index.
901 */
902 void
903 kread(nlx, addr, size)
904 int nlx;
905 void *addr;
906 size_t size;
907 {
908 char *sym;
909
910 if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
911 sym = namelist[nlx].n_name;
912 if (*sym == '_')
913 ++sym;
914 (void)fprintf(stderr,
915 "vmstat: symbol %s not defined\n", sym);
916 exit(1);
917 }
918 if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) {
919 sym = namelist[nlx].n_name;
920 if (*sym == '_')
921 ++sym;
922 (void)fprintf(stderr, "vmstat: %s: %s\n", sym, kvm_geterr(kd));
923 exit(1);
924 }
925 }
926
927 void
928 usage()
929 {
930 (void)fprintf(stderr,
931 #ifndef NEWVM
932 "usage: vmstat [-fimst] [-c count] [-M core] \
933 [-N system] [-w wait] [disks]\n");
934 #else
935 "usage: vmstat [-ims] [-c count] [-M core] \
936 [-N system] [-w wait] [disks]\n");
937 #endif
938 exit(1);
939 }
940
941