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