1 /* 2 * Copyright (c) 1997, 1998, 2000, 2001 Kenneth D. Merry 3 * 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. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 /* 31 * Parts of this program are derived from the original FreeBSD iostat 32 * program: 33 */ 34 /*- 35 * Copyright (c) 1986, 1991, 1993 36 * The Regents of the University of California. All rights reserved. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed by the University of 49 * California, Berkeley and its contributors. 50 * 4. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 */ 66 /* 67 * Ideas for the new iostat statistics output modes taken from the NetBSD 68 * version of iostat: 69 */ 70 /* 71 * Copyright (c) 1996 John M. Vinopal 72 * All rights reserved. 73 * 74 * Redistribution and use in source and binary forms, with or without 75 * modification, are permitted provided that the following conditions 76 * are met: 77 * 1. Redistributions of source code must retain the above copyright 78 * notice, this list of conditions and the following disclaimer. 79 * 2. Redistributions in binary form must reproduce the above copyright 80 * notice, this list of conditions and the following disclaimer in the 81 * documentation and/or other materials provided with the distribution. 82 * 3. All advertising materials mentioning features or use of this software 83 * must display the following acknowledgement: 84 * This product includes software developed for the NetBSD Project 85 * by John M. Vinopal. 86 * 4. The name of the author may not be used to endorse or promote products 87 * derived from this software without specific prior written permission. 88 * 89 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 90 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 91 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 92 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 93 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 94 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 95 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 96 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 97 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 98 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 99 * SUCH DAMAGE. 100 */ 101 102 103 #include <sys/param.h> 104 #include <sys/errno.h> 105 #include <sys/resource.h> 106 #include <sys/sysctl.h> 107 108 #include <err.h> 109 #include <ctype.h> 110 #include <fcntl.h> 111 #include <kvm.h> 112 #include <nlist.h> 113 #include <stdio.h> 114 #include <stdlib.h> 115 #include <string.h> 116 #include <termios.h> 117 #include <unistd.h> 118 #include <limits.h> 119 #include <devstat.h> 120 #include <math.h> 121 122 struct nlist namelist[] = { 123 #define X_TK_NIN 0 124 { "_tk_nin" }, 125 #define X_TK_NOUT 1 126 { "_tk_nout" }, 127 #define X_CP_TIME 2 128 { "_cp_time" }, 129 #define X_BOOTTIME 3 130 { "_boottime" }, 131 #define X_END 3 132 { NULL }, 133 }; 134 135 #define IOSTAT_DEFAULT_ROWS 20 /* Traditional default `wrows' */ 136 137 struct statinfo cur, last; 138 int num_devices; 139 struct device_selection *dev_select; 140 int maxshowdevs; 141 volatile sig_atomic_t headercount; 142 volatile sig_atomic_t wresized; /* Tty resized, when non-zero. */ 143 unsigned short wrows; /* Current number of tty rows. */ 144 int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0; 145 int xflag = 0, zflag = 0; 146 147 /* local function declarations */ 148 static void usage(void); 149 static void needhdr(int signo); 150 static void needresize(int signo); 151 static void doresize(void); 152 static void phdr(void); 153 static void devstats(int perf_select, long double etime, int havelast); 154 static void cpustats(void); 155 static int readvar(kvm_t *kd, const char *name, int nlid, void *ptr, 156 size_t len); 157 158 static void 159 usage(void) 160 { 161 /* 162 * We also support the following 'traditional' syntax: 163 * iostat [drives] [wait [count]] 164 * This isn't mentioned in the man page, or the usage statement, 165 * but it is supported. 166 */ 167 fprintf(stderr, "usage: iostat [-CdhIKoTxz?] [-c count] [-M core]" 168 " [-n devs] [-N system]\n" 169 "\t [-t type,if,pass] [-w wait] [drives]\n"); 170 } 171 172 int 173 main(int argc, char **argv) 174 { 175 int c, i; 176 int tflag = 0, hflag = 0, cflag = 0, wflag = 0, nflag = 0; 177 int count = 0, waittime = 0; 178 char *memf = NULL, *nlistf = NULL; 179 struct devstat_match *matches; 180 int num_matches = 0; 181 char errbuf[_POSIX2_LINE_MAX]; 182 kvm_t *kd = NULL; 183 long generation; 184 int num_devices_specified; 185 int num_selected, num_selections; 186 long select_generation; 187 char **specified_devices; 188 devstat_select_mode select_mode; 189 int havelast = 0; 190 191 matches = NULL; 192 maxshowdevs = 3; 193 194 while ((c = getopt(argc, argv, "c:CdhIKM:n:N:ot:Tw:xz?")) != -1) { 195 switch(c) { 196 case 'c': 197 cflag++; 198 count = atoi(optarg); 199 if (count < 1) 200 errx(1, "count %d is < 1", count); 201 break; 202 case 'C': 203 Cflag++; 204 break; 205 case 'd': 206 dflag++; 207 break; 208 case 'h': 209 hflag++; 210 break; 211 case 'I': 212 Iflag++; 213 break; 214 case 'K': 215 Kflag++; 216 break; 217 case 'M': 218 memf = optarg; 219 break; 220 case 'n': 221 nflag++; 222 maxshowdevs = atoi(optarg); 223 if (maxshowdevs < 0) 224 errx(1, "number of devices %d is < 0", 225 maxshowdevs); 226 break; 227 case 'N': 228 nlistf = optarg; 229 break; 230 case 'o': 231 oflag++; 232 break; 233 case 't': 234 tflag++; 235 if (devstat_buildmatch(optarg, &matches, 236 &num_matches) != 0) 237 errx(1, "%s", devstat_errbuf); 238 break; 239 case 'T': 240 Tflag++; 241 break; 242 case 'w': 243 wflag++; 244 waittime = atoi(optarg); 245 if (waittime < 1) 246 errx(1, "wait time is < 1"); 247 break; 248 case 'x': 249 xflag++; 250 break; 251 case 'z': 252 zflag++; 253 break; 254 default: 255 usage(); 256 exit(1); 257 break; 258 } 259 } 260 261 argc -= optind; 262 argv += optind; 263 264 if (nlistf != NULL || memf != NULL) { 265 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 266 267 if (kd == NULL) 268 errx(1, "kvm_openfiles: %s", errbuf); 269 270 if (kvm_nlist(kd, namelist) == -1) 271 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 272 } 273 274 /* 275 * Make sure that the userland devstat version matches the kernel 276 * devstat version. If not, exit and print a message informing 277 * the user of his mistake. 278 */ 279 if (devstat_checkversion(kd) < 0) 280 errx(1, "%s", devstat_errbuf); 281 282 /* 283 * Make sure Tflag and/or Cflag are set if dflag == 0. If dflag is 284 * greater than 0, they may be 0 or non-zero. 285 */ 286 if (dflag == 0 && xflag == 0) { 287 Cflag = 1; 288 Tflag = 1; 289 } 290 291 /* find out how many devices we have */ 292 if ((num_devices = devstat_getnumdevs(kd)) < 0) 293 err(1, "can't get number of devices"); 294 295 /* 296 * Figure out how many devices we should display. 297 */ 298 if (nflag == 0) { 299 if (xflag > 0) 300 maxshowdevs = num_devices; 301 else if (oflag > 0) { 302 if ((dflag > 0) && (Cflag == 0) && (Tflag == 0)) 303 maxshowdevs = 5; 304 else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0)) 305 maxshowdevs = 5; 306 else 307 maxshowdevs = 4; 308 } else { 309 if ((dflag > 0) && (Cflag == 0)) 310 maxshowdevs = 4; 311 else 312 maxshowdevs = 3; 313 } 314 } 315 316 cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 317 if (cur.dinfo == NULL) 318 err(1, "malloc failed"); 319 320 last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 321 if (last.dinfo == NULL) 322 err(1, "malloc failed"); 323 324 bzero(cur.dinfo, sizeof(struct devinfo)); 325 bzero(last.dinfo, sizeof(struct devinfo)); 326 327 /* 328 * Grab all the devices. We don't look to see if the list has 329 * changed here, since it almost certainly has. We only look for 330 * errors. 331 */ 332 if (devstat_getdevs(kd, &cur) == -1) 333 errx(1, "%s", devstat_errbuf); 334 335 num_devices = cur.dinfo->numdevs; 336 generation = cur.dinfo->generation; 337 338 /* 339 * If the user specified any devices on the command line, see if 340 * they are in the list of devices we have now. 341 */ 342 specified_devices = (char **)malloc(sizeof(char *)); 343 if (specified_devices == NULL) 344 err(1, "malloc failed"); 345 346 for (num_devices_specified = 0; *argv; ++argv) { 347 if (isdigit(**argv)) 348 break; 349 num_devices_specified++; 350 specified_devices = (char **)realloc(specified_devices, 351 sizeof(char *) * 352 num_devices_specified); 353 if (specified_devices == NULL) 354 err(1, "realloc failed"); 355 356 specified_devices[num_devices_specified - 1] = *argv; 357 358 } 359 if (nflag == 0 && maxshowdevs < num_devices_specified) 360 maxshowdevs = num_devices_specified; 361 362 dev_select = NULL; 363 364 if ((num_devices_specified == 0) && (num_matches == 0)) 365 select_mode = DS_SELECT_ADD; 366 else 367 select_mode = DS_SELECT_ONLY; 368 369 /* 370 * At this point, selectdevs will almost surely indicate that the 371 * device list has changed, so we don't look for return values of 0 372 * or 1. If we get back -1, though, there is an error. 373 */ 374 if (devstat_selectdevs(&dev_select, &num_selected, 375 &num_selections, &select_generation, generation, 376 cur.dinfo->devices, num_devices, matches, 377 num_matches, specified_devices, 378 num_devices_specified, select_mode, maxshowdevs, 379 hflag) == -1) 380 errx(1, "%s", devstat_errbuf); 381 382 /* 383 * Look for the traditional wait time and count arguments. 384 */ 385 if (*argv) { 386 waittime = atoi(*argv); 387 388 /* Let the user know he goofed, but keep going anyway */ 389 if (wflag != 0) 390 warnx("discarding previous wait interval, using" 391 " %d instead", waittime); 392 wflag++; 393 394 if (*++argv) { 395 count = atoi(*argv); 396 if (cflag != 0) 397 warnx("discarding previous count, using %d" 398 " instead", count); 399 cflag++; 400 } else 401 count = -1; 402 } 403 404 /* 405 * If the user specified a count, but not an interval, we default 406 * to an interval of 1 second. 407 */ 408 if ((wflag == 0) && (cflag > 0)) 409 waittime = 1; 410 411 /* 412 * If the user specified a wait time, but not a count, we want to 413 * go on ad infinitum. This can be redundant if the user uses the 414 * traditional method of specifying the wait, since in that case we 415 * already set count = -1 above. Oh well. 416 */ 417 if ((wflag > 0) && (cflag == 0)) 418 count = -1; 419 420 bzero(&cur.cp_time, sizeof(cur.cp_time)); 421 cur.tk_nout = 0; 422 cur.tk_nin = 0; 423 424 /* 425 * Set the snap time to the system boot time (ie: zero), so the 426 * stats are calculated since system boot. 427 */ 428 cur.snap_time = 0; 429 430 /* 431 * If the user stops the program (control-Z) and then resumes it, 432 * print out the header again. 433 */ 434 (void)signal(SIGCONT, needhdr); 435 436 /* 437 * If our standard output is a tty, then install a SIGWINCH handler 438 * and set wresized so that our first iteration through the main 439 * iostat loop will peek at the terminal's current rows to find out 440 * how many lines can fit in a screenful of output. 441 */ 442 if (isatty(fileno(stdout)) != 0) { 443 wresized = 1; 444 (void)signal(SIGWINCH, needresize); 445 } else { 446 wresized = 0; 447 wrows = IOSTAT_DEFAULT_ROWS; 448 } 449 450 for (headercount = 1;;) { 451 struct devinfo *tmp_dinfo; 452 long tmp; 453 long double etime; 454 455 if (Tflag > 0) { 456 if ((readvar(kd, "kern.tty_nin", X_TK_NIN, &cur.tk_nin, 457 sizeof(cur.tk_nin)) != 0) 458 || (readvar(kd, "kern.tty_nout", X_TK_NOUT, 459 &cur.tk_nout, sizeof(cur.tk_nout))!= 0)) { 460 Tflag = 0; 461 warnx("disabling TTY statistics"); 462 } 463 } 464 465 if (Cflag > 0) { 466 if (readvar(kd, "kern.cp_time", X_CP_TIME, 467 &cur.cp_time, sizeof(cur.cp_time)) != 0) { 468 Cflag = 0; 469 warnx("disabling CPU time statistics"); 470 } 471 } 472 473 if (!--headercount) { 474 phdr(); 475 if (wresized != 0) 476 doresize(); 477 headercount = wrows; 478 } 479 480 tmp_dinfo = last.dinfo; 481 last.dinfo = cur.dinfo; 482 cur.dinfo = tmp_dinfo; 483 484 last.snap_time = cur.snap_time; 485 486 /* 487 * Here what we want to do is refresh our device stats. 488 * devstat_getdevs() returns 1 when the device list has changed. 489 * If the device list has changed, we want to go through 490 * the selection process again, in case a device that we 491 * were previously displaying has gone away. 492 */ 493 switch (devstat_getdevs(kd, &cur)) { 494 case -1: 495 errx(1, "%s", devstat_errbuf); 496 break; 497 case 1: { 498 int retval; 499 500 num_devices = cur.dinfo->numdevs; 501 generation = cur.dinfo->generation; 502 retval = devstat_selectdevs(&dev_select, &num_selected, 503 &num_selections, 504 &select_generation, 505 generation, 506 cur.dinfo->devices, 507 num_devices, matches, 508 num_matches, 509 specified_devices, 510 num_devices_specified, 511 select_mode, maxshowdevs, 512 hflag); 513 switch(retval) { 514 case -1: 515 errx(1, "%s", devstat_errbuf); 516 break; 517 case 1: 518 phdr(); 519 if (wresized != 0) 520 doresize(); 521 headercount = wrows; 522 break; 523 default: 524 break; 525 } 526 break; 527 } 528 default: 529 break; 530 } 531 532 /* 533 * We only want to re-select devices if we're in 'top' 534 * mode. This is the only mode where the devices selected 535 * could actually change. 536 */ 537 if (hflag > 0) { 538 int retval; 539 retval = devstat_selectdevs(&dev_select, &num_selected, 540 &num_selections, 541 &select_generation, 542 generation, 543 cur.dinfo->devices, 544 num_devices, matches, 545 num_matches, 546 specified_devices, 547 num_devices_specified, 548 select_mode, maxshowdevs, 549 hflag); 550 switch(retval) { 551 case -1: 552 errx(1,"%s", devstat_errbuf); 553 break; 554 case 1: 555 phdr(); 556 if (wresized != 0) 557 doresize(); 558 headercount = wrows; 559 break; 560 default: 561 break; 562 } 563 } 564 565 if (Tflag > 0) { 566 tmp = cur.tk_nin; 567 cur.tk_nin -= last.tk_nin; 568 last.tk_nin = tmp; 569 tmp = cur.tk_nout; 570 cur.tk_nout -= last.tk_nout; 571 last.tk_nout = tmp; 572 } 573 574 etime = cur.snap_time - last.snap_time; 575 576 if (etime == 0.0) 577 etime = 1.0; 578 579 for (i = 0; i < CPUSTATES; i++) { 580 tmp = cur.cp_time[i]; 581 cur.cp_time[i] -= last.cp_time[i]; 582 last.cp_time[i] = tmp; 583 } 584 585 if (xflag == 0 && Tflag > 0) 586 printf("%4.0Lf%5.0Lf", cur.tk_nin / etime, 587 cur.tk_nout / etime); 588 589 devstats(hflag, etime, havelast); 590 591 if (xflag == 0) { 592 if (Cflag > 0) 593 cpustats(); 594 595 printf("\n"); 596 } 597 fflush(stdout); 598 599 if (count >= 0 && --count <= 0) 600 break; 601 602 sleep(waittime); 603 havelast = 1; 604 } 605 606 exit(0); 607 } 608 609 /* 610 * Force a header to be prepended to the next output. 611 */ 612 void 613 needhdr(int signo) 614 { 615 616 headercount = 1; 617 } 618 619 /* 620 * When the terminal is resized, force an update of the maximum number of rows 621 * printed between each header repetition. Then force a new header to be 622 * prepended to the next output. 623 */ 624 void 625 needresize(int signo) 626 { 627 628 wresized = 1; 629 headercount = 1; 630 } 631 632 /* 633 * Update the global `wrows' count of terminal rows. 634 */ 635 void 636 doresize(void) 637 { 638 int status; 639 struct winsize w; 640 641 for (;;) { 642 status = ioctl(fileno(stdout), TIOCGWINSZ, &w); 643 if (status == -1 && errno == EINTR) 644 continue; 645 else if (status == -1) 646 err(1, "ioctl"); 647 if (w.ws_row > 3) 648 wrows = w.ws_row - 3; 649 else 650 wrows = IOSTAT_DEFAULT_ROWS; 651 break; 652 } 653 654 /* 655 * Inhibit doresize() calls until we are rescheduled by SIGWINCH. 656 */ 657 wresized = 0; 658 } 659 660 static void 661 phdr(void) 662 { 663 int i, printed; 664 665 /* 666 * If xflag is set, we need a per-loop header, not a page header, so 667 * just return. We'll print the header in devstats(). 668 */ 669 if (xflag > 0) 670 return; 671 672 if (Tflag > 0) 673 (void)printf(" tty"); 674 for (i = 0, printed=0;(i < num_devices) && (printed < maxshowdevs);i++){ 675 int di; 676 if ((dev_select[i].selected != 0) 677 && (dev_select[i].selected <= maxshowdevs)) { 678 di = dev_select[i].position; 679 if (oflag > 0) 680 (void)printf("%12.6s%d ", 681 cur.dinfo->devices[di].device_name, 682 cur.dinfo->devices[di].unit_number); 683 else 684 printf("%15.6s%d ", 685 cur.dinfo->devices[di].device_name, 686 cur.dinfo->devices[di].unit_number); 687 printed++; 688 } 689 } 690 if (Cflag > 0) 691 (void)printf(" cpu\n"); 692 else 693 (void)printf("\n"); 694 695 if (Tflag > 0) 696 (void)printf(" tin tout"); 697 698 for (i=0, printed = 0;(i < num_devices) && (printed < maxshowdevs);i++){ 699 if ((dev_select[i].selected != 0) 700 && (dev_select[i].selected <= maxshowdevs)) { 701 if (oflag > 0) { 702 if (Iflag == 0) 703 (void)printf(" sps tps msps "); 704 else 705 (void)printf(" blk xfr msps "); 706 } else { 707 if (Iflag == 0) 708 printf(" KB/t tps MB/s "); 709 else 710 printf(" KB/t xfrs MB "); 711 } 712 printed++; 713 } 714 } 715 if (Cflag > 0) 716 (void)printf(" us ni sy in id\n"); 717 else 718 printf("\n"); 719 720 } 721 722 static void 723 devstats(int perf_select, long double etime, int havelast) 724 { 725 int dn; 726 long double transfers_per_second, transfers_per_second_read, transfers_per_second_write; 727 long double kb_per_transfer, mb_per_second, mb_per_second_read, mb_per_second_write; 728 u_int64_t total_bytes, total_transfers, total_blocks; 729 u_int64_t total_bytes_read, total_transfers_read; 730 u_int64_t total_bytes_write, total_transfers_write; 731 long double busy_pct; 732 u_int64_t queue_len; 733 long double total_mb; 734 long double blocks_per_second, ms_per_transaction; 735 int firstline = 1; 736 char *devname; 737 738 if (xflag > 0) { 739 printf(" extended device statistics "); 740 if (Tflag > 0) 741 printf(" tty "); 742 if (Cflag > 0) 743 printf(" cpu "); 744 printf("\n"); 745 if (Iflag == 0) 746 printf( 747 "device r/s w/s kr/s kw/s wait svc_t %%b " 748 ); 749 else 750 printf( 751 "device r/i w/i kr/i kw/i wait svc_t %%b " 752 ); 753 if (Tflag > 0) 754 printf("tin tout "); 755 if (Cflag > 0) 756 printf("us ni sy in id "); 757 printf("\n"); 758 } 759 760 for (dn = 0; dn < num_devices; dn++) { 761 int di; 762 763 if (((perf_select == 0) && (dev_select[dn].selected == 0)) 764 || (dev_select[dn].selected > maxshowdevs)) 765 continue; 766 767 di = dev_select[dn].position; 768 769 if (devstat_compute_statistics(&cur.dinfo->devices[di], 770 havelast ? &last.dinfo->devices[di] : NULL, etime, 771 DSM_TOTAL_BYTES, &total_bytes, 772 DSM_TOTAL_BYTES_READ, &total_bytes_read, 773 DSM_TOTAL_BYTES_WRITE, &total_bytes_write, 774 DSM_TOTAL_TRANSFERS, &total_transfers, 775 DSM_TOTAL_TRANSFERS_READ, &total_transfers_read, 776 DSM_TOTAL_TRANSFERS_WRITE, &total_transfers_write, 777 DSM_TOTAL_BLOCKS, &total_blocks, 778 DSM_KB_PER_TRANSFER, &kb_per_transfer, 779 DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 780 DSM_TRANSFERS_PER_SECOND_READ, &transfers_per_second_read, 781 DSM_TRANSFERS_PER_SECOND_WRITE, &transfers_per_second_write, 782 DSM_MB_PER_SECOND, &mb_per_second, 783 DSM_MB_PER_SECOND_READ, &mb_per_second_read, 784 DSM_MB_PER_SECOND_WRITE, &mb_per_second_write, 785 DSM_BLOCKS_PER_SECOND, &blocks_per_second, 786 DSM_MS_PER_TRANSACTION, &ms_per_transaction, 787 DSM_BUSY_PCT, &busy_pct, 788 DSM_QUEUE_LENGTH, &queue_len, 789 DSM_NONE) != 0) 790 errx(1, "%s", devstat_errbuf); 791 792 if (perf_select != 0) { 793 dev_select[dn].bytes = total_bytes; 794 if ((dev_select[dn].selected == 0) 795 || (dev_select[dn].selected > maxshowdevs)) 796 continue; 797 } 798 799 if (Kflag > 0 || xflag > 0) { 800 int block_size = cur.dinfo->devices[di].block_size; 801 total_blocks = total_blocks * (block_size ? 802 block_size : 512) / 1024; 803 } 804 805 if (xflag > 0) { 806 if (asprintf(&devname, "%s%d", 807 cur.dinfo->devices[di].device_name, 808 cur.dinfo->devices[di].unit_number) == -1) 809 err(1, "asprintf"); 810 /* 811 * If zflag is set, skip any devices with zero I/O. 812 */ 813 if (zflag == 0 || transfers_per_second_read > 0.05 || 814 transfers_per_second_write > 0.05 || 815 mb_per_second_read > ((long double).0005)/1024 || 816 mb_per_second_write > ((long double).0005)/1024 || 817 busy_pct > 0.5) { 818 if (Iflag == 0) 819 printf("%-8.8s %5.1Lf %5.1Lf %7.1Lf %7.1Lf %4qu %5.1Lf %3.0Lf ", 820 devname, transfers_per_second_read, 821 transfers_per_second_write, 822 mb_per_second_read * 1024, 823 mb_per_second_write * 1024, 824 queue_len, 825 ms_per_transaction, busy_pct); 826 else 827 printf("%-8.8s %5.1Lf %5.1Lf %7.1Lf %7.1Lf %4qu %5.1Lf %3.0Lf ", 828 devname, 829 (long double)total_transfers_read, 830 (long double)total_transfers_write, 831 (long double) 832 total_bytes_read / 1024, 833 (long double) 834 total_bytes_write / 1024, 835 queue_len, 836 ms_per_transaction, busy_pct); 837 if (firstline) { 838 /* 839 * If this is the first device 840 * we're printing, also print 841 * CPU or TTY stats if requested. 842 */ 843 firstline = 0; 844 if (Tflag > 0) 845 printf("%4.0Lf%5.0Lf", 846 cur.tk_nin / etime, 847 cur.tk_nout / etime); 848 if (Cflag > 0) 849 cpustats(); 850 } 851 printf("\n"); 852 } 853 free(devname); 854 } else if (oflag > 0) { 855 int msdig = (ms_per_transaction < 100.0) ? 1 : 0; 856 857 if (Iflag == 0) 858 printf("%4.0Lf%4.0Lf%5.*Lf ", 859 blocks_per_second, 860 transfers_per_second, 861 msdig, 862 ms_per_transaction); 863 else 864 printf("%4.1qu%4.1qu%5.*Lf ", 865 total_blocks, 866 total_transfers, 867 msdig, 868 ms_per_transaction); 869 } else { 870 if (Iflag == 0) 871 printf(" %5.2Lf %3.0Lf %5.2Lf ", 872 kb_per_transfer, 873 transfers_per_second, 874 mb_per_second); 875 else { 876 total_mb = total_bytes; 877 total_mb /= 1024 * 1024; 878 879 printf(" %5.2Lf %3.1qu %5.2Lf ", 880 kb_per_transfer, 881 total_transfers, 882 total_mb); 883 } 884 } 885 } 886 if (xflag > 0 && zflag > 0 && firstline == 1 && 887 (Tflag > 0 || Cflag > 0)) { 888 /* 889 * If zflag is set and we did not print any device 890 * lines I/O because they were all zero, 891 * print TTY/CPU stats. 892 */ 893 printf("%52s",""); 894 if (Tflag > 0) 895 printf("%4.0Lf%5.0Lf", cur.tk_nin / etime, 896 cur.tk_nout / etime); 897 if (Cflag > 0) 898 cpustats(); 899 printf("\n"); 900 } 901 } 902 903 static void 904 cpustats(void) 905 { 906 int state; 907 double time; 908 909 time = 0.0; 910 911 for (state = 0; state < CPUSTATES; ++state) 912 time += cur.cp_time[state]; 913 for (state = 0; state < CPUSTATES; ++state) 914 printf(" %2.0f", 915 rint(100. * cur.cp_time[state] / (time ? time : 1))); 916 } 917 918 static int 919 readvar(kvm_t *kd, const char *name, int nlid, void *ptr, size_t len) 920 { 921 if (kd != NULL) { 922 ssize_t nbytes; 923 924 nbytes = kvm_read(kd, namelist[nlid].n_value, ptr, len); 925 926 if (nbytes < 0) { 927 warnx("kvm_read(%s): %s", namelist[nlid].n_name, 928 kvm_geterr(kd)); 929 return (1); 930 } 931 if (nbytes != len) { 932 warnx("kvm_read(%s): expected %zu bytes, got %zd bytes", 933 namelist[nlid].n_name, len, nbytes); 934 return (1); 935 } 936 } else { 937 size_t nlen = len; 938 939 if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 940 warn("sysctl(%s...) failed", name); 941 return (1); 942 } 943 if (nlen != len) { 944 warnx("sysctl(%s...): expected %lu, got %lu", name, 945 (unsigned long)len, (unsigned long)nlen); 946 return (1); 947 } 948 } 949 return (0); 950 } 951