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