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