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