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