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