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