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