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 141 /* local function declarations */ 142 static void usage(void); 143 static void needhdr(int signo); 144 static void phdr(void); 145 static void devstats(int perf_select, long double etime, int havelast); 146 static void cpustats(void); 147 static int readvar(kvm_t *kd, const char *name, int nlid, void *ptr, 148 size_t len); 149 150 static void 151 usage(void) 152 { 153 /* 154 * We also support the following 'traditional' syntax: 155 * iostat [drives] [wait [count]] 156 * This isn't mentioned in the man page, or the usage statement, 157 * but it is supported. 158 */ 159 fprintf(stderr, "usage: iostat [-CdhIKoT?] [-c count] [-M core]" 160 " [-n devs] [-N system]\n" 161 "\t [-t type,if,pass] [-w wait] [drives]\n"); 162 } 163 164 int 165 main(int argc, char **argv) 166 { 167 int c; 168 register int 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:?")) != -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 default: 242 usage(); 243 exit(1); 244 break; 245 } 246 } 247 248 argc -= optind; 249 argv += optind; 250 251 if (nlistf != NULL || memf != NULL) { 252 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 253 254 if (kd == NULL) 255 errx(1, "kvm_openfiles: %s", errbuf); 256 257 if (kvm_nlist(kd, namelist) == -1) 258 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 259 } 260 261 /* 262 * Make sure that the userland devstat version matches the kernel 263 * devstat version. If not, exit and print a message informing 264 * the user of his mistake. 265 */ 266 if (devstat_checkversion(kd) < 0) 267 errx(1, "%s", devstat_errbuf); 268 269 /* 270 * Make sure Tflag and/or Cflag are set if dflag == 0. If dflag is 271 * greater than 0, they may be 0 or non-zero. 272 */ 273 if (dflag == 0) { 274 Cflag = 1; 275 Tflag = 1; 276 } 277 278 /* 279 * Figure out how many devices we should display. 280 */ 281 if (nflag == 0) { 282 if (oflag > 0) { 283 if ((dflag > 0) && (Cflag == 0) && (Tflag == 0)) 284 maxshowdevs = 5; 285 else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0)) 286 maxshowdevs = 5; 287 else 288 maxshowdevs = 4; 289 } else { 290 if ((dflag > 0) && (Cflag == 0)) 291 maxshowdevs = 4; 292 else 293 maxshowdevs = 3; 294 } 295 } 296 297 /* find out how many devices we have */ 298 if ((num_devices = devstat_getnumdevs(kd)) < 0) 299 err(1, "can't get number of devices"); 300 301 cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 302 if (cur.dinfo == NULL) 303 err(1, "malloc failed"); 304 305 last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 306 if (last.dinfo == NULL) 307 err(1, "malloc failed"); 308 309 bzero(cur.dinfo, sizeof(struct devinfo)); 310 bzero(last.dinfo, sizeof(struct devinfo)); 311 312 /* 313 * Grab all the devices. We don't look to see if the list has 314 * changed here, since it almost certainly has. We only look for 315 * errors. 316 */ 317 if (devstat_getdevs(kd, &cur) == -1) 318 errx(1, "%s", devstat_errbuf); 319 320 num_devices = cur.dinfo->numdevs; 321 generation = cur.dinfo->generation; 322 323 /* 324 * If the user specified any devices on the command line, see if 325 * they are in the list of devices we have now. 326 */ 327 specified_devices = (char **)malloc(sizeof(char *)); 328 if (specified_devices == NULL) 329 err(1, "malloc failed"); 330 331 for (num_devices_specified = 0; *argv; ++argv) { 332 if (isdigit(**argv)) 333 break; 334 num_devices_specified++; 335 specified_devices = (char **)realloc(specified_devices, 336 sizeof(char *) * 337 num_devices_specified); 338 if (specified_devices == NULL) 339 err(1, "realloc failed"); 340 341 specified_devices[num_devices_specified - 1] = *argv; 342 343 } 344 if (nflag == 0 && maxshowdevs < num_devices_specified) 345 maxshowdevs = num_devices_specified; 346 347 dev_select = NULL; 348 349 if ((num_devices_specified == 0) && (num_matches == 0)) 350 select_mode = DS_SELECT_ADD; 351 else 352 select_mode = DS_SELECT_ONLY; 353 354 /* 355 * At this point, selectdevs will almost surely indicate that the 356 * device list has changed, so we don't look for return values of 0 357 * or 1. If we get back -1, though, there is an error. 358 */ 359 if (devstat_selectdevs(&dev_select, &num_selected, 360 &num_selections, &select_generation, generation, 361 cur.dinfo->devices, num_devices, matches, 362 num_matches, specified_devices, 363 num_devices_specified, select_mode, maxshowdevs, 364 hflag) == -1) 365 errx(1, "%s", devstat_errbuf); 366 367 /* 368 * Look for the traditional wait time and count arguments. 369 */ 370 if (*argv) { 371 waittime = atoi(*argv); 372 373 /* Let the user know he goofed, but keep going anyway */ 374 if (wflag != 0) 375 warnx("discarding previous wait interval, using" 376 " %d instead", waittime); 377 wflag++; 378 379 if (*++argv) { 380 count = atoi(*argv); 381 if (cflag != 0) 382 warnx("discarding previous count, using %d" 383 " instead", count); 384 cflag++; 385 } else 386 count = -1; 387 } 388 389 /* 390 * If the user specified a count, but not an interval, we default 391 * to an interval of 1 second. 392 */ 393 if ((wflag == 0) && (cflag > 0)) 394 waittime = 1; 395 396 /* 397 * If the user specified a wait time, but not a count, we want to 398 * go on ad infinitum. This can be redundant if the user uses the 399 * traditional method of specifying the wait, since in that case we 400 * already set count = -1 above. Oh well. 401 */ 402 if ((wflag > 0) && (cflag == 0)) 403 count = -1; 404 405 bzero(&cur.cp_time, sizeof(cur.cp_time)); 406 cur.tk_nout = 0; 407 cur.tk_nin = 0; 408 409 /* 410 * Set the busy time to the system boot time, so the stats are 411 * calculated since system boot. 412 */ 413 if (readvar(kd, "kern.boottime", X_BOOTTIME, &cur.busy_time, 414 sizeof(cur.busy_time)) != 0) 415 exit(1); 416 417 /* 418 * If the user stops the program (control-Z) and then resumes it, 419 * print out the header again. 420 */ 421 (void)signal(SIGCONT, needhdr); 422 423 for (headercount = 1;;) { 424 struct devinfo *tmp_dinfo; 425 long tmp; 426 long double etime; 427 428 if (Tflag > 0) { 429 if ((readvar(kd, "kern.tty_nin", X_TK_NIN, &cur.tk_nin, 430 sizeof(cur.tk_nin)) != 0) 431 || (readvar(kd, "kern.tty_nout", X_TK_NOUT, 432 &cur.tk_nout, sizeof(cur.tk_nout))!= 0)) { 433 Tflag = 0; 434 warnx("disabling TTY statistics"); 435 } 436 } 437 438 if (Cflag > 0) { 439 if (readvar(kd, "kern.cp_time", X_CP_TIME, 440 &cur.cp_time, sizeof(cur.cp_time)) != 0) { 441 Cflag = 0; 442 warnx("disabling CPU time statistics"); 443 } 444 } 445 446 if (!--headercount) { 447 phdr(); 448 headercount = 20; 449 } 450 451 tmp_dinfo = last.dinfo; 452 last.dinfo = cur.dinfo; 453 cur.dinfo = tmp_dinfo; 454 455 last.busy_time = cur.busy_time; 456 457 /* 458 * Here what we want to do is refresh our device stats. 459 * devstat_getdevs() returns 1 when the device list has changed. 460 * If the device list has changed, we want to go through 461 * the selection process again, in case a device that we 462 * were previously displaying has gone away. 463 */ 464 switch (devstat_getdevs(kd, &cur)) { 465 case -1: 466 errx(1, "%s", devstat_errbuf); 467 break; 468 case 1: { 469 int retval; 470 471 num_devices = cur.dinfo->numdevs; 472 generation = cur.dinfo->generation; 473 retval = devstat_selectdevs(&dev_select, &num_selected, 474 &num_selections, 475 &select_generation, 476 generation, 477 cur.dinfo->devices, 478 num_devices, matches, 479 num_matches, 480 specified_devices, 481 num_devices_specified, 482 select_mode, maxshowdevs, 483 hflag); 484 switch(retval) { 485 case -1: 486 errx(1, "%s", devstat_errbuf); 487 break; 488 case 1: 489 phdr(); 490 headercount = 20; 491 break; 492 default: 493 break; 494 } 495 break; 496 } 497 default: 498 break; 499 } 500 501 /* 502 * We only want to re-select devices if we're in 'top' 503 * mode. This is the only mode where the devices selected 504 * could actually change. 505 */ 506 if (hflag > 0) { 507 int retval; 508 retval = devstat_selectdevs(&dev_select, &num_selected, 509 &num_selections, 510 &select_generation, 511 generation, 512 cur.dinfo->devices, 513 num_devices, matches, 514 num_matches, 515 specified_devices, 516 num_devices_specified, 517 select_mode, maxshowdevs, 518 hflag); 519 switch(retval) { 520 case -1: 521 errx(1,"%s", devstat_errbuf); 522 break; 523 case 1: 524 phdr(); 525 headercount = 20; 526 break; 527 default: 528 break; 529 } 530 } 531 532 if (Tflag > 0) { 533 tmp = cur.tk_nin; 534 cur.tk_nin -= last.tk_nin; 535 last.tk_nin = tmp; 536 tmp = cur.tk_nout; 537 cur.tk_nout -= last.tk_nout; 538 last.tk_nout = tmp; 539 } 540 541 etime = devstat_compute_etime(cur.busy_time, last.busy_time); 542 543 if (etime == 0.0) 544 etime = 1.0; 545 546 for (i = 0; i < CPUSTATES; i++) { 547 tmp = cur.cp_time[i]; 548 cur.cp_time[i] -= last.cp_time[i]; 549 last.cp_time[i] = tmp; 550 } 551 552 if (Tflag > 0) 553 printf("%4.0Lf%5.0Lf", cur.tk_nin / etime, 554 cur.tk_nout/etime); 555 556 devstats(hflag, etime, havelast); 557 558 if (Cflag > 0) 559 cpustats(); 560 561 printf("\n"); 562 fflush(stdout); 563 564 if (count >= 0 && --count <= 0) 565 break; 566 567 sleep(waittime); 568 havelast = 1; 569 } 570 571 exit(0); 572 } 573 574 /* 575 * Force a header to be prepended to the next output. 576 */ 577 void 578 needhdr(int signo) 579 { 580 581 headercount = 1; 582 } 583 584 static void 585 phdr(void) 586 { 587 register int i; 588 int printed; 589 590 if (Tflag > 0) 591 (void)printf(" tty"); 592 for (i = 0, printed=0;(i < num_devices) && (printed < maxshowdevs);i++){ 593 int di; 594 if ((dev_select[i].selected != 0) 595 && (dev_select[i].selected <= maxshowdevs)) { 596 di = dev_select[i].position; 597 if (oflag > 0) 598 (void)printf("%12.6s%d ", 599 cur.dinfo->devices[di].device_name, 600 cur.dinfo->devices[di].unit_number); 601 else 602 printf("%15.6s%d ", 603 cur.dinfo->devices[di].device_name, 604 cur.dinfo->devices[di].unit_number); 605 printed++; 606 } 607 } 608 if (Cflag > 0) 609 (void)printf(" cpu\n"); 610 else 611 (void)printf("\n"); 612 613 if (Tflag > 0) 614 (void)printf(" tin tout"); 615 616 for (i=0, printed = 0;(i < num_devices) && (printed < maxshowdevs);i++){ 617 if ((dev_select[i].selected != 0) 618 && (dev_select[i].selected <= maxshowdevs)) { 619 if (oflag > 0) { 620 if (Iflag == 0) 621 (void)printf(" sps tps msps "); 622 else 623 (void)printf(" blk xfr msps "); 624 } else { 625 if (Iflag == 0) 626 printf(" KB/t tps MB/s "); 627 else 628 printf(" KB/t xfrs MB "); 629 } 630 printed++; 631 } 632 } 633 if (Cflag > 0) 634 (void)printf(" us ni sy in id\n"); 635 else 636 printf("\n"); 637 638 } 639 640 static void 641 devstats(int perf_select, long double etime, int havelast) 642 { 643 register int dn; 644 long double transfers_per_second; 645 long double kb_per_transfer, mb_per_second; 646 u_int64_t total_bytes, total_transfers, total_blocks; 647 long double total_mb; 648 long double blocks_per_second, ms_per_transaction; 649 650 for (dn = 0; dn < num_devices; dn++) { 651 int di; 652 653 if (((perf_select == 0) && (dev_select[dn].selected == 0)) 654 || (dev_select[dn].selected > maxshowdevs)) 655 continue; 656 657 di = dev_select[dn].position; 658 659 if (devstat_compute_statistics(&cur.dinfo->devices[di], 660 havelast ? &last.dinfo->devices[di] : NULL, etime, 661 DSM_TOTAL_BYTES, &total_bytes, 662 DSM_TOTAL_TRANSFERS, &total_transfers, 663 DSM_TOTAL_BLOCKS, &total_blocks, 664 DSM_KB_PER_TRANSFER, &kb_per_transfer, 665 DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 666 DSM_MB_PER_SECOND, &mb_per_second, 667 DSM_BLOCKS_PER_SECOND, &blocks_per_second, 668 DSM_MS_PER_TRANSACTION, &ms_per_transaction, 669 DSM_NONE) != 0) 670 errx(1, "%s", devstat_errbuf); 671 672 if (perf_select != 0) { 673 dev_select[dn].bytes = total_bytes; 674 if ((dev_select[dn].selected == 0) 675 || (dev_select[dn].selected > maxshowdevs)) 676 continue; 677 } 678 679 if (Kflag) { 680 int block_size = cur.dinfo->devices[di].block_size; 681 total_blocks = total_blocks * (block_size ? 682 block_size : 512) / 1024; 683 } 684 685 if (oflag > 0) { 686 int msdig = (ms_per_transaction < 100.0) ? 1 : 0; 687 688 if (Iflag == 0) 689 printf("%4.0Lf%4.0Lf%5.*Lf ", 690 blocks_per_second, 691 transfers_per_second, 692 msdig, 693 ms_per_transaction); 694 else 695 printf("%4.1qu%4.1qu%5.*Lf ", 696 total_blocks, 697 total_transfers, 698 msdig, 699 ms_per_transaction); 700 } else { 701 if (Iflag == 0) 702 printf(" %5.2Lf %3.0Lf %5.2Lf ", 703 kb_per_transfer, 704 transfers_per_second, 705 mb_per_second); 706 else { 707 total_mb = total_bytes; 708 total_mb /= 1024 * 1024; 709 710 printf(" %5.2Lf %3.1qu %5.2Lf ", 711 kb_per_transfer, 712 total_transfers, 713 total_mb); 714 } 715 } 716 } 717 } 718 719 static void 720 cpustats(void) 721 { 722 register int state; 723 double time; 724 725 time = 0.0; 726 727 for (state = 0; state < CPUSTATES; ++state) 728 time += cur.cp_time[state]; 729 for (state = 0; state < CPUSTATES; ++state) 730 printf(" %2.0f", 731 rint(100. * cur.cp_time[state] / (time ? time : 1))); 732 } 733 734 static int 735 readvar(kvm_t *kd, const char *name, int nlid, void *ptr, size_t len) 736 { 737 if (kd != NULL) { 738 ssize_t nbytes; 739 740 nbytes = kvm_read(kd, nlid, ptr, len); 741 742 if (nbytes == 0) { 743 warnx("kvm_read(%s): %s", name, kvm_geterr(kd)); 744 return (1); 745 } 746 if (nbytes != len) { 747 warnx("kvm_read(%s): expected %lu bytes, got %ld bytes", 748 name, (unsigned long)len, (long)nbytes); 749 return (1); 750 } 751 } else { 752 size_t nlen = len; 753 754 if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 755 warn("sysctl(%s...) failed", name); 756 return (1); 757 } 758 if (nlen != len) { 759 warnx("sysctl(%s...): expected %lu, got %lu", name, 760 (unsigned long)len, (unsigned long)nlen); 761 return (1); 762 } 763 } 764 return (0); 765 } 766