1 /* 2 * Copyright (c) 1980, 1986, 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static const char copyright[] = 36 "@(#) Copyright (c) 1980, 1986, 1991, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93"; 43 #endif 44 static const char rcsid[] = 45 "$Id: vmstat.c,v 1.34 1999/05/10 00:33:32 imp Exp $"; 46 #endif /* not lint */ 47 48 #include <sys/param.h> 49 #include <sys/time.h> 50 #include <sys/proc.h> 51 #include <sys/dkstat.h> 52 #include <sys/buf.h> 53 #include <sys/uio.h> 54 #include <sys/namei.h> 55 #include <sys/malloc.h> 56 #include <sys/signal.h> 57 #include <sys/fcntl.h> 58 #include <sys/ioctl.h> 59 #include <sys/sysctl.h> 60 #include <sys/vmmeter.h> 61 62 #include <vm/vm_param.h> 63 #include <vm/vm_zone.h> 64 65 #include <ctype.h> 66 #include <err.h> 67 #include <errno.h> 68 #include <kvm.h> 69 #include <limits.h> 70 #include <nlist.h> 71 #include <paths.h> 72 #include <stdio.h> 73 #include <stdlib.h> 74 #include <string.h> 75 #include <sysexits.h> 76 #include <time.h> 77 #include <unistd.h> 78 #include <devstat.h> 79 80 struct nlist namelist[] = { 81 #define X_CPTIME 0 82 { "_cp_time" }, 83 #define X_SUM 1 84 { "_cnt" }, 85 #define X_BOOTTIME 2 86 { "_boottime" }, 87 #define X_HZ 3 88 { "_hz" }, 89 #define X_STATHZ 4 90 { "_stathz" }, 91 #define X_NCHSTATS 5 92 { "_nchstats" }, 93 #define X_INTRNAMES 6 94 { "_intrnames" }, 95 #define X_EINTRNAMES 7 96 { "_eintrnames" }, 97 #define X_INTRCNT 8 98 { "_intrcnt" }, 99 #define X_EINTRCNT 9 100 { "_eintrcnt" }, 101 #define X_KMEMSTATISTICS 10 102 { "_kmemstatistics" }, 103 #define X_KMEMBUCKETS 11 104 { "_bucket" }, 105 #define X_ZLIST 12 106 { "_zlist" }, 107 #ifdef notyet 108 #define X_DEFICIT 13 109 { "_deficit" }, 110 #define X_FORKSTAT 14 111 { "_forkstat" }, 112 #define X_REC 15 113 { "_rectime" }, 114 #define X_PGIN 16 115 { "_pgintime" }, 116 #define X_XSTATS 17 117 { "_xstats" }, 118 #define X_END 18 119 #else 120 #define X_END 13 121 #endif 122 #if defined(hp300) || defined(luna68k) 123 #define X_HPDINIT (X_END) 124 { "_hp_dinit" }, 125 #endif 126 #ifdef mips 127 #define X_SCSI_DINIT (X_END) 128 { "_scsi_dinit" }, 129 #endif 130 #ifdef tahoe 131 #define X_VBDINIT (X_END) 132 { "_vbdinit" }, 133 #define X_CKEYSTATS (X_END+1) 134 { "_ckeystats" }, 135 #define X_DKEYSTATS (X_END+2) 136 { "_dkeystats" }, 137 #endif 138 #ifdef vax 139 #define X_MBDINIT (X_END) 140 { "_mbdinit" }, 141 #define X_UBDINIT (X_END+1) 142 { "_ubdinit" }, 143 #endif 144 { "" }, 145 }; 146 147 struct statinfo cur, last; 148 int num_devices, maxshowdevs; 149 long generation; 150 struct device_selection *dev_select; 151 int num_selected; 152 struct devstat_match *matches; 153 int num_matches = 0; 154 int num_devices_specified, num_selections; 155 long select_generation; 156 char **specified_devices; 157 devstat_select_mode select_mode; 158 159 struct vmmeter sum, osum; 160 161 int winlines = 20; 162 int nflag = 0; 163 164 kvm_t *kd; 165 166 #define FORKSTAT 0x01 167 #define INTRSTAT 0x02 168 #define MEMSTAT 0x04 169 #define SUMSTAT 0x08 170 #define TIMESTAT 0x10 171 #define VMSTAT 0x20 172 #define ZMEMSTAT 0x40 173 174 void cpustats(), dointr(), domem(), dosum(), dozmem(); 175 void dovmstat(), kread(), usage(); 176 #ifdef notyet 177 void dotimes(), doforkst(); 178 #endif 179 void printhdr __P((void)); 180 static void devstats(); 181 182 int 183 main(argc, argv) 184 register int argc; 185 register char **argv; 186 { 187 register int c, todo; 188 u_int interval; 189 int reps; 190 char *memf, *nlistf; 191 char errbuf[_POSIX2_LINE_MAX]; 192 char *err_str; 193 194 memf = nlistf = NULL; 195 interval = reps = todo = 0; 196 maxshowdevs = 2; 197 while ((c = getopt(argc, argv, "c:fiM:mN:n:p:stw:z")) != -1) { 198 switch (c) { 199 case 'c': 200 reps = atoi(optarg); 201 break; 202 case 'f': 203 #ifdef notyet 204 todo |= FORKSTAT; 205 #else 206 errx(EX_USAGE, "sorry, -f is not (re)implemented yet"); 207 #endif 208 break; 209 case 'i': 210 todo |= INTRSTAT; 211 break; 212 case 'M': 213 memf = optarg; 214 break; 215 case 'm': 216 todo |= MEMSTAT; 217 break; 218 case 'N': 219 nlistf = optarg; 220 break; 221 case 'n': 222 nflag = 1; 223 maxshowdevs = atoi(optarg); 224 if (maxshowdevs < 0) 225 errx(1, "number of devices %d is < 0", 226 maxshowdevs); 227 break; 228 case 'p': 229 if (buildmatch(optarg, &matches, &num_matches) != 0) 230 errx(1, "%s", devstat_errbuf); 231 break; 232 case 's': 233 todo |= SUMSTAT; 234 break; 235 case 't': 236 #ifdef notyet 237 todo |= TIMESTAT; 238 #else 239 errx(EX_USAGE, "sorry, -t is not (re)implemented yet"); 240 #endif 241 break; 242 case 'w': 243 interval = atoi(optarg); 244 break; 245 case 'z': 246 todo |= ZMEMSTAT; 247 break; 248 case '?': 249 default: 250 usage(); 251 } 252 } 253 argc -= optind; 254 argv += optind; 255 256 if (todo == 0) 257 todo = VMSTAT; 258 259 /* 260 * Discard setgid privileges if not the running kernel so that bad 261 * guys can't print interesting stuff from kernel memory. 262 */ 263 if (nlistf != NULL || memf != NULL) 264 setgid(getgid()); 265 266 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 267 if (kd == 0) 268 errx(1, "kvm_openfiles: %s", errbuf); 269 270 if ((c = kvm_nlist(kd, namelist)) != 0) { 271 if (c > 0) { 272 warnx("undefined symbols:"); 273 for (c = 0; 274 c < sizeof(namelist)/sizeof(namelist[0]); c++) 275 if (namelist[c].n_type == 0) 276 fprintf(stderr, " %s", 277 namelist[c].n_name); 278 (void)fputc('\n', stderr); 279 } else 280 warnx("kvm_nlist: %s", kvm_geterr(kd)); 281 exit(1); 282 } 283 284 if (todo & VMSTAT) { 285 char **getdrivedata(); 286 struct winsize winsize; 287 288 /* 289 * Make sure that the userland devstat version matches the 290 * kernel devstat version. If not, exit and print a 291 * message informing the user of his mistake. 292 */ 293 if (checkversion() < 0) 294 errx(1, "%s", devstat_errbuf); 295 296 297 argv = getdrivedata(argv); 298 winsize.ws_row = 0; 299 (void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize); 300 if (winsize.ws_row > 0) 301 winlines = winsize.ws_row; 302 303 } 304 305 #define BACKWARD_COMPATIBILITY 306 #ifdef BACKWARD_COMPATIBILITY 307 if (*argv) { 308 interval = atoi(*argv); 309 if (*++argv) 310 reps = atoi(*argv); 311 } 312 #endif 313 314 if (interval) { 315 if (!reps) 316 reps = -1; 317 } else if (reps) 318 interval = 1; 319 320 #ifdef notyet 321 if (todo & FORKSTAT) 322 doforkst(); 323 #endif 324 if (todo & MEMSTAT) 325 domem(); 326 if (todo & ZMEMSTAT) 327 dozmem(); 328 if (todo & SUMSTAT) 329 dosum(); 330 #ifdef notyet 331 if (todo & TIMESTAT) 332 dotimes(); 333 #endif 334 if (todo & INTRSTAT) 335 dointr(); 336 if (todo & VMSTAT) 337 dovmstat(interval, reps); 338 exit(0); 339 } 340 341 char ** 342 getdrivedata(argv) 343 char **argv; 344 { 345 register int i; 346 char buf[30]; 347 348 if ((num_devices = getnumdevs()) < 0) 349 errx(1, "%s", devstat_errbuf); 350 351 cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 352 last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 353 bzero(cur.dinfo, sizeof(struct devinfo)); 354 bzero(last.dinfo, sizeof(struct devinfo)); 355 356 if (getdevs(&cur) == -1) 357 errx(1, "%s", devstat_errbuf); 358 359 num_devices = cur.dinfo->numdevs; 360 generation = cur.dinfo->generation; 361 362 specified_devices = (char **)malloc(sizeof(char *)); 363 for (num_devices_specified = 0; *argv; ++argv) { 364 if (isdigit(**argv)) 365 break; 366 num_devices_specified++; 367 specified_devices = (char **)realloc(specified_devices, 368 sizeof(char *) * 369 num_devices_specified); 370 specified_devices[num_devices_specified - 1] = *argv; 371 } 372 dev_select = NULL; 373 374 if (nflag == 0 && maxshowdevs < num_devices_specified) 375 maxshowdevs = num_devices_specified; 376 377 /* 378 * People are generally only interested in disk statistics when 379 * they're running vmstat. So, that's what we're going to give 380 * them if they don't specify anything by default. We'll also give 381 * them any other random devices in the system so that we get to 382 * maxshowdevs devices, if that many devices exist. If the user 383 * specifies devices on the command line, either through a pattern 384 * match or by naming them explicitly, we will give the user only 385 * those devices. 386 */ 387 if ((num_devices_specified == 0) && (num_matches == 0)) { 388 if (buildmatch("da", &matches, &num_matches) != 0) 389 errx(1, "%s", devstat_errbuf); 390 391 select_mode = DS_SELECT_ADD; 392 } else 393 select_mode = DS_SELECT_ONLY; 394 395 /* 396 * At this point, selectdevs will almost surely indicate that the 397 * device list has changed, so we don't look for return values of 0 398 * or 1. If we get back -1, though, there is an error. 399 */ 400 if (selectdevs(&dev_select, &num_selected, &num_selections, 401 &select_generation, generation, cur.dinfo->devices, 402 num_devices, matches, num_matches, specified_devices, 403 num_devices_specified, select_mode, 404 maxshowdevs, 0) == -1) 405 errx(1, "%s", devstat_errbuf); 406 407 return(argv); 408 } 409 410 long 411 getuptime() 412 { 413 static time_t now, boottime; 414 time_t uptime; 415 416 if (boottime == 0) 417 kread(X_BOOTTIME, &boottime, sizeof(boottime)); 418 (void)time(&now); 419 uptime = now - boottime; 420 if (uptime <= 0 || uptime > 60*60*24*365*10) 421 errx(1, "time makes no sense; namelist must be wrong"); 422 return(uptime); 423 } 424 425 int hz, hdrcnt; 426 427 void 428 dovmstat(interval, reps) 429 u_int interval; 430 int reps; 431 { 432 struct vmtotal total; 433 time_t uptime, halfuptime; 434 struct devinfo *tmp_dinfo; 435 void needhdr(); 436 int mib[2], size; 437 438 uptime = getuptime(); 439 halfuptime = uptime / 2; 440 (void)signal(SIGCONT, needhdr); 441 442 if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0) 443 kread(X_STATHZ, &hz, sizeof(hz)); 444 if (!hz) 445 kread(X_HZ, &hz, sizeof(hz)); 446 447 for (hdrcnt = 1;;) { 448 if (!--hdrcnt) 449 printhdr(); 450 kread(X_CPTIME, cur.cp_time, sizeof(cur.cp_time)); 451 452 tmp_dinfo = last.dinfo; 453 last.dinfo = cur.dinfo; 454 cur.dinfo = tmp_dinfo; 455 last.busy_time = cur.busy_time; 456 457 /* 458 * Here what we want to do is refresh our device stats. 459 * getdevs() returns 1 when the device list has changed. 460 * If the device list has changed, we want to go through 461 * the selection process again, in case a device that we 462 * were previously displaying has gone away. 463 */ 464 switch (getdevs(&cur)) { 465 case -1: 466 errx(1, "%s", devstat_errbuf); 467 break; 468 case 1: { 469 int retval; 470 471 num_devices = cur.dinfo->numdevs; 472 generation = cur.dinfo->generation; 473 474 retval = selectdevs(&dev_select, &num_selected, 475 &num_selections, &select_generation, 476 generation, cur.dinfo->devices, 477 num_devices, matches, num_matches, 478 specified_devices, 479 num_devices_specified, select_mode, 480 maxshowdevs, 0); 481 switch (retval) { 482 case -1: 483 errx(1, "%s", devstat_errbuf); 484 break; 485 case 1: 486 printhdr(); 487 break; 488 default: 489 break; 490 } 491 } 492 default: 493 break; 494 } 495 496 kread(X_SUM, &sum, sizeof(sum)); 497 size = sizeof(total); 498 mib[0] = CTL_VM; 499 mib[1] = VM_METER; 500 if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) { 501 printf("Can't get kerninfo: %s\n", strerror(errno)); 502 bzero(&total, sizeof(total)); 503 } 504 (void)printf("%2d%2d%2d", 505 total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); 506 #define pgtok(a) ((a) * sum.v_page_size >> 10) 507 #define rate(x) (((x) + halfuptime) / uptime) /* round */ 508 (void)printf("%8ld%6ld ", 509 (long)pgtok(total.t_avm), (long)pgtok(total.t_free)); 510 (void)printf("%4lu ", 511 (u_long)rate(sum.v_vm_faults - osum.v_vm_faults)); 512 (void)printf("%3lu ", 513 (u_long)rate(sum.v_reactivated - osum.v_reactivated)); 514 (void)printf("%3lu ", 515 (u_long)rate(sum.v_swapin + sum.v_vnodein - 516 (osum.v_swapin + osum.v_vnodein))); 517 (void)printf("%3lu ", 518 (u_long)rate(sum.v_swapout + sum.v_vnodeout - 519 (osum.v_swapout + osum.v_vnodeout))); 520 (void)printf("%3lu ", 521 (u_long)rate(sum.v_tfree - osum.v_tfree)); 522 (void)printf("%3lu ", 523 (u_long)rate(sum.v_pdpages - osum.v_pdpages)); 524 devstats(); 525 (void)printf("%4lu %4lu %3lu ", 526 (u_long)rate(sum.v_intr - osum.v_intr), 527 (u_long)rate(sum.v_syscall - osum.v_syscall), 528 (u_long)rate(sum.v_swtch - osum.v_swtch)); 529 cpustats(); 530 (void)printf("\n"); 531 (void)fflush(stdout); 532 if (reps >= 0 && --reps <= 0) 533 break; 534 osum = sum; 535 uptime = interval; 536 /* 537 * We round upward to avoid losing low-frequency events 538 * (i.e., >= 1 per interval but < 1 per second). 539 */ 540 if (interval != 1) 541 halfuptime = (uptime + 1) / 2; 542 else 543 halfuptime = 0; 544 (void)sleep(interval); 545 } 546 } 547 548 void 549 printhdr() 550 { 551 int i, num_shown; 552 553 num_shown = (num_selected < maxshowdevs) ? num_selected : maxshowdevs; 554 (void)printf(" procs memory page%*s", 19, ""); 555 if (num_shown > 1) 556 (void)printf(" disks %*s", num_shown * 4 - 7, ""); 557 else if (num_shown == 1) 558 (void)printf("disk"); 559 (void)printf(" faults cpu\n"); 560 (void)printf(" r b w avm fre flt re pi po fr sr "); 561 for (i = 0; i < num_devices; i++) 562 if ((dev_select[i].selected) 563 && (dev_select[i].selected <= maxshowdevs)) 564 (void)printf("%c%c%d ", dev_select[i].device_name[0], 565 dev_select[i].device_name[1], 566 dev_select[i].unit_number); 567 (void)printf(" in sy cs us sy id\n"); 568 hdrcnt = winlines - 2; 569 } 570 571 /* 572 * Force a header to be prepended to the next output. 573 */ 574 void 575 needhdr() 576 { 577 578 hdrcnt = 1; 579 } 580 581 #ifdef notyet 582 void 583 dotimes() 584 { 585 u_int pgintime, rectime; 586 587 kread(X_REC, &rectime, sizeof(rectime)); 588 kread(X_PGIN, &pgintime, sizeof(pgintime)); 589 kread(X_SUM, &sum, sizeof(sum)); 590 (void)printf("%u reclaims, %u total time (usec)\n", 591 sum.v_pgrec, rectime); 592 (void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec); 593 (void)printf("\n"); 594 (void)printf("%u page ins, %u total time (msec)\n", 595 sum.v_pgin, pgintime / 10); 596 (void)printf("average: %8.1f msec / page in\n", 597 pgintime / (sum.v_pgin * 10.0)); 598 } 599 #endif 600 601 long 602 pct(top, bot) 603 long top, bot; 604 { 605 long ans; 606 607 if (bot == 0) 608 return(0); 609 ans = (quad_t)top * 100 / bot; 610 return (ans); 611 } 612 613 #define PCT(top, bot) pct((long)(top), (long)(bot)) 614 615 #if defined(tahoe) 616 #include <machine/cpu.h> 617 #endif 618 619 void 620 dosum() 621 { 622 struct nchstats nchstats; 623 long nchtotal; 624 #if defined(tahoe) 625 struct keystats keystats; 626 #endif 627 628 kread(X_SUM, &sum, sizeof(sum)); 629 (void)printf("%9u cpu context switches\n", sum.v_swtch); 630 (void)printf("%9u device interrupts\n", sum.v_intr); 631 (void)printf("%9u software interrupts\n", sum.v_soft); 632 #ifdef vax 633 (void)printf("%9u pseudo-dma dz interrupts\n", sum.v_pdma); 634 #endif 635 (void)printf("%9u traps\n", sum.v_trap); 636 (void)printf("%9u system calls\n", sum.v_syscall); 637 (void)printf("%9u swap pager pageins\n", sum.v_swapin); 638 (void)printf("%9u swap pager pages paged in\n", sum.v_swappgsin); 639 (void)printf("%9u swap pager pageouts\n", sum.v_swapout); 640 (void)printf("%9u swap pager pages paged out\n", sum.v_swappgsout); 641 (void)printf("%9u vnode pager pageins\n", sum.v_vnodein); 642 (void)printf("%9u vnode pager pages paged in\n", sum.v_vnodepgsin); 643 (void)printf("%9u vnode pager pageouts\n", sum.v_vnodeout); 644 (void)printf("%9u vnode pager pages paged out\n", sum.v_vnodepgsout); 645 (void)printf("%9u page daemon wakeups\n", sum.v_pdwakeups); 646 (void)printf("%9u pages examined by the page daemon\n", sum.v_pdpages); 647 (void)printf("%9u pages reactivated\n", sum.v_reactivated); 648 (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults); 649 (void)printf("%9u copy-on-write optimized faults\n", sum.v_cow_optim); 650 (void)printf("%9u zero fill pages zeroed\n", sum.v_zfod); 651 (void)printf("%9u zero fill pages prezeroed\n", sum.v_ozfod); 652 (void)printf("%9u intransit blocking page faults\n", sum.v_intrans); 653 (void)printf("%9u total VM faults taken\n", sum.v_vm_faults); 654 (void)printf("%9u pages freed\n", sum.v_tfree); 655 (void)printf("%9u pages freed by daemon\n", sum.v_dfree); 656 (void)printf("%9u pages freed by exiting processes\n", sum.v_pfree); 657 (void)printf("%9u pages active\n", sum.v_active_count); 658 (void)printf("%9u pages inactive\n", sum.v_inactive_count); 659 (void)printf("%9u pages in VM cache\n", sum.v_cache_count); 660 (void)printf("%9u pages wired down\n", sum.v_wire_count); 661 (void)printf("%9u pages free\n", sum.v_free_count); 662 (void)printf("%9u bytes per page\n", sum.v_page_size); 663 kread(X_NCHSTATS, &nchstats, sizeof(nchstats)); 664 nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits + 665 nchstats.ncs_badhits + nchstats.ncs_falsehits + 666 nchstats.ncs_miss + nchstats.ncs_long; 667 (void)printf("%9ld total name lookups\n", nchtotal); 668 (void)printf( 669 "%9s cache hits (%ld%% pos + %ld%% neg) system %ld%% per-directory\n", 670 "", PCT(nchstats.ncs_goodhits, nchtotal), 671 PCT(nchstats.ncs_neghits, nchtotal), 672 PCT(nchstats.ncs_pass2, nchtotal)); 673 (void)printf("%9s deletions %ld%%, falsehits %ld%%, toolong %ld%%\n", "", 674 PCT(nchstats.ncs_badhits, nchtotal), 675 PCT(nchstats.ncs_falsehits, nchtotal), 676 PCT(nchstats.ncs_long, nchtotal)); 677 #if defined(tahoe) 678 kread(X_CKEYSTATS, &keystats, sizeof(keystats)); 679 (void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n", 680 keystats.ks_allocs, "code cache keys allocated", 681 PCT(keystats.ks_allocfree, keystats.ks_allocs), 682 PCT(keystats.ks_norefs, keystats.ks_allocs), 683 PCT(keystats.ks_taken, keystats.ks_allocs), 684 PCT(keystats.ks_shared, keystats.ks_allocs)); 685 kread(X_DKEYSTATS, &keystats, sizeof(keystats)); 686 (void)printf("%9d %s (free %d%% norefs %d%% taken %d%% shared %d%%)\n", 687 keystats.ks_allocs, "data cache keys allocated", 688 PCT(keystats.ks_allocfree, keystats.ks_allocs), 689 PCT(keystats.ks_norefs, keystats.ks_allocs), 690 PCT(keystats.ks_taken, keystats.ks_allocs), 691 PCT(keystats.ks_shared, keystats.ks_allocs)); 692 #endif 693 } 694 695 #ifdef notyet 696 void 697 doforkst() 698 { 699 struct forkstat fks; 700 701 kread(X_FORKSTAT, &fks, sizeof(struct forkstat)); 702 (void)printf("%d forks, %d pages, average %.2f\n", 703 fks.cntfork, fks.sizfork, (double)fks.sizfork / fks.cntfork); 704 (void)printf("%d vforks, %d pages, average %.2f\n", 705 fks.cntvfork, fks.sizvfork, (double)fks.sizvfork / fks.cntvfork); 706 } 707 #endif 708 709 static void 710 devstats() 711 { 712 register int dn, state; 713 long double transfers_per_second; 714 long double busy_seconds; 715 long tmp; 716 717 for (state = 0; state < CPUSTATES; ++state) { 718 tmp = cur.cp_time[state]; 719 cur.cp_time[state] -= last.cp_time[state]; 720 last.cp_time[state] = tmp; 721 } 722 723 busy_seconds = compute_etime(cur.busy_time, last.busy_time); 724 725 for (dn = 0; dn < num_devices; dn++) { 726 int di; 727 728 if ((dev_select[dn].selected == 0) 729 || (dev_select[dn].selected > maxshowdevs)) 730 continue; 731 732 di = dev_select[dn].position; 733 734 if (compute_stats(&cur.dinfo->devices[di], 735 &last.dinfo->devices[di], busy_seconds, 736 NULL, NULL, NULL, 737 NULL, &transfers_per_second, NULL, 738 NULL, NULL) != 0) 739 errx(1, "%s", devstat_errbuf); 740 741 printf("%3.0Lf ", transfers_per_second); 742 } 743 } 744 745 void 746 cpustats() 747 { 748 register int state; 749 double pct, total; 750 751 total = 0; 752 for (state = 0; state < CPUSTATES; ++state) 753 total += cur.cp_time[state]; 754 if (total) 755 pct = 100 / total; 756 else 757 pct = 0; 758 (void)printf("%2.0f ", (cur.cp_time[CP_USER] + 759 cur.cp_time[CP_NICE]) * pct); 760 (void)printf("%2.0f ", (cur.cp_time[CP_SYS] + 761 cur.cp_time[CP_INTR]) * pct); 762 (void)printf("%2.0f", cur.cp_time[CP_IDLE] * pct); 763 } 764 765 void 766 dointr() 767 { 768 register long *intrcnt, inttotal, uptime; 769 register int nintr, inamlen; 770 register char *intrname; 771 772 uptime = getuptime(); 773 nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value; 774 inamlen = 775 namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value; 776 intrcnt = malloc((size_t)nintr); 777 intrname = malloc((size_t)inamlen); 778 if (intrcnt == NULL || intrname == NULL) 779 errx(1, "malloc"); 780 kread(X_INTRCNT, intrcnt, (size_t)nintr); 781 kread(X_INTRNAMES, intrname, (size_t)inamlen); 782 (void)printf("interrupt total rate\n"); 783 inttotal = 0; 784 nintr /= sizeof(long); 785 while (--nintr >= 0) { 786 if (*intrcnt) 787 (void)printf("%-12s %8ld %8ld\n", intrname, 788 *intrcnt, *intrcnt / uptime); 789 intrname += strlen(intrname) + 1; 790 inttotal += *intrcnt++; 791 } 792 (void)printf("Total %8ld %8ld\n", inttotal, inttotal / uptime); 793 } 794 795 #define MAX_KMSTATS 200 796 797 void 798 domem() 799 { 800 register struct kmembuckets *kp; 801 register struct malloc_type *ks; 802 register int i, j; 803 int len, size, first, nkms; 804 long totuse = 0, totfree = 0, totreq = 0; 805 const char *name; 806 struct malloc_type kmemstats[MAX_KMSTATS], *kmsp; 807 char *kmemnames[MAX_KMSTATS]; 808 char buf[1024]; 809 struct kmembuckets buckets[MINBUCKET + 16]; 810 811 kread(X_KMEMBUCKETS, buckets, sizeof(buckets)); 812 kread(X_KMEMSTATISTICS, &kmsp, sizeof(kmsp)); 813 for (nkms = 0; nkms < MAX_KMSTATS && kmsp != NULL; nkms++) { 814 if (sizeof(kmemstats[0]) != kvm_read(kd, (u_long)kmsp, 815 &kmemstats[nkms], sizeof(kmemstats[0]))) 816 err(1, "kvm_read(%p)", (void *)kmsp); 817 if (sizeof(buf) != kvm_read(kd, 818 (u_long)kmemstats[nkms].ks_shortdesc, buf, sizeof(buf))) 819 err(1, "kvm_read(%p)", 820 (void *)kmemstats[nkms].ks_shortdesc); 821 buf[sizeof(buf) - 1] = '\0'; 822 kmemstats[nkms].ks_shortdesc = strdup(buf); 823 kmsp = kmemstats[nkms].ks_next; 824 } 825 if (kmsp != NULL) 826 warnx("truncated to the first %d memory types", nkms); 827 (void)printf("Memory statistics by bucket size\n"); 828 (void)printf( 829 "Size In Use Free Requests HighWater Couldfree\n"); 830 for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) { 831 if (kp->kb_calls == 0) 832 continue; 833 size = 1 << i; 834 if(size < 1024) 835 (void)printf("%4d",size); 836 else 837 (void)printf("%3dK",size>>10); 838 (void)printf(" %8ld %6ld %10ld %7ld %10ld\n", 839 kp->kb_total - kp->kb_totalfree, 840 kp->kb_totalfree, kp->kb_calls, 841 kp->kb_highwat, kp->kb_couldfree); 842 totfree += size * kp->kb_totalfree; 843 } 844 845 (void)printf("\nMemory usage type by bucket size\n"); 846 (void)printf("Size Type(s)\n"); 847 kp = &buckets[MINBUCKET]; 848 for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) { 849 if (kp->kb_calls == 0) 850 continue; 851 first = 1; 852 len = 8; 853 for (i = 0, ks = &kmemstats[0]; i < nkms; i++, ks++) { 854 if (ks->ks_calls == 0) 855 continue; 856 if ((ks->ks_size & j) == 0) 857 continue; 858 name = ks->ks_shortdesc; 859 len += 2 + strlen(name); 860 if (first && j < 1024) 861 printf("%4d %s", j, name); 862 else if (first) 863 printf("%3dK %s", j>>10, name); 864 else 865 printf(","); 866 if (len >= 79) { 867 printf("\n\t "); 868 len = 10 + strlen(name); 869 } 870 if (!first) 871 printf(" %s", name); 872 first = 0; 873 } 874 printf("\n"); 875 } 876 877 (void)printf( 878 "\nMemory statistics by type Type Kern\n"); 879 (void)printf( 880 " Type InUse MemUse HighUse Limit Requests Limit Limit Size(s)\n"); 881 for (i = 0, ks = &kmemstats[0]; i < nkms; i++, ks++) { 882 if (ks->ks_calls == 0) 883 continue; 884 (void)printf("%13s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u", 885 ks->ks_shortdesc, 886 ks->ks_inuse, (ks->ks_memuse + 1023) / 1024, 887 (ks->ks_maxused + 1023) / 1024, 888 (ks->ks_limit + 1023) / 1024, ks->ks_calls, 889 ks->ks_limblocks, ks->ks_mapblocks); 890 first = 1; 891 for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) { 892 if ((ks->ks_size & j) == 0) 893 continue; 894 if (first) 895 printf(" "); 896 else 897 printf(","); 898 if(j<1024) 899 printf("%d",j); 900 else 901 printf("%dK",j>>10); 902 first = 0; 903 } 904 printf("\n"); 905 totuse += ks->ks_memuse; 906 totreq += ks->ks_calls; 907 } 908 (void)printf("\nMemory Totals: In Use Free Requests\n"); 909 (void)printf(" %7ldK %6ldK %8ld\n", 910 (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq); 911 } 912 913 void 914 dozmem() 915 { 916 vm_zone_t zonep; 917 int nmax = 512; 918 int zused_bytes = 0; 919 int ztotal_bytes = 0; 920 921 printf( 922 "\n" 923 "%-16s%-8s%-8s%-8s\n", 924 "ZONE", 925 "used", 926 "total", 927 "mem-use" 928 ); 929 930 kread(X_ZLIST, &zonep, sizeof(zonep)); 931 while (zonep != NULL && nmax) { 932 struct vm_zone zone; 933 char buf[32]; 934 int n; 935 936 if (kvm_read(kd, (u_long)zonep, &zone, sizeof(zone)) != sizeof(zone)) 937 break; 938 n = kvm_read(kd, (u_long)zone.zname, buf, sizeof(buf) - 1); 939 if (n < 0) 940 n = 0; 941 buf[n] = 0; 942 943 printf( 944 "%-15.15s %-7d %-7d %4d/%dK\n", 945 buf, 946 zone.ztotal - zone.zfreecnt, 947 zone.ztotal, 948 (zone.ztotal - zone.zfreecnt) * zone.zsize / 1024, 949 zone.ztotal * zone.zsize / 1024 950 ); 951 zused_bytes += (zone.ztotal - zone.zfreecnt) * zone.zsize; 952 ztotal_bytes += zone.ztotal * zone.zsize; 953 --nmax; 954 zonep = zone.znext; 955 } 956 printf( 957 "------------------------------------------\n" 958 "%-15.15s %-7s %-7s %4d/%dK\n\n", 959 "TOTAL", 960 "", 961 "", 962 zused_bytes / 1024, 963 ztotal_bytes / 1024 964 ); 965 } 966 967 /* 968 * kread reads something from the kernel, given its nlist index. 969 */ 970 void 971 kread(nlx, addr, size) 972 int nlx; 973 void *addr; 974 size_t size; 975 { 976 char *sym; 977 978 if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) { 979 sym = namelist[nlx].n_name; 980 if (*sym == '_') 981 ++sym; 982 errx(1, "symbol %s not defined", sym); 983 } 984 if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) { 985 sym = namelist[nlx].n_name; 986 if (*sym == '_') 987 ++sym; 988 errx(1, "%s: %s", sym, kvm_geterr(kd)); 989 } 990 } 991 992 void 993 usage() 994 { 995 (void)fprintf(stderr, 996 "usage: vmstat [-imsz] [-c count] [-M core] [-N system] [-w wait] [disks]\n"); 997 exit(1); 998 } 999