iostat.c revision 82723
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 82723 2001-09-01 07:40:19Z kris $ 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 <signal.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; 138int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0; 139volatile sig_atomic_t phdr_flag = 0; 140 141/* local function declarations */ 142static void usage(void); 143static void phdr(int signo); 144static void do_phdr(); 145static void devstats(int perf_select, long double etime, int havelast); 146static void cpustats(void); 147static int readvar(kvm_t *kd, const char *name, int nlid, void *ptr, 148 size_t len); 149 150static void 151usage(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 164int 165main(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 int headercount; 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:?")) != -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 default: 243 usage(); 244 exit(1); 245 break; 246 } 247 } 248 249 argc -= optind; 250 argv += optind; 251 252 if (nlistf != NULL || memf != NULL) { 253 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 254 255 if (kd == NULL) 256 errx(1, "kvm_openfiles: %s", errbuf); 257 258 if (kvm_nlist(kd, namelist) == -1) 259 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 260 } 261 262 /* 263 * Make sure that the userland devstat version matches the kernel 264 * devstat version. If not, exit and print a message informing 265 * the user of his mistake. 266 */ 267 if (devstat_checkversion(kd) < 0) 268 errx(1, "%s", devstat_errbuf); 269 270 /* 271 * Make sure Tflag and/or Cflag are set if dflag == 0. If dflag is 272 * greater than 0, they may be 0 or non-zero. 273 */ 274 if (dflag == 0) { 275 Cflag = 1; 276 Tflag = 1; 277 } 278 279 /* 280 * Figure out how many devices we should display. 281 */ 282 if (nflag == 0) { 283 if (oflag > 0) { 284 if ((dflag > 0) && (Cflag == 0) && (Tflag == 0)) 285 maxshowdevs = 5; 286 else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0)) 287 maxshowdevs = 5; 288 else 289 maxshowdevs = 4; 290 } else { 291 if ((dflag > 0) && (Cflag == 0)) 292 maxshowdevs = 4; 293 else 294 maxshowdevs = 3; 295 } 296 } 297 298 /* find out how many devices we have */ 299 if ((num_devices = devstat_getnumdevs(kd)) < 0) 300 err(1, "can't get number of devices"); 301 302 cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 303 if (cur.dinfo == NULL) 304 err(1, "malloc failed"); 305 306 last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 307 if (last.dinfo == NULL) 308 err(1, "malloc failed"); 309 310 bzero(cur.dinfo, sizeof(struct devinfo)); 311 bzero(last.dinfo, sizeof(struct devinfo)); 312 313 /* 314 * Grab all the devices. We don't look to see if the list has 315 * changed here, since it almost certainly has. We only look for 316 * errors. 317 */ 318 if (devstat_getdevs(kd, &cur) == -1) 319 errx(1, "%s", devstat_errbuf); 320 321 num_devices = cur.dinfo->numdevs; 322 generation = cur.dinfo->generation; 323 324 /* 325 * If the user specified any devices on the command line, see if 326 * they are in the list of devices we have now. 327 */ 328 specified_devices = (char **)malloc(sizeof(char *)); 329 if (specified_devices == NULL) 330 err(1, "malloc failed"); 331 332 for (num_devices_specified = 0; *argv; ++argv) { 333 if (isdigit(**argv)) 334 break; 335 num_devices_specified++; 336 specified_devices = (char **)realloc(specified_devices, 337 sizeof(char *) * 338 num_devices_specified); 339 if (specified_devices == NULL) 340 err(1, "realloc failed"); 341 342 specified_devices[num_devices_specified - 1] = *argv; 343 344 } 345 if (nflag == 0 && maxshowdevs < num_devices_specified) 346 maxshowdevs = num_devices_specified; 347 348 dev_select = NULL; 349 350 if ((num_devices_specified == 0) && (num_matches == 0)) 351 select_mode = DS_SELECT_ADD; 352 else 353 select_mode = DS_SELECT_ONLY; 354 355 /* 356 * At this point, selectdevs will almost surely indicate that the 357 * device list has changed, so we don't look for return values of 0 358 * or 1. If we get back -1, though, there is an error. 359 */ 360 if (devstat_selectdevs(&dev_select, &num_selected, 361 &num_selections, &select_generation, generation, 362 cur.dinfo->devices, num_devices, matches, 363 num_matches, specified_devices, 364 num_devices_specified, select_mode, maxshowdevs, 365 hflag) == -1) 366 errx(1, "%s", devstat_errbuf); 367 368 /* 369 * Look for the traditional wait time and count arguments. 370 */ 371 if (*argv) { 372 waittime = atoi(*argv); 373 374 /* Let the user know he goofed, but keep going anyway */ 375 if (wflag != 0) 376 warnx("discarding previous wait interval, using" 377 " %d instead", waittime); 378 wflag++; 379 380 if (*++argv) { 381 count = atoi(*argv); 382 if (cflag != 0) 383 warnx("discarding previous count, using %d" 384 " instead", count); 385 cflag++; 386 } else 387 count = -1; 388 } 389 390 /* 391 * If the user specified a count, but not an interval, we default 392 * to an interval of 1 second. 393 */ 394 if ((wflag == 0) && (cflag > 0)) 395 waittime = 1; 396 397 /* 398 * If the user specified a wait time, but not a count, we want to 399 * go on ad infinitum. This can be redundant if the user uses the 400 * traditional method of specifying the wait, since in that case we 401 * already set count = -1 above. Oh well. 402 */ 403 if ((wflag > 0) && (cflag == 0)) 404 count = -1; 405 406 bzero(&cur.cp_time, sizeof(cur.cp_time)); 407 cur.tk_nout = 0; 408 cur.tk_nin = 0; 409 410 /* 411 * Set the busy time to the system boot time, so the stats are 412 * calculated since system boot. 413 */ 414 if (readvar(kd, "kern.boottime", X_BOOTTIME, &cur.busy_time, 415 sizeof(cur.busy_time)) != 0) 416 exit(1); 417 418 /* 419 * If the user stops the program (control-Z) and then resumes it, 420 * print out the header again. 421 */ 422 (void)signal(SIGCONT, phdr); 423 424 for (headercount = 1;;) { 425 struct devinfo *tmp_dinfo; 426 long tmp; 427 long double etime; 428 429 if (Tflag > 0) { 430 if ((readvar(kd, "kern.tty_nin", X_TK_NIN, &cur.tk_nin, 431 sizeof(cur.tk_nin)) != 0) 432 || (readvar(kd, "kern.tty_nout", X_TK_NOUT, 433 &cur.tk_nout, sizeof(cur.tk_nout))!= 0)) { 434 Tflag = 0; 435 warnx("disabling TTY statistics"); 436 } 437 } 438 439 if (phdr_flag) { 440 phdr_flag = 0; 441 do_phdr(); 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 do_phdr(); 454 headercount = 20; 455 } 456 457 tmp_dinfo = last.dinfo; 458 last.dinfo = cur.dinfo; 459 cur.dinfo = tmp_dinfo; 460 461 last.busy_time = cur.busy_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 do_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 do_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 = devstat_compute_etime(cur.busy_time, last.busy_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 (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 (Cflag > 0) 565 cpustats(); 566 567 printf("\n"); 568 fflush(stdout); 569 570 if (count >= 0 && --count <= 0) 571 break; 572 573 sleep(waittime); 574 havelast = 1; 575 } 576 577 exit(0); 578} 579 580static void 581phdr(int signo) 582{ 583 584 phdr_flag = 1; 585} 586 587static void 588do_phdr() 589{ 590 register int i; 591 int printed; 592 593 if (Tflag > 0) 594 (void)printf(" tty"); 595 for (i = 0, printed=0;(i < num_devices) && (printed < maxshowdevs);i++){ 596 int di; 597 if ((dev_select[i].selected != 0) 598 && (dev_select[i].selected <= maxshowdevs)) { 599 di = dev_select[i].position; 600 if (oflag > 0) 601 (void)printf("%12.6s%d ", 602 cur.dinfo->devices[di].device_name, 603 cur.dinfo->devices[di].unit_number); 604 else 605 printf("%15.6s%d ", 606 cur.dinfo->devices[di].device_name, 607 cur.dinfo->devices[di].unit_number); 608 printed++; 609 } 610 } 611 if (Cflag > 0) 612 (void)printf(" cpu\n"); 613 else 614 (void)printf("\n"); 615 616 if (Tflag > 0) 617 (void)printf(" tin tout"); 618 619 for (i=0, printed = 0;(i < num_devices) && (printed < maxshowdevs);i++){ 620 if ((dev_select[i].selected != 0) 621 && (dev_select[i].selected <= maxshowdevs)) { 622 if (oflag > 0) { 623 if (Iflag == 0) 624 (void)printf(" sps tps msps "); 625 else 626 (void)printf(" blk xfr msps "); 627 } else { 628 if (Iflag == 0) 629 printf(" KB/t tps MB/s "); 630 else 631 printf(" KB/t xfrs MB "); 632 } 633 printed++; 634 } 635 } 636 if (Cflag > 0) 637 (void)printf(" us ni sy in id\n"); 638 else 639 printf("\n"); 640} 641 642static void 643devstats(int perf_select, long double etime, int havelast) 644{ 645 register int dn; 646 long double transfers_per_second; 647 long double kb_per_transfer, mb_per_second; 648 u_int64_t total_bytes, total_transfers, total_blocks; 649 long double total_mb; 650 long double blocks_per_second, ms_per_transaction; 651 652 for (dn = 0; dn < num_devices; dn++) { 653 int di; 654 655 if (((perf_select == 0) && (dev_select[dn].selected == 0)) 656 || (dev_select[dn].selected > maxshowdevs)) 657 continue; 658 659 di = dev_select[dn].position; 660 661 if (devstat_compute_statistics(&cur.dinfo->devices[di], 662 havelast ? &last.dinfo->devices[di] : NULL, etime, 663 DSM_TOTAL_BYTES, &total_bytes, 664 DSM_TOTAL_TRANSFERS, &total_transfers, 665 DSM_TOTAL_BLOCKS, &total_blocks, 666 DSM_KB_PER_TRANSFER, &kb_per_transfer, 667 DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 668 DSM_MB_PER_SECOND, &mb_per_second, 669 DSM_BLOCKS_PER_SECOND, &blocks_per_second, 670 DSM_MS_PER_TRANSACTION, &ms_per_transaction, 671 DSM_NONE) != 0) 672 errx(1, "%s", devstat_errbuf); 673 674 if (perf_select != 0) { 675 dev_select[dn].bytes = total_bytes; 676 if ((dev_select[dn].selected == 0) 677 || (dev_select[dn].selected > maxshowdevs)) 678 continue; 679 } 680 681 if (Kflag) { 682 int block_size = cur.dinfo->devices[di].block_size; 683 total_blocks = total_blocks * (block_size ? 684 block_size : 512) / 1024; 685 } 686 687 if (oflag > 0) { 688 int msdig = (ms_per_transaction < 100.0) ? 1 : 0; 689 690 if (Iflag == 0) 691 printf("%4.0Lf%4.0Lf%5.*Lf ", 692 blocks_per_second, 693 transfers_per_second, 694 msdig, 695 ms_per_transaction); 696 else 697 printf("%4.1qu%4.1qu%5.*Lf ", 698 total_blocks, 699 total_transfers, 700 msdig, 701 ms_per_transaction); 702 } else { 703 if (Iflag == 0) 704 printf(" %5.2Lf %3.0Lf %5.2Lf ", 705 kb_per_transfer, 706 transfers_per_second, 707 mb_per_second); 708 else { 709 total_mb = total_bytes; 710 total_mb /= 1024 * 1024; 711 712 printf(" %5.2Lf %3.1qu %5.2Lf ", 713 kb_per_transfer, 714 total_transfers, 715 total_mb); 716 } 717 } 718 } 719} 720 721static void 722cpustats(void) 723{ 724 register int state; 725 double time; 726 727 time = 0.0; 728 729 for (state = 0; state < CPUSTATES; ++state) 730 time += cur.cp_time[state]; 731 for (state = 0; state < CPUSTATES; ++state) 732 printf("%3.0f", 733 rint(100. * cur.cp_time[state] / (time ? time : 1))); 734} 735 736static int 737readvar(kvm_t *kd, const char *name, int nlid, void *ptr, size_t len) 738{ 739 if (kd != NULL) { 740 ssize_t nbytes; 741 742 nbytes = kvm_read(kd, nlid, ptr, len); 743 744 if (nbytes == 0) { 745 warnx("kvm_read(%s): %s", name, kvm_geterr(kd)); 746 return (1); 747 } 748 if (nbytes != len) { 749 warnx("kvm_read(%s): expected %lu bytes, got %ld bytes", 750 name, (unsigned long)len, (long)nbytes); 751 return (1); 752 } 753 } else { 754 size_t nlen = len; 755 756 if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 757 warn("sysctl(%s...) failed", name); 758 return (1); 759 } 760 if (nlen != len) { 761 warnx("sysctl(%s...): expected %lu, got %lu", name, 762 (unsigned long)len, (unsigned long)nlen); 763 return (1); 764 } 765 } 766 return (0); 767} 768