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 <unistd.h> 117 #include <limits.h> 118 #include <devstat.h> 119 #include <math.h> 120 121 struct nlist namelist[] = { 122 #define X_TK_NIN 0 123 { "_tk_nin" }, 124 #define X_TK_NOUT 1 125 { "_tk_nout" }, 126 #define X_CP_TIME 2 127 { "_cp_time" }, 128 #define X_BOOTTIME 3 129 { "_boottime" }, 130 #define X_END 3 131 { NULL }, 132 }; 133 134 struct statinfo cur, last; 135 int num_devices; 136 struct device_selection *dev_select; 137 int maxshowdevs; 138 volatile sig_atomic_t headercount; 139 int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0; 140 int xflag = 0, zflag = 0; 141 142 /* local function declarations */ 143 static void usage(void); 144 static void needhdr(int signo); 145 static void phdr(void); 146 static void devstats(int perf_select, long double etime, int havelast); 147 static void cpustats(void); 148 static int readvar(kvm_t *kd, const char *name, int nlid, void *ptr, 149 size_t len); 150 151 static void 152 usage(void) 153 { 154 /* 155 * We also support the following 'traditional' syntax: 156 * iostat [drives] [wait [count]] 157 * This isn't mentioned in the man page, or the usage statement, 158 * but it is supported. 159 */ 160 fprintf(stderr, "usage: iostat [-CdhIKoTxz?] [-c count] [-M core]" 161 " [-n devs] [-N system]\n" 162 "\t [-t type,if,pass] [-w wait] [drives]\n"); 163 } 164 165 int 166 main(int argc, char **argv) 167 { 168 int c, i; 169 int tflag = 0, hflag = 0, cflag = 0, wflag = 0, nflag = 0; 170 int count = 0, waittime = 0; 171 char *memf = NULL, *nlistf = NULL; 172 struct devstat_match *matches; 173 int num_matches = 0; 174 char errbuf[_POSIX2_LINE_MAX]; 175 kvm_t *kd = NULL; 176 long generation; 177 int num_devices_specified; 178 int num_selected, num_selections; 179 long select_generation; 180 char **specified_devices; 181 devstat_select_mode select_mode; 182 int havelast = 0; 183 184 matches = NULL; 185 maxshowdevs = 3; 186 187 while ((c = getopt(argc, argv, "c:CdhIKM:n:N:ot:Tw:xz?")) != -1) { 188 switch(c) { 189 case 'c': 190 cflag++; 191 count = atoi(optarg); 192 if (count < 1) 193 errx(1, "count %d is < 1", count); 194 break; 195 case 'C': 196 Cflag++; 197 break; 198 case 'd': 199 dflag++; 200 break; 201 case 'h': 202 hflag++; 203 break; 204 case 'I': 205 Iflag++; 206 break; 207 case 'K': 208 Kflag++; 209 break; 210 case 'M': 211 memf = optarg; 212 break; 213 case 'n': 214 nflag++; 215 maxshowdevs = atoi(optarg); 216 if (maxshowdevs < 0) 217 errx(1, "number of devices %d is < 0", 218 maxshowdevs); 219 break; 220 case 'N': 221 nlistf = optarg; 222 break; 223 case 'o': 224 oflag++; 225 break; 226 case 't': 227 tflag++; 228 if (devstat_buildmatch(optarg, &matches, 229 &num_matches) != 0) 230 errx(1, "%s", devstat_errbuf); 231 break; 232 case 'T': 233 Tflag++; 234 break; 235 case 'w': 236 wflag++; 237 waittime = atoi(optarg); 238 if (waittime < 1) 239 errx(1, "wait time is < 1"); 240 break; 241 case 'x': 242 xflag++; 243 break; 244 case 'z': 245 zflag++; 246 break; 247 default: 248 usage(); 249 exit(1); 250 break; 251 } 252 } 253 254 argc -= optind; 255 argv += optind; 256 257 if (nlistf != NULL || memf != NULL) { 258 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 259 260 if (kd == NULL) 261 errx(1, "kvm_openfiles: %s", errbuf); 262 263 if (kvm_nlist(kd, namelist) == -1) 264 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 265 } 266 267 /* 268 * Make sure that the userland devstat version matches the kernel 269 * devstat version. If not, exit and print a message informing 270 * the user of his mistake. 271 */ 272 if (devstat_checkversion(kd) < 0) 273 errx(1, "%s", devstat_errbuf); 274 275 /* 276 * Make sure Tflag and/or Cflag are set if dflag == 0. If dflag is 277 * greater than 0, they may be 0 or non-zero. 278 */ 279 if (dflag == 0 && xflag == 0) { 280 Cflag = 1; 281 Tflag = 1; 282 } 283 284 /* find out how many devices we have */ 285 if ((num_devices = devstat_getnumdevs(kd)) < 0) 286 err(1, "can't get number of devices"); 287 288 /* 289 * Figure out how many devices we should display. 290 */ 291 if (nflag == 0) { 292 if (xflag > 0) 293 maxshowdevs = num_devices; 294 else if (oflag > 0) { 295 if ((dflag > 0) && (Cflag == 0) && (Tflag == 0)) 296 maxshowdevs = 5; 297 else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0)) 298 maxshowdevs = 5; 299 else 300 maxshowdevs = 4; 301 } else { 302 if ((dflag > 0) && (Cflag == 0)) 303 maxshowdevs = 4; 304 else 305 maxshowdevs = 3; 306 } 307 } 308 309 cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 310 if (cur.dinfo == NULL) 311 err(1, "malloc failed"); 312 313 last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 314 if (last.dinfo == NULL) 315 err(1, "malloc failed"); 316 317 bzero(cur.dinfo, sizeof(struct devinfo)); 318 bzero(last.dinfo, sizeof(struct devinfo)); 319 320 /* 321 * Grab all the devices. We don't look to see if the list has 322 * changed here, since it almost certainly has. We only look for 323 * errors. 324 */ 325 if (devstat_getdevs(kd, &cur) == -1) 326 errx(1, "%s", devstat_errbuf); 327 328 num_devices = cur.dinfo->numdevs; 329 generation = cur.dinfo->generation; 330 331 /* 332 * If the user specified any devices on the command line, see if 333 * they are in the list of devices we have now. 334 */ 335 specified_devices = (char **)malloc(sizeof(char *)); 336 if (specified_devices == NULL) 337 err(1, "malloc failed"); 338 339 for (num_devices_specified = 0; *argv; ++argv) { 340 if (isdigit(**argv)) 341 break; 342 num_devices_specified++; 343 specified_devices = (char **)realloc(specified_devices, 344 sizeof(char *) * 345 num_devices_specified); 346 if (specified_devices == NULL) 347 err(1, "realloc failed"); 348 349 specified_devices[num_devices_specified - 1] = *argv; 350 351 } 352 if (nflag == 0 && maxshowdevs < num_devices_specified) 353 maxshowdevs = num_devices_specified; 354 355 dev_select = NULL; 356 357 if ((num_devices_specified == 0) && (num_matches == 0)) 358 select_mode = DS_SELECT_ADD; 359 else 360 select_mode = DS_SELECT_ONLY; 361 362 /* 363 * At this point, selectdevs will almost surely indicate that the 364 * device list has changed, so we don't look for return values of 0 365 * or 1. If we get back -1, though, there is an error. 366 */ 367 if (devstat_selectdevs(&dev_select, &num_selected, 368 &num_selections, &select_generation, generation, 369 cur.dinfo->devices, num_devices, matches, 370 num_matches, specified_devices, 371 num_devices_specified, select_mode, maxshowdevs, 372 hflag) == -1) 373 errx(1, "%s", devstat_errbuf); 374 375 /* 376 * Look for the traditional wait time and count arguments. 377 */ 378 if (*argv) { 379 waittime = atoi(*argv); 380 381 /* Let the user know he goofed, but keep going anyway */ 382 if (wflag != 0) 383 warnx("discarding previous wait interval, using" 384 " %d instead", waittime); 385 wflag++; 386 387 if (*++argv) { 388 count = atoi(*argv); 389 if (cflag != 0) 390 warnx("discarding previous count, using %d" 391 " instead", count); 392 cflag++; 393 } else 394 count = -1; 395 } 396 397 /* 398 * If the user specified a count, but not an interval, we default 399 * to an interval of 1 second. 400 */ 401 if ((wflag == 0) && (cflag > 0)) 402 waittime = 1; 403 404 /* 405 * If the user specified a wait time, but not a count, we want to 406 * go on ad infinitum. This can be redundant if the user uses the 407 * traditional method of specifying the wait, since in that case we 408 * already set count = -1 above. Oh well. 409 */ 410 if ((wflag > 0) && (cflag == 0)) 411 count = -1; 412 413 bzero(&cur.cp_time, sizeof(cur.cp_time)); 414 cur.tk_nout = 0; 415 cur.tk_nin = 0; 416 417 /* 418 * Set the snap time to the system boot time (ie: zero), so the 419 * stats are calculated since system boot. 420 */ 421 cur.snap_time = 0; 422 423 /* 424 * If the user stops the program (control-Z) and then resumes it, 425 * print out the header again. 426 */ 427 (void)signal(SIGCONT, needhdr); 428 429 for (headercount = 1;;) { 430 struct devinfo *tmp_dinfo; 431 long tmp; 432 long double etime; 433 434 if (Tflag > 0) { 435 if ((readvar(kd, "kern.tty_nin", X_TK_NIN, &cur.tk_nin, 436 sizeof(cur.tk_nin)) != 0) 437 || (readvar(kd, "kern.tty_nout", X_TK_NOUT, 438 &cur.tk_nout, sizeof(cur.tk_nout))!= 0)) { 439 Tflag = 0; 440 warnx("disabling TTY statistics"); 441 } 442 } 443 444 if (Cflag > 0) { 445 if (readvar(kd, "kern.cp_time", X_CP_TIME, 446 &cur.cp_time, sizeof(cur.cp_time)) != 0) { 447 Cflag = 0; 448 warnx("disabling CPU time statistics"); 449 } 450 } 451 452 if (!--headercount) { 453 phdr(); 454 headercount = 20; 455 } 456 457 tmp_dinfo = last.dinfo; 458 last.dinfo = cur.dinfo; 459 cur.dinfo = tmp_dinfo; 460 461 last.snap_time = cur.snap_time; 462 463 /* 464 * Here what we want to do is refresh our device stats. 465 * devstat_getdevs() returns 1 when the device list has changed. 466 * If the device list has changed, we want to go through 467 * the selection process again, in case a device that we 468 * were previously displaying has gone away. 469 */ 470 switch (devstat_getdevs(kd, &cur)) { 471 case -1: 472 errx(1, "%s", devstat_errbuf); 473 break; 474 case 1: { 475 int retval; 476 477 num_devices = cur.dinfo->numdevs; 478 generation = cur.dinfo->generation; 479 retval = devstat_selectdevs(&dev_select, &num_selected, 480 &num_selections, 481 &select_generation, 482 generation, 483 cur.dinfo->devices, 484 num_devices, matches, 485 num_matches, 486 specified_devices, 487 num_devices_specified, 488 select_mode, maxshowdevs, 489 hflag); 490 switch(retval) { 491 case -1: 492 errx(1, "%s", devstat_errbuf); 493 break; 494 case 1: 495 phdr(); 496 headercount = 20; 497 break; 498 default: 499 break; 500 } 501 break; 502 } 503 default: 504 break; 505 } 506 507 /* 508 * We only want to re-select devices if we're in 'top' 509 * mode. This is the only mode where the devices selected 510 * could actually change. 511 */ 512 if (hflag > 0) { 513 int retval; 514 retval = devstat_selectdevs(&dev_select, &num_selected, 515 &num_selections, 516 &select_generation, 517 generation, 518 cur.dinfo->devices, 519 num_devices, matches, 520 num_matches, 521 specified_devices, 522 num_devices_specified, 523 select_mode, maxshowdevs, 524 hflag); 525 switch(retval) { 526 case -1: 527 errx(1,"%s", devstat_errbuf); 528 break; 529 case 1: 530 phdr(); 531 headercount = 20; 532 break; 533 default: 534 break; 535 } 536 } 537 538 if (Tflag > 0) { 539 tmp = cur.tk_nin; 540 cur.tk_nin -= last.tk_nin; 541 last.tk_nin = tmp; 542 tmp = cur.tk_nout; 543 cur.tk_nout -= last.tk_nout; 544 last.tk_nout = tmp; 545 } 546 547 etime = cur.snap_time - last.snap_time; 548 549 if (etime == 0.0) 550 etime = 1.0; 551 552 for (i = 0; i < CPUSTATES; i++) { 553 tmp = cur.cp_time[i]; 554 cur.cp_time[i] -= last.cp_time[i]; 555 last.cp_time[i] = tmp; 556 } 557 558 if (xflag == 0 && Tflag > 0) 559 printf("%4.0Lf%5.0Lf", cur.tk_nin / etime, 560 cur.tk_nout / etime); 561 562 devstats(hflag, etime, havelast); 563 564 if (xflag == 0) { 565 if (Cflag > 0) 566 cpustats(); 567 568 printf("\n"); 569 } 570 fflush(stdout); 571 572 if (count >= 0 && --count <= 0) 573 break; 574 575 sleep(waittime); 576 havelast = 1; 577 } 578 579 exit(0); 580 } 581 582 /* 583 * Force a header to be prepended to the next output. 584 */ 585 void 586 needhdr(int signo) 587 { 588 589 headercount = 1; 590 } 591 592 static void 593 phdr(void) 594 { 595 int i, printed; 596 597 /* 598 * If xflag is set, we need a per-loop header, not a page header, so 599 * just return. We'll print the header in devstats(). 600 */ 601 if (xflag > 0) 602 return; 603 604 if (Tflag > 0) 605 (void)printf(" tty"); 606 for (i = 0, printed=0;(i < num_devices) && (printed < maxshowdevs);i++){ 607 int di; 608 if ((dev_select[i].selected != 0) 609 && (dev_select[i].selected <= maxshowdevs)) { 610 di = dev_select[i].position; 611 if (oflag > 0) 612 (void)printf("%12.6s%d ", 613 cur.dinfo->devices[di].device_name, 614 cur.dinfo->devices[di].unit_number); 615 else 616 printf("%15.6s%d ", 617 cur.dinfo->devices[di].device_name, 618 cur.dinfo->devices[di].unit_number); 619 printed++; 620 } 621 } 622 if (Cflag > 0) 623 (void)printf(" cpu\n"); 624 else 625 (void)printf("\n"); 626 627 if (Tflag > 0) 628 (void)printf(" tin tout"); 629 630 for (i=0, printed = 0;(i < num_devices) && (printed < maxshowdevs);i++){ 631 if ((dev_select[i].selected != 0) 632 && (dev_select[i].selected <= maxshowdevs)) { 633 if (oflag > 0) { 634 if (Iflag == 0) 635 (void)printf(" sps tps msps "); 636 else 637 (void)printf(" blk xfr msps "); 638 } else { 639 if (Iflag == 0) 640 printf(" KB/t tps MB/s "); 641 else 642 printf(" KB/t xfrs MB "); 643 } 644 printed++; 645 } 646 } 647 if (Cflag > 0) 648 (void)printf(" us ni sy in id\n"); 649 else 650 printf("\n"); 651 652 } 653 654 static void 655 devstats(int perf_select, long double etime, int havelast) 656 { 657 int dn; 658 long double transfers_per_second, transfers_per_second_read, transfers_per_second_write; 659 long double kb_per_transfer, mb_per_second, mb_per_second_read, mb_per_second_write; 660 u_int64_t total_bytes, total_transfers, total_blocks; 661 u_int64_t total_bytes_read, total_transfers_read; 662 u_int64_t total_bytes_write, total_transfers_write; 663 long double busy_pct; 664 u_int64_t queue_len; 665 long double total_mb; 666 long double blocks_per_second, ms_per_transaction; 667 int firstline = 1; 668 char *devname; 669 670 if (xflag > 0) { 671 printf(" extended device statistics "); 672 if (Tflag > 0) 673 printf(" tty "); 674 if (Cflag > 0) 675 printf(" cpu "); 676 printf("\n"); 677 if (Iflag == 0) 678 printf( 679 "device r/s w/s kr/s kw/s wait svc_t %%b " 680 ); 681 else 682 printf( 683 "device r/i w/i kr/i kw/i wait svc_t %%b " 684 ); 685 if (Tflag > 0) 686 printf("tin tout "); 687 if (Cflag > 0) 688 printf("us ni sy in id "); 689 printf("\n"); 690 } 691 692 for (dn = 0; dn < num_devices; dn++) { 693 int di; 694 695 if (((perf_select == 0) && (dev_select[dn].selected == 0)) 696 || (dev_select[dn].selected > maxshowdevs)) 697 continue; 698 699 di = dev_select[dn].position; 700 701 if (devstat_compute_statistics(&cur.dinfo->devices[di], 702 havelast ? &last.dinfo->devices[di] : NULL, etime, 703 DSM_TOTAL_BYTES, &total_bytes, 704 DSM_TOTAL_BYTES_READ, &total_bytes_read, 705 DSM_TOTAL_BYTES_WRITE, &total_bytes_write, 706 DSM_TOTAL_TRANSFERS, &total_transfers, 707 DSM_TOTAL_TRANSFERS_READ, &total_transfers_read, 708 DSM_TOTAL_TRANSFERS_WRITE, &total_transfers_write, 709 DSM_TOTAL_BLOCKS, &total_blocks, 710 DSM_KB_PER_TRANSFER, &kb_per_transfer, 711 DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 712 DSM_TRANSFERS_PER_SECOND_READ, &transfers_per_second_read, 713 DSM_TRANSFERS_PER_SECOND_WRITE, &transfers_per_second_write, 714 DSM_MB_PER_SECOND, &mb_per_second, 715 DSM_MB_PER_SECOND_READ, &mb_per_second_read, 716 DSM_MB_PER_SECOND_WRITE, &mb_per_second_write, 717 DSM_BLOCKS_PER_SECOND, &blocks_per_second, 718 DSM_MS_PER_TRANSACTION, &ms_per_transaction, 719 DSM_BUSY_PCT, &busy_pct, 720 DSM_QUEUE_LENGTH, &queue_len, 721 DSM_NONE) != 0) 722 errx(1, "%s", devstat_errbuf); 723 724 if (perf_select != 0) { 725 dev_select[dn].bytes = total_bytes; 726 if ((dev_select[dn].selected == 0) 727 || (dev_select[dn].selected > maxshowdevs)) 728 continue; 729 } 730 731 if (Kflag > 0 || xflag > 0) { 732 int block_size = cur.dinfo->devices[di].block_size; 733 total_blocks = total_blocks * (block_size ? 734 block_size : 512) / 1024; 735 } 736 737 if (xflag > 0) { 738 if (asprintf(&devname, "%s%d", 739 cur.dinfo->devices[di].device_name, 740 cur.dinfo->devices[di].unit_number) == -1) 741 err(1, "asprintf"); 742 /* 743 * If zflag is set, skip any devices with zero I/O. 744 */ 745 if (zflag == 0 || transfers_per_second_read > 0.05 || 746 transfers_per_second_write > 0.05 || 747 mb_per_second_read > ((long double).0005)/1024 || 748 mb_per_second_write > ((long double).0005)/1024 || 749 busy_pct > 0.5) { 750 if (Iflag == 0) 751 printf("%-8.8s %5.1Lf %5.1Lf %7.1Lf %7.1Lf %4qu %5.1Lf %3.0Lf ", 752 devname, transfers_per_second_read, 753 transfers_per_second_write, 754 mb_per_second_read * 1024, 755 mb_per_second_write * 1024, 756 queue_len, 757 ms_per_transaction, busy_pct); 758 else 759 printf("%-8.8s %5.1Lf %5.1Lf %7.1Lf %7.1Lf %4qu %5.1Lf %3.0Lf ", 760 devname, 761 (long double)total_transfers_read, 762 (long double)total_transfers_write, 763 (long double) 764 total_bytes_read / 1024, 765 (long double) 766 total_bytes_write / 1024, 767 queue_len, 768 ms_per_transaction, busy_pct); 769 if (firstline) { 770 /* 771 * If this is the first device 772 * we're printing, also print 773 * CPU or TTY stats if requested. 774 */ 775 firstline = 0; 776 if (Tflag > 0) 777 printf("%4.0Lf%5.0Lf", 778 cur.tk_nin / etime, 779 cur.tk_nout / etime); 780 if (Cflag > 0) 781 cpustats(); 782 } 783 printf("\n"); 784 } 785 free(devname); 786 } else if (oflag > 0) { 787 int msdig = (ms_per_transaction < 100.0) ? 1 : 0; 788 789 if (Iflag == 0) 790 printf("%4.0Lf%4.0Lf%5.*Lf ", 791 blocks_per_second, 792 transfers_per_second, 793 msdig, 794 ms_per_transaction); 795 else 796 printf("%4.1qu%4.1qu%5.*Lf ", 797 total_blocks, 798 total_transfers, 799 msdig, 800 ms_per_transaction); 801 } else { 802 if (Iflag == 0) 803 printf(" %5.2Lf %3.0Lf %5.2Lf ", 804 kb_per_transfer, 805 transfers_per_second, 806 mb_per_second); 807 else { 808 total_mb = total_bytes; 809 total_mb /= 1024 * 1024; 810 811 printf(" %5.2Lf %3.1qu %5.2Lf ", 812 kb_per_transfer, 813 total_transfers, 814 total_mb); 815 } 816 } 817 } 818 if (xflag > 0 && zflag > 0 && firstline == 1 && 819 (Tflag > 0 || Cflag > 0)) { 820 /* 821 * If zflag is set and we did not print any device 822 * lines I/O because they were all zero, 823 * print TTY/CPU stats. 824 */ 825 printf("%52s",""); 826 if (Tflag > 0) 827 printf("%4.0Lf%5.0Lf", cur.tk_nin / etime, 828 cur.tk_nout / etime); 829 if (Cflag > 0) 830 cpustats(); 831 printf("\n"); 832 } 833 } 834 835 static void 836 cpustats(void) 837 { 838 int state; 839 double time; 840 841 time = 0.0; 842 843 for (state = 0; state < CPUSTATES; ++state) 844 time += cur.cp_time[state]; 845 for (state = 0; state < CPUSTATES; ++state) 846 printf(" %2.0f", 847 rint(100. * cur.cp_time[state] / (time ? time : 1))); 848 } 849 850 static int 851 readvar(kvm_t *kd, const char *name, int nlid, void *ptr, size_t len) 852 { 853 if (kd != NULL) { 854 ssize_t nbytes; 855 856 nbytes = kvm_read(kd, namelist[nlid].n_value, ptr, len); 857 858 if (nbytes < 0) { 859 warnx("kvm_read(%s): %s", namelist[nlid].n_name, 860 kvm_geterr(kd)); 861 return (1); 862 } 863 if (nbytes != len) { 864 warnx("kvm_read(%s): expected %zu bytes, got %zd bytes", 865 namelist[nlid].n_name, len, nbytes); 866 return (1); 867 } 868 } else { 869 size_t nlen = len; 870 871 if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 872 warn("sysctl(%s...) failed", name); 873 return (1); 874 } 875 if (nlen != len) { 876 warnx("sysctl(%s...): expected %lu, got %lu", name, 877 (unsigned long)len, (unsigned long)nlen); 878 return (1); 879 } 880 } 881 return (0); 882 } 883