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