iostat.c revision 39387
12061Sjkh/* 25749Swollman * Copyright (c) 1997, 1998 Kenneth D. Merry. 32061Sjkh * All rights reserved. 42061Sjkh * 52061Sjkh * Redistribution and use in source and binary forms, with or without 62061Sjkh * modification, are permitted provided that the following conditions 72061Sjkh * are met: 83197Scsgr * 1. Redistributions of source code must retain the above copyright 93197Scsgr * notice, this list of conditions and the following disclaimer. 102061Sjkh * 2. Redistributions in binary form must reproduce the above copyright 112160Scsgr * notice, this list of conditions and the following disclaimer in the 122834Swollman * documentation and/or other materials provided with the distribution. 132061Sjkh * 3. The name of the author may not be used to endorse or promote products 142061Sjkh * derived from this software without specific prior written permission. 152160Scsgr * 161594Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 172061Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 182061Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 191594Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 204486Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 214486Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 224486Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 234486Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 244486Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 252061Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 262061Sjkh * SUCH DAMAGE. 272061Sjkh * 282061Sjkh * $Id: iostat.c,v 1.10 1998/09/16 18:03:44 dillon Exp $ 292061Sjkh */ 302061Sjkh/* 312061Sjkh * Parts of this program are derived from the original FreeBSD iostat 322061Sjkh * program: 332061Sjkh */ 342061Sjkh/*- 352061Sjkh * Copyright (c) 1986, 1991, 1993 362061Sjkh * The Regents of the University of California. All rights reserved. 372061Sjkh * 382061Sjkh * Redistribution and use in source and binary forms, with or without 392061Sjkh * modification, are permitted provided that the following conditions 402061Sjkh * are met: 412061Sjkh * 1. Redistributions of source code must retain the above copyright 422061Sjkh * notice, this list of conditions and the following disclaimer. 433197Scsgr * 2. Redistributions in binary form must reproduce the above copyright 442626Scsgr * notice, this list of conditions and the following disclaimer in the 452626Scsgr * documentation and/or other materials provided with the distribution. 462061Sjkh * 3. All advertising materials mentioning features or use of this software 472061Sjkh * must display the following acknowledgement: 482061Sjkh * This product includes software developed by the University of 492061Sjkh * California, Berkeley and its contributors. 502061Sjkh * 4. Neither the name of the University nor the names of its contributors 512061Sjkh * may be used to endorse or promote products derived from this software 522061Sjkh * without specific prior written permission. 532061Sjkh * 542061Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 552061Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 562061Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 572061Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 582061Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 592061Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 602061Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 612061Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 622061Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 632061Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 642834Swollman * SUCH DAMAGE. 652834Swollman */ 662834Swollman/* 672834Swollman * Ideas for the new iostat statistics output modes taken from the NetBSD 682834Swollman * version of iostat: 692834Swollman */ 701594Srgrimes/* 714486Sphk * Copyright (c) 1996 John M. Vinopal 724486Sphk * All rights reserved. 734486Sphk * 744486Sphk * Redistribution and use in source and binary forms, with or without 754486Sphk * modification, are permitted provided that the following conditions 762061Sjkh * are met: 772061Sjkh * 1. Redistributions of source code must retain the above copyright 782061Sjkh * notice, this list of conditions and the following disclaimer. 792061Sjkh * 2. Redistributions in binary form must reproduce the above copyright 802061Sjkh * notice, this list of conditions and the following disclaimer in the 812061Sjkh * documentation and/or other materials provided with the distribution. 822061Sjkh * 3. All advertising materials mentioning features or use of this software 832061Sjkh * must display the following acknowledgement: 842061Sjkh * This product includes software developed for the NetBSD Project 852061Sjkh * by John M. Vinopal. 862061Sjkh * 4. The name of the author may not be used to endorse or promote products 872061Sjkh * derived from this software without specific prior written permission. 882061Sjkh * 892061Sjkh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 902061Sjkh * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 912061Sjkh * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 922061Sjkh * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 932061Sjkh * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 942061Sjkh * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 952061Sjkh * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 962061Sjkh * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 975511Sjkh * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 982061Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 992061Sjkh * SUCH DAMAGE. 1002061Sjkh */ 1012061Sjkh 1022061Sjkh 1032061Sjkh#include <sys/param.h> 1042061Sjkh#include <sys/types.h> 1052302Spaul#include <sys/errno.h> 1063030Srgrimes#include <sys/dkstat.h> 1072061Sjkh 1083030Srgrimes#include <err.h> 1092061Sjkh#include <ctype.h> 1103030Srgrimes#include <fcntl.h> 1112061Sjkh#include <kvm.h> 1122302Spaul#include <stdio.h> 1132302Spaul#include <stdlib.h> 1142302Spaul#include <string.h> 1152302Spaul#include <unistd.h> 1162302Spaul#include <limits.h> 1172302Spaul#include <devstat.h> 1182302Spaul 1192302Spaulstruct nlist namelist[] = { 1202302Spaul#define X_TK_NIN 0 1212302Spaul { "_tk_nin" }, 1222302Spaul#define X_TK_NOUT 1 1232302Spaul { "_tk_nout" }, 1242302Spaul#define X_CP_TIME 2 1252302Spaul { "_cp_time" }, 1262061Sjkh#define X_HZ 3 1272061Sjkh { "_hz" }, 1282061Sjkh#define X_STATHZ 4 1292061Sjkh { "_stathz" }, 1302061Sjkh#define X_END 4 1312061Sjkh { NULL }, 1322061Sjkh}; 1332061Sjkh 1342061Sjkhstruct statinfo cur, last; 1352061Sjkhint num_devices; 1362061Sjkhstruct device_selection *dev_select; 1372061Sjkhint maxshowdevs; 1382061Sjkhint dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0; 1392061Sjkh 1402061Sjkh#define nlread(x, v) \ 1412061Sjkh kvm_read(kd, namelist[x].n_value, &(v), sizeof(v)) 1422061Sjkh 1432061Sjkh/* local function declarations */ 1442061Sjkhstatic void usage(void); 1452061Sjkhstatic void phdr(int signo); 1462061Sjkhstatic void devstats(int perf_select); 1472061Sjkhstatic void cpustats(void); 1482061Sjkh 1492061Sjkhstatic void 1502061Sjkhusage(void) 1512061Sjkh{ 1523626Swollman /* 1533626Swollman * We also support the following 'traditional' syntax: 1543626Swollman * iostat [drives] [wait [count]] 1553626Swollman * This isn't mentioned in the man page, or the usage statement, 1563626Swollman * but it is supported. 1573626Swollman */ 1583626Swollman fprintf(stderr, "usage: iostat [-CdhIoT?] [-c count] [-M core]" 1593626Swollman " [-n devs] [-N system]\n" 1603626Swollman "\t [-t type,if,pass] [-w wait] [drives]\n"); 1613626Swollman} 1623626Swollman 1633626Swollmanint 1643626Swollmanmain(int argc, char **argv) 1653626Swollman{ 1663626Swollman int c; 1673626Swollman register int i; 1683626Swollman int tflag = 0, hflag = 0, cflag = 0, wflag = 0, nflag = 0; 1693626Swollman int count = 0, waittime = 0; 1703626Swollman char *memf = NULL, *nlistf = NULL; 1713626Swollman struct devstat_match *matches; 1723626Swollman int num_matches = 0; 1733626Swollman char errbuf[_POSIX2_LINE_MAX]; 1743626Swollman char *err_str; 1753626Swollman kvm_t *kd; 1763626Swollman int hz, stathz; 1773626Swollman int headercount; 1783626Swollman int generation; 1793626Swollman int num_devices_specified; 1803626Swollman int num_selected, num_selections, select_generation; 1813626Swollman char **specified_devices; 1823626Swollman devstat_select_mode select_mode; 1833626Swollman 1843626Swollman matches = NULL; 1853626Swollman maxshowdevs = 3; 1863626Swollman 1873626Swollman while ((c = getopt(argc, argv, "c:CdhIKM:n:N:ot:Tw:?")) != -1) { 1882061Sjkh switch(c) { 1892061Sjkh case 'c': 1902061Sjkh cflag++; 1912061Sjkh count = atoi(optarg); 1922061Sjkh if (count < 1) 1932061Sjkh errx(1, "count %d is < 1", count); 1942061Sjkh break; 1952061Sjkh case 'C': 1962061Sjkh Cflag++; 1972061Sjkh break; 1982061Sjkh case 'd': 1992061Sjkh dflag++; 2002061Sjkh break; 2012061Sjkh case 'h': 2022061Sjkh hflag++; 2032061Sjkh break; 2042061Sjkh case 'I': 2052061Sjkh Iflag++; 2064249Sache break; 2072685Srgrimes case 'K': 2082685Srgrimes Kflag++; 2093518Sache break; 2103197Scsgr case 'M': 2113197Scsgr memf = optarg; 2123197Scsgr break; 2132061Sjkh case 'n': 2142061Sjkh nflag++; 2152061Sjkh maxshowdevs = atoi(optarg); 2162883Sphk if (maxshowdevs < 0) 2173429Sache errx(1, "number of devcies %d is < 0", 2183429Sache maxshowdevs); 2193242Spaul break; 2203242Spaul case 'N': 2213242Spaul nlistf = optarg; 2222061Sjkh break; 2233213Spst case 'o': 2244942Sache oflag++; 2255749Swollman break; 2262061Sjkh case 't': 2275366Snate tflag++; 2285366Snate if (buildmatch(optarg, &matches, 2295366Snate &num_matches) != 0) 2305366Snate errx(1, "%s", devstat_errbuf); 2315366Snate break; 2325366Snate case 'T': 2335366Snate Tflag++; 2345366Snate break; 2355366Snate case 'w': 2365366Snate wflag++; 2375366Snate waittime = atoi(optarg); 2385728Swollman if (waittime < 1) 2395728Swollman errx(1, "wait time is < 1"); 2405728Swollman break; 2415728Swollman default: 2425728Swollman usage(); 2435366Snate exit(1); 2442061Sjkh break; 2452061Sjkh } 2462061Sjkh } 2472061Sjkh 2482061Sjkh argc -= optind; 2492061Sjkh argv += optind; 2502061Sjkh 2512061Sjkh /* 2522061Sjkh * Discard setgid privileges if not the running kernel so that bad 2532468Spaul * guys can't print interesting stuff from kernel memory. 2542061Sjkh */ 2552273Spaul if (nlistf != NULL || memf != NULL) 2562061Sjkh setgid(getgid()); 2572160Scsgr 2582160Scsgr /* 2592160Scsgr * Make sure that the userland devstat version matches the kernel 2602160Scsgr * devstat version. If not, exit and print a message informing 2612279Spaul * the user of his mistake. 2624054Spst */ 2634054Spst if (checkversion() < 0) 2642061Sjkh errx(1, "%s", devstat_errbuf); 2652061Sjkh 2662279Spaul /* 2672468Spaul * Figure out how many devices we should display. 2682468Spaul */ 2693197Scsgr if (nflag == 0) { 2702626Scsgr if (oflag > 0) { 2712626Scsgr if ((dflag > 0) && (Cflag == 0) && (Tflag == 0)) 2722626Scsgr maxshowdevs = 5; 2732626Scsgr else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0)) 2742626Scsgr maxshowdevs = 5; 2752626Scsgr else 2762626Scsgr maxshowdevs = 4; 2772626Scsgr } else { 2782626Scsgr if ((dflag > 0) && (Cflag == 0)) 2792061Sjkh maxshowdevs = 4; 2802061Sjkh else 2812061Sjkh maxshowdevs = 3; 2822061Sjkh } 2832061Sjkh } 2842061Sjkh 2852273Spaul /* find out how many devices we have */ 2862061Sjkh if ((num_devices = getnumdevs()) < 0) 2872061Sjkh err(1, "can't get number of devices"); 2882061Sjkh 2892061Sjkh cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 2901594Srgrimes last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 291 bzero(cur.dinfo, sizeof(struct devinfo)); 292 bzero(last.dinfo, sizeof(struct devinfo)); 293 294 /* 295 * Grab all the devices. We don't look to see if the list has 296 * changed here, since it almost certainly has. We only look for 297 * errors. 298 */ 299 if (getdevs(&cur) == -1) 300 errx(1, "%s", devstat_errbuf); 301 302 num_devices = cur.dinfo->numdevs; 303 generation = cur.dinfo->generation; 304 305 /* 306 * If the user specified any devices on the command line, see if 307 * they are in the list of devices we have now. 308 */ 309 specified_devices = (char **)malloc(sizeof(char *)); 310 for (num_devices_specified = 0; *argv; ++argv) { 311 if (isdigit(**argv)) 312 break; 313 num_devices_specified++; 314 specified_devices = (char **)realloc(specified_devices, 315 sizeof(char *) * 316 num_devices_specified); 317 specified_devices[num_devices_specified - 1] = *argv; 318 319 } 320 if (nflag == 0 && maxshowdevs < num_devices_specified) 321 maxshowdevs = num_devices_specified; 322 323 dev_select = NULL; 324 325 if ((num_devices_specified == 0) && (num_matches == 0)) 326 select_mode = DS_SELECT_ADD; 327 else 328 select_mode = DS_SELECT_ONLY; 329 330 /* 331 * At this point, selectdevs will almost surely indicate that the 332 * device list has changed, so we don't look for return values of 0 333 * or 1. If we get back -1, though, there is an error. 334 */ 335 if (selectdevs(&dev_select, &num_selected, 336 &num_selections, &select_generation, 337 generation, cur.dinfo->devices, num_devices, 338 matches, num_matches, 339 specified_devices, num_devices_specified, 340 select_mode, maxshowdevs, hflag) == -1) 341 errx(1, "%s", devstat_errbuf); 342 343 /* 344 * Look for the traditional wait time and count arguments. 345 */ 346 if (*argv) { 347 waittime = atoi(*argv); 348 349 /* Let the user know he goofed, but keep going anyway */ 350 if (wflag != 0) 351 warnx("discarding previous wait interval, using" 352 " %d instead", waittime); 353 wflag++; 354 355 if (*++argv) { 356 count = atoi(*argv); 357 if (cflag != 0) 358 warnx("discarding previous count, using %d" 359 " instead", count); 360 cflag++; 361 } else 362 count = -1; 363 } 364 365 /* 366 * If the user specified a count, but not an interval, we default 367 * to an interval of 1 second. 368 */ 369 if ((wflag == 0) && (cflag > 0)) 370 waittime = 1; 371 372 /* 373 * If the user specified a wait time, but not a count, we want to 374 * go on ad infinitum. This can be redundant if the user uses the 375 * traditional method of specifying the wait, since in that case we 376 * already set count = -1 above. Oh well. 377 */ 378 if ((wflag > 0) && (cflag == 0)) 379 count = -1; 380 381 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 382 383 if (kd == 0) 384 errx(1, "kvm_openfiles: %s", errbuf); 385 386 if (kvm_nlist(kd, namelist) == -1) 387 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 388 389 (void)nlread(X_HZ, hz); 390 (void)nlread(X_STATHZ, stathz); 391 if (stathz) 392 hz = stathz; 393 394 /* 395 * If the user stops the program (control-Z) and then resumes it, 396 * print out the header again. 397 */ 398 (void)signal(SIGCONT, phdr); 399 400 for (headercount = 1;;) { 401 struct devinfo *tmp_dinfo; 402 long tmp; 403 double etime; 404 405 if (!--headercount) { 406 phdr(0); 407 headercount = 20; 408 } 409 (void)kvm_read(kd, namelist[X_TK_NIN].n_value, 410 &cur.tk_nin, sizeof(cur.tk_nin)); 411 (void)kvm_read(kd, namelist[X_TK_NOUT].n_value, 412 &cur.tk_nout, sizeof(cur.tk_nout)); 413 (void)kvm_read(kd, namelist[X_CP_TIME].n_value, 414 cur.cp_time, sizeof(cur.cp_time)); 415 416 tmp_dinfo = last.dinfo; 417 last.dinfo = cur.dinfo; 418 cur.dinfo = tmp_dinfo; 419 420 last.busy_time = cur.busy_time; 421 422 /* 423 * Here what we want to do is refresh our device stats. 424 * getdevs() returns 1 when the device list has changed. 425 * If the device list has changed, we want to go through 426 * the selection process again, in case a device that we 427 * were previously displaying has gone away. 428 */ 429 switch (getdevs(&cur)) { 430 case -1: 431 errx(1, "%s", devstat_errbuf); 432 break; 433 case 1: { 434 int retval; 435 436 num_devices = cur.dinfo->numdevs; 437 generation = cur.dinfo->generation; 438 retval = selectdevs(&dev_select, &num_selected, 439 &num_selections, &select_generation, 440 generation, cur.dinfo->devices, 441 num_devices, matches, num_matches, 442 specified_devices, 443 num_devices_specified, 444 select_mode, maxshowdevs, hflag); 445 switch(retval) { 446 case -1: 447 errx(1, "%s", devstat_errbuf); 448 break; 449 case 1: 450 phdr(0); 451 headercount = 20; 452 break; 453 default: 454 break; 455 } 456 break; 457 } 458 default: 459 break; 460 } 461 462 /* 463 * We only want to re-select devices if we're in 'top' 464 * mode. This is the only mode where the devices selected 465 * could actually change. 466 */ 467 if (hflag > 0) { 468 int retval; 469 retval = selectdevs(&dev_select, &num_selected, 470 &num_selections, &select_generation, 471 generation, cur.dinfo->devices, 472 num_devices, matches, num_matches, 473 specified_devices, 474 num_devices_specified, 475 select_mode, maxshowdevs, hflag); 476 switch(retval) { 477 case -1: 478 errx(1,"%s", devstat_errbuf); 479 break; 480 case 1: 481 phdr(0); 482 headercount = 20; 483 break; 484 default: 485 break; 486 } 487 } 488 489 tmp = cur.tk_nin; 490 cur.tk_nin -= last.tk_nin; 491 last.tk_nin = tmp; 492 tmp = cur.tk_nout; 493 cur.tk_nout -= last.tk_nout; 494 last.tk_nout = tmp; 495 496 etime = 0.0; 497 498#define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp 499 500 for (i = 0; i < CPUSTATES; i++) { 501 X(cp_time); 502 etime += cur.cp_time[i]; 503 } 504 if (etime == 0.0) 505 etime = 1.0; 506 etime /= (float)hz; 507 if ((dflag == 0) || (Tflag > 0)) 508 printf("%4.0f%5.0f", cur.tk_nin / etime, 509 cur.tk_nout/etime); 510 devstats(hflag); 511 if ((dflag == 0) || (Cflag > 0)) 512 cpustats(); 513 printf("\n"); 514 fflush(stdout); 515 516 if (count >= 0 && --count <= 0) 517 break; 518 519 sleep(waittime); 520 } 521 522 exit(0); 523} 524 525static void 526phdr(int signo) 527{ 528 register int i; 529 int printed; 530 531 if ((dflag == 0) || (Tflag > 0)) 532 (void)printf(" tty"); 533 for (i = 0, printed=0;(i < num_devices) && (printed < maxshowdevs);i++){ 534 int di; 535 if ((dev_select[i].selected != 0) 536 && (dev_select[i].selected <= maxshowdevs)) { 537 di = dev_select[i].position; 538 if (oflag > 0) 539 (void)printf("%12.6s%d ", 540 cur.dinfo->devices[di].device_name, 541 cur.dinfo->devices[di].unit_number); 542 else 543 printf("%15.6s%d ", 544 cur.dinfo->devices[di].device_name, 545 cur.dinfo->devices[di].unit_number); 546 printed++; 547 } 548 } 549 if ((dflag == 0) || (Cflag > 0)) 550 (void)printf(" cpu\n"); 551 else 552 (void)printf("\n"); 553 554 if ((dflag == 0) || (Tflag > 0)) 555 (void)printf(" tin tout"); 556 557 for (i=0, printed = 0;(i < num_devices) && (printed < maxshowdevs);i++){ 558 if ((dev_select[i].selected != 0) 559 && (dev_select[i].selected <= maxshowdevs)) { 560 if (oflag > 0) { 561 if (Iflag == 0) 562 (void)printf(" sps tps msps "); 563 else 564 (void)printf(" blk xfr msps "); 565 } else { 566 if (Iflag == 0) 567 printf(" KB/t tps MB/s "); 568 else 569 printf(" KB/t xfrs MB "); 570 } 571 printed++; 572 } 573 } 574 if ((dflag == 0) || (Cflag > 0)) 575 (void)printf(" us ni sy in id\n"); 576 else 577 printf("\n"); 578 579} 580 581static void 582devstats(int perf_select) 583{ 584 register int dn; 585 long double transfers_per_second; 586 long double kb_per_transfer, mb_per_second; 587 u_int64_t total_bytes, total_transfers, total_blocks; 588 long double busy_seconds; 589 long double total_mb; 590 long double blocks_per_second, ms_per_transaction; 591 592 /* 593 * Calculate elapsed time up front, since it's the same for all 594 * devices. 595 */ 596 busy_seconds = compute_etime(cur.busy_time, last.busy_time); 597 598 for (dn = 0; dn < num_devices; dn++) { 599 int di; 600 601 if (((perf_select == 0) && (dev_select[dn].selected == 0)) 602 || (dev_select[dn].selected > maxshowdevs)) 603 continue; 604 605 di = dev_select[dn].position; 606 607 if (compute_stats(&cur.dinfo->devices[di], 608 &last.dinfo->devices[di], busy_seconds, 609 &total_bytes, &total_transfers, 610 &total_blocks, &kb_per_transfer, 611 &transfers_per_second, &mb_per_second, 612 &blocks_per_second, &ms_per_transaction)!= 0) 613 errx(1, "%s", devstat_errbuf); 614 615 if (perf_select != 0) { 616 dev_select[dn].bytes = total_bytes; 617 if ((dev_select[dn].selected == 0) 618 || (dev_select[dn].selected > maxshowdevs)) 619 continue; 620 } 621 622 if (Kflag) { 623 int block_size = cur.dinfo->devices[di].block_size; 624 total_blocks = total_blocks * (block_size ? 625 block_size : 512) / 1024; 626 } 627 628 if (oflag > 0) { 629 int msdig = (ms_per_transaction < 100.0) ? 1 : 0; 630 631 if (Iflag == 0) 632 printf("%4.0Lf%4.0Lf%5.*Lf ", 633 blocks_per_second, 634 transfers_per_second, 635 msdig, 636 ms_per_transaction); 637 else 638 printf("%4.1qu%4.1qu%5.*Lf ", 639 total_blocks, 640 total_transfers, 641 msdig, 642 ms_per_transaction); 643 } else { 644 if (Iflag == 0) 645 printf(" %5.2Lf %3.0Lf %5.2Lf ", 646 kb_per_transfer, 647 transfers_per_second, 648 mb_per_second); 649 else { 650 total_mb = total_bytes; 651 total_mb /= 1024 * 1024; 652 653 printf(" %5.2Lf %3.1qu %5.2Lf ", 654 kb_per_transfer, 655 total_transfers, 656 total_mb); 657 } 658 } 659 } 660} 661 662static void 663cpustats(void) 664{ 665 register int state; 666 double time; 667 668 time = 0.0; 669 670 for (state = 0; state < CPUSTATES; ++state) 671 time += cur.cp_time[state]; 672 for (state = 0; state < CPUSTATES; ++state) 673 printf("%3.0f", 674 100. * cur.cp_time[state] / (time ? time : 1)); 675} 676