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