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 #if 0 41 #ifndef lint 42 static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93"; 43 #endif /* not lint */ 44 #endif 45 46 #include <sys/cdefs.h> 47 __FBSDID("$FreeBSD$"); 48 49 #include <sys/param.h> 50 #include <sys/time.h> 51 #include <sys/proc.h> 52 #include <sys/uio.h> 53 #include <sys/namei.h> 54 #include <sys/malloc.h> 55 #include <sys/signal.h> 56 #include <sys/fcntl.h> 57 #include <sys/ioctl.h> 58 #include <sys/resource.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 <devstat.h> 66 #include <err.h> 67 #include <errno.h> 68 #include <kvm.h> 69 #include <limits.h> 70 #include <memstat.h> 71 #include <nlist.h> 72 #include <paths.h> 73 #include <stdio.h> 74 #include <stdlib.h> 75 #include <string.h> 76 #include <sysexits.h> 77 #include <time.h> 78 #include <unistd.h> 79 #include <libutil.h> 80 81 static char da[] = "da"; 82 83 static struct nlist namelist[] = { 84 #define X_SUM 0 85 { "_cnt" }, 86 #define X_BOOTTIME 1 87 { "_boottime" }, 88 #define X_HZ 2 89 { "_hz" }, 90 #define X_STATHZ 3 91 { "_stathz" }, 92 #define X_NCHSTATS 4 93 { "_nchstats" }, 94 #define X_INTRNAMES 5 95 { "_intrnames" }, 96 #define X_EINTRNAMES 6 97 { "_eintrnames" }, 98 #define X_INTRCNT 7 99 { "_intrcnt" }, 100 #define X_EINTRCNT 8 101 { "_eintrcnt" }, 102 #define X_KMEMSTATS 9 103 { "_kmemstatistics" }, 104 #define X_KMEMZONES 10 105 { "_kmemzones" }, 106 #ifdef notyet 107 #define X_DEFICIT XXX 108 { "_deficit" }, 109 #define X_REC XXX 110 { "_rectime" }, 111 #define X_PGIN XXX 112 { "_pgintime" }, 113 #define X_XSTATS XXX 114 { "_xstats" }, 115 #define X_END XXX 116 #else 117 #define X_END 11 118 #endif 119 { "" }, 120 }; 121 122 static struct statinfo cur, last; 123 static int num_devices, maxshowdevs; 124 static long generation; 125 static struct device_selection *dev_select; 126 static int num_selected; 127 static struct devstat_match *matches; 128 static int num_matches = 0; 129 static int num_devices_specified, num_selections; 130 static long select_generation; 131 static char **specified_devices; 132 static devstat_select_mode select_mode; 133 134 static struct vmmeter sum, osum; 135 136 static int winlines = 20; 137 static int aflag; 138 static int nflag; 139 static int Pflag; 140 static int hflag; 141 142 static kvm_t *kd; 143 144 #define FORKSTAT 0x01 145 #define INTRSTAT 0x02 146 #define MEMSTAT 0x04 147 #define SUMSTAT 0x08 148 #define TIMESTAT 0x10 149 #define VMSTAT 0x20 150 #define ZMEMSTAT 0x40 151 152 static void cpustats(void); 153 static void pcpustats(int, u_long, int); 154 static void devstats(void); 155 static void doforkst(void); 156 static void dointr(void); 157 static void dosum(void); 158 static void dovmstat(unsigned int, int); 159 static void domemstat_malloc(void); 160 static void domemstat_zone(void); 161 static void kread(int, void *, size_t); 162 static void kreado(int, void *, size_t, size_t); 163 static char *kgetstr(const char *); 164 static void needhdr(int); 165 static void printhdr(int, u_long); 166 static void usage(void); 167 168 static long pct(long, long); 169 static long getuptime(void); 170 171 static char **getdrivedata(char **); 172 173 int 174 main(int argc, char *argv[]) 175 { 176 int c, todo; 177 unsigned int interval; 178 int reps; 179 char *memf, *nlistf; 180 char errbuf[_POSIX2_LINE_MAX]; 181 182 memf = nlistf = NULL; 183 interval = reps = todo = 0; 184 maxshowdevs = 2; 185 hflag = isatty(1); 186 while ((c = getopt(argc, argv, "ac:fhHiM:mN:n:Pp:stw:z")) != -1) { 187 switch (c) { 188 case 'a': 189 aflag++; 190 break; 191 case 'c': 192 reps = atoi(optarg); 193 break; 194 case 'P': 195 Pflag++; 196 break; 197 case 'f': 198 todo |= FORKSTAT; 199 break; 200 case 'h': 201 hflag = 1; 202 break; 203 case 'H': 204 hflag = 0; 205 break; 206 case 'i': 207 todo |= INTRSTAT; 208 break; 209 case 'M': 210 memf = optarg; 211 break; 212 case 'm': 213 todo |= MEMSTAT; 214 break; 215 case 'N': 216 nlistf = optarg; 217 break; 218 case 'n': 219 nflag = 1; 220 maxshowdevs = atoi(optarg); 221 if (maxshowdevs < 0) 222 errx(1, "number of devices %d is < 0", 223 maxshowdevs); 224 break; 225 case 'p': 226 if (devstat_buildmatch(optarg, &matches, &num_matches) != 0) 227 errx(1, "%s", devstat_errbuf); 228 break; 229 case 's': 230 todo |= SUMSTAT; 231 break; 232 case 't': 233 #ifdef notyet 234 todo |= TIMESTAT; 235 #else 236 errx(EX_USAGE, "sorry, -t is not (re)implemented yet"); 237 #endif 238 break; 239 case 'w': 240 interval = atoi(optarg); 241 break; 242 case 'z': 243 todo |= ZMEMSTAT; 244 break; 245 case '?': 246 default: 247 usage(); 248 } 249 } 250 argc -= optind; 251 argv += optind; 252 253 if (todo == 0) 254 todo = VMSTAT; 255 256 if (memf != NULL) { 257 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 258 if (kd == NULL) 259 errx(1, "kvm_openfiles: %s", errbuf); 260 } 261 262 if (kd != NULL && (c = kvm_nlist(kd, namelist)) != 0) { 263 if (c > 0) { 264 warnx("undefined symbols:"); 265 for (c = 0; 266 c < (int)(sizeof(namelist)/sizeof(namelist[0])); 267 c++) 268 if (namelist[c].n_type == 0) 269 (void)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 if (kd && Pflag) 277 errx(1, "Cannot use -P with crash dumps"); 278 279 if (todo & VMSTAT) { 280 struct winsize winsize; 281 282 /* 283 * Make sure that the userland devstat version matches the 284 * kernel devstat version. If not, exit and print a 285 * message informing the user of his mistake. 286 */ 287 if (devstat_checkversion(NULL) < 0) 288 errx(1, "%s", devstat_errbuf); 289 290 291 argv = getdrivedata(argv); 292 winsize.ws_row = 0; 293 (void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize); 294 if (winsize.ws_row > 0) 295 winlines = winsize.ws_row; 296 297 } 298 299 #define BACKWARD_COMPATIBILITY 300 #ifdef BACKWARD_COMPATIBILITY 301 if (*argv) { 302 interval = atoi(*argv); 303 if (*++argv) 304 reps = atoi(*argv); 305 } 306 #endif 307 308 if (interval) { 309 if (!reps) 310 reps = -1; 311 } else if (reps) 312 interval = 1; 313 314 if (todo & FORKSTAT) 315 doforkst(); 316 if (todo & MEMSTAT) 317 domemstat_malloc(); 318 if (todo & ZMEMSTAT) 319 domemstat_zone(); 320 if (todo & SUMSTAT) 321 dosum(); 322 #ifdef notyet 323 if (todo & TIMESTAT) 324 dotimes(); 325 #endif 326 if (todo & INTRSTAT) 327 dointr(); 328 if (todo & VMSTAT) 329 dovmstat(interval, reps); 330 exit(0); 331 } 332 333 static int 334 mysysctl(const char *name, void *oldp, size_t *oldlenp, 335 void *newp, size_t newlen) 336 { 337 int error; 338 339 error = sysctlbyname(name, oldp, oldlenp, newp, newlen); 340 if (error != 0 && errno != ENOMEM) 341 err(1, "sysctl(%s)", name); 342 return (error); 343 } 344 345 static char ** 346 getdrivedata(char **argv) 347 { 348 if ((num_devices = devstat_getnumdevs(NULL)) < 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 (devstat_getdevs(NULL, &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 (devstat_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 (devstat_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 static long 411 getuptime(void) 412 { 413 struct timespec sp; 414 time_t uptime; 415 416 (void)clock_gettime(CLOCK_MONOTONIC, &sp); 417 uptime = sp.tv_sec; 418 if (uptime <= 0 || uptime > 60*60*24*365*10) 419 errx(1, "time makes no sense; namelist must be wrong"); 420 421 return(uptime); 422 } 423 424 static void 425 fill_vmmeter(struct vmmeter *vmmp) 426 { 427 if (kd != NULL) { 428 kread(X_SUM, vmmp, sizeof(*vmmp)); 429 } else { 430 size_t size = sizeof(unsigned int); 431 #define GET_VM_STATS(cat, name) \ 432 mysysctl("vm.stats." #cat "." #name, &vmmp->name, &size, NULL, 0) 433 /* sys */ 434 GET_VM_STATS(sys, v_swtch); 435 GET_VM_STATS(sys, v_trap); 436 GET_VM_STATS(sys, v_syscall); 437 GET_VM_STATS(sys, v_intr); 438 GET_VM_STATS(sys, v_soft); 439 440 /* vm */ 441 GET_VM_STATS(vm, v_vm_faults); 442 GET_VM_STATS(vm, v_cow_faults); 443 GET_VM_STATS(vm, v_cow_optim); 444 GET_VM_STATS(vm, v_zfod); 445 GET_VM_STATS(vm, v_ozfod); 446 GET_VM_STATS(vm, v_swapin); 447 GET_VM_STATS(vm, v_swapout); 448 GET_VM_STATS(vm, v_swappgsin); 449 GET_VM_STATS(vm, v_swappgsout); 450 GET_VM_STATS(vm, v_vnodein); 451 GET_VM_STATS(vm, v_vnodeout); 452 GET_VM_STATS(vm, v_vnodepgsin); 453 GET_VM_STATS(vm, v_vnodepgsout); 454 GET_VM_STATS(vm, v_intrans); 455 GET_VM_STATS(vm, v_reactivated); 456 GET_VM_STATS(vm, v_pdwakeups); 457 GET_VM_STATS(vm, v_pdpages); 458 GET_VM_STATS(vm, v_tcached); 459 GET_VM_STATS(vm, v_dfree); 460 GET_VM_STATS(vm, v_pfree); 461 GET_VM_STATS(vm, v_tfree); 462 GET_VM_STATS(vm, v_page_size); 463 GET_VM_STATS(vm, v_page_count); 464 GET_VM_STATS(vm, v_free_reserved); 465 GET_VM_STATS(vm, v_free_target); 466 GET_VM_STATS(vm, v_free_min); 467 GET_VM_STATS(vm, v_free_count); 468 GET_VM_STATS(vm, v_wire_count); 469 GET_VM_STATS(vm, v_active_count); 470 GET_VM_STATS(vm, v_inactive_target); 471 GET_VM_STATS(vm, v_inactive_count); 472 GET_VM_STATS(vm, v_cache_count); 473 GET_VM_STATS(vm, v_cache_min); 474 GET_VM_STATS(vm, v_cache_max); 475 GET_VM_STATS(vm, v_pageout_free_min); 476 GET_VM_STATS(vm, v_interrupt_free_min); 477 /*GET_VM_STATS(vm, v_free_severe);*/ 478 GET_VM_STATS(vm, v_forks); 479 GET_VM_STATS(vm, v_vforks); 480 GET_VM_STATS(vm, v_rforks); 481 GET_VM_STATS(vm, v_kthreads); 482 GET_VM_STATS(vm, v_forkpages); 483 GET_VM_STATS(vm, v_vforkpages); 484 GET_VM_STATS(vm, v_rforkpages); 485 GET_VM_STATS(vm, v_kthreadpages); 486 #undef GET_VM_STATS 487 } 488 } 489 490 static void 491 fill_vmtotal(struct vmtotal *vmtp) 492 { 493 if (kd != NULL) { 494 /* XXX fill vmtp */ 495 errx(1, "not implemented"); 496 } else { 497 size_t size = sizeof(*vmtp); 498 mysysctl("vm.vmtotal", vmtp, &size, NULL, 0); 499 if (size != sizeof(*vmtp)) 500 errx(1, "vm.total size mismatch"); 501 } 502 } 503 504 /* Determine how many cpu columns, and what index they are in kern.cp_times */ 505 static int 506 getcpuinfo(u_long *maskp, int *maxidp) 507 { 508 int maxcpu; 509 int maxid; 510 int ncpus; 511 int i, j; 512 int empty; 513 size_t size; 514 long *times; 515 u_long mask; 516 517 if (kd != NULL) 518 errx(1, "not implemented"); 519 mask = 0; 520 ncpus = 0; 521 size = sizeof(maxcpu); 522 mysysctl("kern.smp.maxcpus", &maxcpu, &size, NULL, 0); 523 if (size != sizeof(maxcpu)) 524 errx(1, "sysctl kern.smp.maxcpus"); 525 size = sizeof(long) * maxcpu * CPUSTATES; 526 times = malloc(size); 527 if (times == NULL) 528 err(1, "malloc %zd bytes", size); 529 mysysctl("kern.cp_times", times, &size, NULL, 0); 530 maxid = (size / CPUSTATES / sizeof(long)) - 1; 531 for (i = 0; i <= maxid; i++) { 532 empty = 1; 533 for (j = 0; empty && j < CPUSTATES; j++) { 534 if (times[i * CPUSTATES + j] != 0) 535 empty = 0; 536 } 537 if (!empty) { 538 mask |= (1ul << i); 539 ncpus++; 540 } 541 } 542 if (maskp) 543 *maskp = mask; 544 if (maxidp) 545 *maxidp = maxid; 546 return (ncpus); 547 } 548 549 550 static void 551 prthuman(u_int64_t val, int size) 552 { 553 char buf[10]; 554 int flags; 555 556 if (size < 5 || size > 9) 557 errx(1, "doofus"); 558 flags = HN_B | HN_NOSPACE | HN_DECIMAL; 559 humanize_number(buf, size, val, "", HN_AUTOSCALE, flags); 560 printf("%*s", size, buf); 561 } 562 563 static int hz, hdrcnt; 564 565 static long *cur_cp_times; 566 static long *last_cp_times; 567 static size_t size_cp_times; 568 569 static void 570 dovmstat(unsigned int interval, int reps) 571 { 572 struct vmtotal total; 573 time_t uptime, halfuptime; 574 struct devinfo *tmp_dinfo; 575 size_t size; 576 int ncpus, maxid; 577 u_long cpumask; 578 579 uptime = getuptime(); 580 halfuptime = uptime / 2; 581 (void)signal(SIGCONT, needhdr); 582 583 if (kd != NULL) { 584 if (namelist[X_STATHZ].n_type != 0 && 585 namelist[X_STATHZ].n_value != 0) 586 kread(X_STATHZ, &hz, sizeof(hz)); 587 if (!hz) 588 kread(X_HZ, &hz, sizeof(hz)); 589 } else { 590 struct clockinfo clockrate; 591 592 size = sizeof(clockrate); 593 mysysctl("kern.clockrate", &clockrate, &size, NULL, 0); 594 if (size != sizeof(clockrate)) 595 errx(1, "clockrate size mismatch"); 596 hz = clockrate.hz; 597 } 598 599 if (Pflag) { 600 ncpus = getcpuinfo(&cpumask, &maxid); 601 size_cp_times = sizeof(long) * (maxid + 1) * CPUSTATES; 602 cur_cp_times = malloc(size_cp_times); 603 last_cp_times = malloc(size_cp_times); 604 bzero(cur_cp_times, size_cp_times); 605 bzero(last_cp_times, size_cp_times); 606 } 607 for (hdrcnt = 1;;) { 608 if (!--hdrcnt) 609 printhdr(ncpus, cpumask); 610 if (kd != NULL) { 611 if (kvm_getcptime(kd, cur.cp_time) < 0) 612 errx(1, "kvm_getcptime: %s", kvm_geterr(kd)); 613 } else { 614 size = sizeof(cur.cp_time); 615 mysysctl("kern.cp_time", &cur.cp_time, &size, NULL, 0); 616 if (size != sizeof(cur.cp_time)) 617 errx(1, "cp_time size mismatch"); 618 } 619 if (Pflag) { 620 size = size_cp_times; 621 mysysctl("kern.cp_times", cur_cp_times, &size, NULL, 0); 622 if (size != size_cp_times) 623 errx(1, "cp_times mismatch"); 624 } 625 626 tmp_dinfo = last.dinfo; 627 last.dinfo = cur.dinfo; 628 cur.dinfo = tmp_dinfo; 629 last.snap_time = cur.snap_time; 630 631 /* 632 * Here what we want to do is refresh our device stats. 633 * getdevs() returns 1 when the device list has changed. 634 * If the device list has changed, we want to go through 635 * the selection process again, in case a device that we 636 * were previously displaying has gone away. 637 */ 638 switch (devstat_getdevs(NULL, &cur)) { 639 case -1: 640 errx(1, "%s", devstat_errbuf); 641 break; 642 case 1: { 643 int retval; 644 645 num_devices = cur.dinfo->numdevs; 646 generation = cur.dinfo->generation; 647 648 retval = devstat_selectdevs(&dev_select, &num_selected, 649 &num_selections, &select_generation, 650 generation, cur.dinfo->devices, 651 num_devices, matches, num_matches, 652 specified_devices, 653 num_devices_specified, select_mode, 654 maxshowdevs, 0); 655 switch (retval) { 656 case -1: 657 errx(1, "%s", devstat_errbuf); 658 break; 659 case 1: 660 printhdr(ncpus, cpumask); 661 break; 662 default: 663 break; 664 } 665 } 666 default: 667 break; 668 } 669 670 fill_vmmeter(&sum); 671 fill_vmtotal(&total); 672 (void)printf("%2d %1d %1d", 673 total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); 674 #define vmstat_pgtok(a) ((a) * (sum.v_page_size >> 10)) 675 #define rate(x) (((x) + halfuptime) / uptime) /* round */ 676 if (hflag) { 677 printf(" "); 678 prthuman(total.t_avm * (u_int64_t)sum.v_page_size, 7); 679 printf(" "); 680 prthuman(total.t_free * (u_int64_t)sum.v_page_size, 6); 681 printf(" "); 682 } else { 683 printf(" %7d ", vmstat_pgtok(total.t_avm)); 684 printf(" %6d ", vmstat_pgtok(total.t_free)); 685 } 686 (void)printf("%5lu ", 687 (unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults)); 688 (void)printf("%3lu ", 689 (unsigned long)rate(sum.v_reactivated - osum.v_reactivated)); 690 (void)printf("%3lu ", 691 (unsigned long)rate(sum.v_swapin + sum.v_vnodein - 692 (osum.v_swapin + osum.v_vnodein))); 693 (void)printf("%3lu ", 694 (unsigned long)rate(sum.v_swapout + sum.v_vnodeout - 695 (osum.v_swapout + osum.v_vnodeout))); 696 (void)printf("%5lu ", 697 (unsigned long)rate(sum.v_tfree - osum.v_tfree)); 698 (void)printf("%3lu ", 699 (unsigned long)rate(sum.v_pdpages - osum.v_pdpages)); 700 devstats(); 701 (void)printf("%4lu %4lu %4lu", 702 (unsigned long)rate(sum.v_intr - osum.v_intr), 703 (unsigned long)rate(sum.v_syscall - osum.v_syscall), 704 (unsigned long)rate(sum.v_swtch - osum.v_swtch)); 705 if (Pflag) 706 pcpustats(ncpus, cpumask, maxid); 707 else 708 cpustats(); 709 (void)printf("\n"); 710 (void)fflush(stdout); 711 if (reps >= 0 && --reps <= 0) 712 break; 713 osum = sum; 714 uptime = interval; 715 /* 716 * We round upward to avoid losing low-frequency events 717 * (i.e., >= 1 per interval but < 1 per second). 718 */ 719 if (interval != 1) 720 halfuptime = (uptime + 1) / 2; 721 else 722 halfuptime = 0; 723 (void)sleep(interval); 724 } 725 } 726 727 static void 728 printhdr(int ncpus, u_long cpumask) 729 { 730 int i, num_shown; 731 732 num_shown = (num_selected < maxshowdevs) ? num_selected : maxshowdevs; 733 (void)printf(" procs memory page%*s", 19, ""); 734 if (num_shown > 1) 735 (void)printf(" disks %*s", num_shown * 4 - 7, ""); 736 else if (num_shown == 1) 737 (void)printf("disk"); 738 (void)printf(" faults "); 739 if (Pflag) { 740 for (i = 0; i < ncpus; i++) { 741 if (cpumask & (1ul << i)) 742 printf("cpu%-2d ", i); 743 } 744 printf("\n"); 745 } else 746 printf("cpu\n"); 747 (void)printf(" r b w avm fre flt re pi po fr sr "); 748 for (i = 0; i < num_devices; i++) 749 if ((dev_select[i].selected) 750 && (dev_select[i].selected <= maxshowdevs)) 751 (void)printf("%c%c%d ", dev_select[i].device_name[0], 752 dev_select[i].device_name[1], 753 dev_select[i].unit_number); 754 (void)printf(" in sy cs"); 755 if (Pflag) { 756 for (i = 0; i < ncpus; i++) 757 printf(" us sy id"); 758 printf("\n"); 759 } else 760 printf(" us sy id\n"); 761 hdrcnt = winlines - 2; 762 } 763 764 /* 765 * Force a header to be prepended to the next output. 766 */ 767 static void 768 needhdr(int dummy __unused) 769 { 770 771 hdrcnt = 1; 772 } 773 774 #ifdef notyet 775 static void 776 dotimes(void) 777 { 778 unsigned int pgintime, rectime; 779 780 kread(X_REC, &rectime, sizeof(rectime)); 781 kread(X_PGIN, &pgintime, sizeof(pgintime)); 782 kread(X_SUM, &sum, sizeof(sum)); 783 (void)printf("%u reclaims, %u total time (usec)\n", 784 sum.v_pgrec, rectime); 785 (void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec); 786 (void)printf("\n"); 787 (void)printf("%u page ins, %u total time (msec)\n", 788 sum.v_pgin, pgintime / 10); 789 (void)printf("average: %8.1f msec / page in\n", 790 pgintime / (sum.v_pgin * 10.0)); 791 } 792 #endif 793 794 static long 795 pct(long top, long bot) 796 { 797 long ans; 798 799 if (bot == 0) 800 return(0); 801 ans = (quad_t)top * 100 / bot; 802 return (ans); 803 } 804 805 #define PCT(top, bot) pct((long)(top), (long)(bot)) 806 807 static void 808 dosum(void) 809 { 810 struct nchstats lnchstats; 811 long nchtotal; 812 813 fill_vmmeter(&sum); 814 (void)printf("%9u cpu context switches\n", sum.v_swtch); 815 (void)printf("%9u device interrupts\n", sum.v_intr); 816 (void)printf("%9u software interrupts\n", sum.v_soft); 817 (void)printf("%9u traps\n", sum.v_trap); 818 (void)printf("%9u system calls\n", sum.v_syscall); 819 (void)printf("%9u kernel threads created\n", sum.v_kthreads); 820 (void)printf("%9u fork() calls\n", sum.v_forks); 821 (void)printf("%9u vfork() calls\n", sum.v_vforks); 822 (void)printf("%9u rfork() calls\n", sum.v_rforks); 823 (void)printf("%9u swap pager pageins\n", sum.v_swapin); 824 (void)printf("%9u swap pager pages paged in\n", sum.v_swappgsin); 825 (void)printf("%9u swap pager pageouts\n", sum.v_swapout); 826 (void)printf("%9u swap pager pages paged out\n", sum.v_swappgsout); 827 (void)printf("%9u vnode pager pageins\n", sum.v_vnodein); 828 (void)printf("%9u vnode pager pages paged in\n", sum.v_vnodepgsin); 829 (void)printf("%9u vnode pager pageouts\n", sum.v_vnodeout); 830 (void)printf("%9u vnode pager pages paged out\n", sum.v_vnodepgsout); 831 (void)printf("%9u page daemon wakeups\n", sum.v_pdwakeups); 832 (void)printf("%9u pages examined by the page daemon\n", sum.v_pdpages); 833 (void)printf("%9u pages reactivated\n", sum.v_reactivated); 834 (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults); 835 (void)printf("%9u copy-on-write optimized faults\n", sum.v_cow_optim); 836 (void)printf("%9u zero fill pages zeroed\n", sum.v_zfod); 837 (void)printf("%9u zero fill pages prezeroed\n", sum.v_ozfod); 838 (void)printf("%9u intransit blocking page faults\n", sum.v_intrans); 839 (void)printf("%9u total VM faults taken\n", sum.v_vm_faults); 840 (void)printf("%9u pages affected by kernel thread creation\n", sum.v_kthreadpages); 841 (void)printf("%9u pages affected by fork()\n", sum.v_forkpages); 842 (void)printf("%9u pages affected by vfork()\n", sum.v_vforkpages); 843 (void)printf("%9u pages affected by rfork()\n", sum.v_rforkpages); 844 (void)printf("%9u pages cached\n", sum.v_tcached); 845 (void)printf("%9u pages freed\n", sum.v_tfree); 846 (void)printf("%9u pages freed by daemon\n", sum.v_dfree); 847 (void)printf("%9u pages freed by exiting processes\n", sum.v_pfree); 848 (void)printf("%9u pages active\n", sum.v_active_count); 849 (void)printf("%9u pages inactive\n", sum.v_inactive_count); 850 (void)printf("%9u pages in VM cache\n", sum.v_cache_count); 851 (void)printf("%9u pages wired down\n", sum.v_wire_count); 852 (void)printf("%9u pages free\n", sum.v_free_count); 853 (void)printf("%9u bytes per page\n", sum.v_page_size); 854 if (kd != NULL) { 855 kread(X_NCHSTATS, &lnchstats, sizeof(lnchstats)); 856 } else { 857 size_t size = sizeof(lnchstats); 858 mysysctl("vfs.cache.nchstats", &lnchstats, &size, NULL, 0); 859 if (size != sizeof(lnchstats)) 860 errx(1, "vfs.cache.nchstats size mismatch"); 861 } 862 nchtotal = lnchstats.ncs_goodhits + lnchstats.ncs_neghits + 863 lnchstats.ncs_badhits + lnchstats.ncs_falsehits + 864 lnchstats.ncs_miss + lnchstats.ncs_long; 865 (void)printf("%9ld total name lookups\n", nchtotal); 866 (void)printf( 867 "%9s cache hits (%ld%% pos + %ld%% neg) system %ld%% per-directory\n", 868 "", PCT(lnchstats.ncs_goodhits, nchtotal), 869 PCT(lnchstats.ncs_neghits, nchtotal), 870 PCT(lnchstats.ncs_pass2, nchtotal)); 871 (void)printf("%9s deletions %ld%%, falsehits %ld%%, toolong %ld%%\n", "", 872 PCT(lnchstats.ncs_badhits, nchtotal), 873 PCT(lnchstats.ncs_falsehits, nchtotal), 874 PCT(lnchstats.ncs_long, nchtotal)); 875 } 876 877 static void 878 doforkst(void) 879 { 880 fill_vmmeter(&sum); 881 (void)printf("%u forks, %u pages, average %.2f\n", 882 sum.v_forks, sum.v_forkpages, 883 sum.v_forks == 0 ? 0.0 : 884 (double)sum.v_forkpages / sum.v_forks); 885 (void)printf("%u vforks, %u pages, average %.2f\n", 886 sum.v_vforks, sum.v_vforkpages, 887 sum.v_vforks == 0 ? 0.0 : 888 (double)sum.v_vforkpages / sum.v_vforks); 889 (void)printf("%u rforks, %u pages, average %.2f\n", 890 sum.v_rforks, sum.v_rforkpages, 891 sum.v_rforks == 0 ? 0.0 : 892 (double)sum.v_rforkpages / sum.v_rforks); 893 } 894 895 static void 896 devstats(void) 897 { 898 int dn, state; 899 long double transfers_per_second; 900 long double busy_seconds; 901 long tmp; 902 903 for (state = 0; state < CPUSTATES; ++state) { 904 tmp = cur.cp_time[state]; 905 cur.cp_time[state] -= last.cp_time[state]; 906 last.cp_time[state] = tmp; 907 } 908 909 busy_seconds = cur.snap_time - last.snap_time; 910 911 for (dn = 0; dn < num_devices; dn++) { 912 int di; 913 914 if ((dev_select[dn].selected == 0) 915 || (dev_select[dn].selected > maxshowdevs)) 916 continue; 917 918 di = dev_select[dn].position; 919 920 if (devstat_compute_statistics(&cur.dinfo->devices[di], 921 &last.dinfo->devices[di], busy_seconds, 922 DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 923 DSM_NONE) != 0) 924 errx(1, "%s", devstat_errbuf); 925 926 (void)printf("%3.0Lf ", transfers_per_second); 927 } 928 } 929 930 static void 931 percent(double pct, int *over) 932 { 933 char buf[10]; 934 int l; 935 936 l = snprintf(buf, sizeof(buf), "%.0f", pct); 937 if (l == 1 && *over) { 938 printf("%s", buf); 939 (*over)--; 940 } else 941 printf("%2s", buf); 942 if (l > 2) 943 (*over)++; 944 } 945 946 static void 947 cpustats(void) 948 { 949 int state, over; 950 double lpct, total; 951 952 total = 0; 953 for (state = 0; state < CPUSTATES; ++state) 954 total += cur.cp_time[state]; 955 if (total) 956 lpct = 100.0 / total; 957 else 958 lpct = 0.0; 959 over = 0; 960 printf(" "); 961 percent((cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * lpct, &over); 962 printf(" "); 963 percent((cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * lpct, &over); 964 printf(" "); 965 percent(cur.cp_time[CP_IDLE] * lpct, &over); 966 } 967 968 static void 969 pcpustats(int ncpus, u_long cpumask, int maxid) 970 { 971 int state, i; 972 double lpct, total; 973 long tmp; 974 int over; 975 976 /* devstats does this for cp_time */ 977 for (i = 0; i <= maxid; i++) { 978 if ((cpumask & (1ul << i)) == 0) 979 continue; 980 for (state = 0; state < CPUSTATES; ++state) { 981 tmp = cur_cp_times[i * CPUSTATES + state]; 982 cur_cp_times[i * CPUSTATES + state] -= last_cp_times[i * CPUSTATES + state]; 983 last_cp_times[i * CPUSTATES + state] = tmp; 984 } 985 } 986 987 over = 0; 988 for (i = 0; i <= maxid; i++) { 989 if ((cpumask & (1ul << i)) == 0) 990 continue; 991 total = 0; 992 for (state = 0; state < CPUSTATES; ++state) 993 total += cur_cp_times[i * CPUSTATES + state]; 994 if (total) 995 lpct = 100.0 / total; 996 else 997 lpct = 0.0; 998 printf(" "); 999 percent((cur_cp_times[i * CPUSTATES + CP_USER] + 1000 cur_cp_times[i * CPUSTATES + CP_NICE]) * lpct, &over); 1001 printf(" "); 1002 percent((cur_cp_times[i * CPUSTATES + CP_SYS] + 1003 cur_cp_times[i * CPUSTATES + CP_INTR]) * lpct, &over); 1004 printf(" "); 1005 percent(cur_cp_times[i * CPUSTATES + CP_IDLE] * lpct, &over); 1006 } 1007 } 1008 1009 static void 1010 dointr(void) 1011 { 1012 unsigned long *intrcnt, uptime; 1013 uint64_t inttotal; 1014 size_t clen, inamlen, intrcntlen, istrnamlen; 1015 unsigned int i, nintr; 1016 char *intrname, *tintrname; 1017 1018 uptime = getuptime(); 1019 if (kd != NULL) { 1020 intrcntlen = namelist[X_EINTRCNT].n_value - 1021 namelist[X_INTRCNT].n_value; 1022 inamlen = namelist[X_EINTRNAMES].n_value - 1023 namelist[X_INTRNAMES].n_value; 1024 if ((intrcnt = malloc(intrcntlen)) == NULL || 1025 (intrname = malloc(inamlen)) == NULL) 1026 err(1, "malloc()"); 1027 kread(X_INTRCNT, intrcnt, intrcntlen); 1028 kread(X_INTRNAMES, intrname, inamlen); 1029 } else { 1030 for (intrcnt = NULL, intrcntlen = 1024; ; intrcntlen *= 2) { 1031 if ((intrcnt = reallocf(intrcnt, intrcntlen)) == NULL) 1032 err(1, "reallocf()"); 1033 if (mysysctl("hw.intrcnt", 1034 intrcnt, &intrcntlen, NULL, 0) == 0) 1035 break; 1036 } 1037 for (intrname = NULL, inamlen = 1024; ; inamlen *= 2) { 1038 if ((intrname = reallocf(intrname, inamlen)) == NULL) 1039 err(1, "reallocf()"); 1040 if (mysysctl("hw.intrnames", 1041 intrname, &inamlen, NULL, 0) == 0) 1042 break; 1043 } 1044 } 1045 nintr = intrcntlen / sizeof(unsigned long); 1046 tintrname = intrname; 1047 istrnamlen = strlen("interrupt"); 1048 for (i = 0; i < nintr; i++) { 1049 clen = strlen(tintrname); 1050 if (clen > istrnamlen) 1051 istrnamlen = clen; 1052 tintrname += clen + 1; 1053 } 1054 (void)printf("%-*s %20s %10s\n", istrnamlen, "interrupt", "total", 1055 "rate"); 1056 inttotal = 0; 1057 for (i = 0; i < nintr; i++) { 1058 if (intrname[0] != '\0' && (*intrcnt != 0 || aflag)) 1059 (void)printf("%-*s %20lu %10lu\n", istrnamlen, intrname, 1060 *intrcnt, *intrcnt / uptime); 1061 intrname += strlen(intrname) + 1; 1062 inttotal += *intrcnt++; 1063 } 1064 (void)printf("%-*s %20llu %10llu\n", istrnamlen, "Total", 1065 (long long)inttotal, (long long)(inttotal / uptime)); 1066 } 1067 1068 static void 1069 domemstat_malloc(void) 1070 { 1071 struct memory_type_list *mtlp; 1072 struct memory_type *mtp; 1073 int error, first, i; 1074 1075 mtlp = memstat_mtl_alloc(); 1076 if (mtlp == NULL) { 1077 warn("memstat_mtl_alloc"); 1078 return; 1079 } 1080 if (kd == NULL) { 1081 if (memstat_sysctl_malloc(mtlp, 0) < 0) { 1082 warnx("memstat_sysctl_malloc: %s", 1083 memstat_strerror(memstat_mtl_geterror(mtlp))); 1084 return; 1085 } 1086 } else { 1087 if (memstat_kvm_malloc(mtlp, kd) < 0) { 1088 error = memstat_mtl_geterror(mtlp); 1089 if (error == MEMSTAT_ERROR_KVM) 1090 warnx("memstat_kvm_malloc: %s", 1091 kvm_geterr(kd)); 1092 else 1093 warnx("memstat_kvm_malloc: %s", 1094 memstat_strerror(error)); 1095 } 1096 } 1097 printf("%13s %5s %6s %7s %8s Size(s)\n", "Type", "InUse", "MemUse", 1098 "HighUse", "Requests"); 1099 for (mtp = memstat_mtl_first(mtlp); mtp != NULL; 1100 mtp = memstat_mtl_next(mtp)) { 1101 if (memstat_get_numallocs(mtp) == 0 && 1102 memstat_get_count(mtp) == 0) 1103 continue; 1104 printf("%13s %5lld %5lldK %7s %8lld ", 1105 memstat_get_name(mtp), memstat_get_count(mtp), 1106 ((int64_t)memstat_get_bytes(mtp) + 1023) / 1024, "-", 1107 memstat_get_numallocs(mtp)); 1108 first = 1; 1109 for (i = 0; i < 32; i++) { 1110 if (memstat_get_sizemask(mtp) & (1 << i)) { 1111 if (!first) 1112 printf(","); 1113 printf("%d", 1 << (i + 4)); 1114 first = 0; 1115 } 1116 } 1117 printf("\n"); 1118 } 1119 memstat_mtl_free(mtlp); 1120 } 1121 1122 static void 1123 domemstat_zone(void) 1124 { 1125 struct memory_type_list *mtlp; 1126 struct memory_type *mtp; 1127 char name[MEMTYPE_MAXNAME + 1]; 1128 int error; 1129 1130 mtlp = memstat_mtl_alloc(); 1131 if (mtlp == NULL) { 1132 warn("memstat_mtl_alloc"); 1133 return; 1134 } 1135 if (kd == NULL) { 1136 if (memstat_sysctl_uma(mtlp, 0) < 0) { 1137 warnx("memstat_sysctl_uma: %s", 1138 memstat_strerror(memstat_mtl_geterror(mtlp))); 1139 return; 1140 } 1141 } else { 1142 if (memstat_kvm_uma(mtlp, kd) < 0) { 1143 error = memstat_mtl_geterror(mtlp); 1144 if (error == MEMSTAT_ERROR_KVM) 1145 warnx("memstat_kvm_uma: %s", 1146 kvm_geterr(kd)); 1147 else 1148 warnx("memstat_kvm_uma: %s", 1149 memstat_strerror(error)); 1150 } 1151 } 1152 printf("%-20s %8s %8s %8s %8s %8s %8s\n\n", "ITEM", "SIZE", 1153 "LIMIT", "USED", "FREE", "REQUESTS", "FAILURES"); 1154 for (mtp = memstat_mtl_first(mtlp); mtp != NULL; 1155 mtp = memstat_mtl_next(mtp)) { 1156 strlcpy(name, memstat_get_name(mtp), MEMTYPE_MAXNAME); 1157 strcat(name, ":"); 1158 printf("%-20s %8llu, %8llu, %8llu, %8llu, %8llu, %8llu\n", name, 1159 memstat_get_size(mtp), memstat_get_countlimit(mtp), 1160 memstat_get_count(mtp), memstat_get_free(mtp), 1161 memstat_get_numallocs(mtp), memstat_get_failures(mtp)); 1162 } 1163 memstat_mtl_free(mtlp); 1164 printf("\n"); 1165 } 1166 1167 /* 1168 * kread reads something from the kernel, given its nlist index. 1169 */ 1170 static void 1171 kreado(int nlx, void *addr, size_t size, size_t offset) 1172 { 1173 const char *sym; 1174 1175 if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) { 1176 sym = namelist[nlx].n_name; 1177 if (*sym == '_') 1178 ++sym; 1179 errx(1, "symbol %s not defined", sym); 1180 } 1181 if ((size_t)kvm_read(kd, namelist[nlx].n_value + offset, addr, 1182 size) != size) { 1183 sym = namelist[nlx].n_name; 1184 if (*sym == '_') 1185 ++sym; 1186 errx(1, "%s: %s", sym, kvm_geterr(kd)); 1187 } 1188 } 1189 1190 static void 1191 kread(int nlx, void *addr, size_t size) 1192 { 1193 kreado(nlx, addr, size, 0); 1194 } 1195 1196 static char * 1197 kgetstr(const char *strp) 1198 { 1199 int n = 0, size = 1; 1200 char *ret = NULL; 1201 1202 do { 1203 if (size == n + 1) { 1204 ret = realloc(ret, size); 1205 if (ret == NULL) 1206 err(1, "%s: realloc", __func__); 1207 size *= 2; 1208 } 1209 if (kvm_read(kd, (u_long)strp + n, &ret[n], 1) != 1) 1210 errx(1, "%s: %s", __func__, kvm_geterr(kd)); 1211 } while (ret[n++] != '\0'); 1212 return (ret); 1213 } 1214 1215 static void 1216 usage(void) 1217 { 1218 (void)fprintf(stderr, "%s%s", 1219 "usage: vmstat [-afHhimPsz] [-c count] [-M core [-N system]] [-w wait]\n", 1220 " [-n devs] [-p type,if,pass] [disks]\n"); 1221 exit(1); 1222 } 1223