1 /* 2 * Copyright (c) 1997, 1998 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: src/usr.sbin/iostat/iostat.c,v 1.17.2.2 2001/07/19 04:15:42 kris Exp $ 29 * $DragonFly: src/usr.sbin/iostat/iostat.c,v 1.7 2005/09/01 19:08:38 swildner Exp $ 30 */ 31 /* 32 * Parts of this program are derived from the original FreeBSD iostat 33 * program: 34 */ 35 /*- 36 * Copyright (c) 1986, 1991, 1993 37 * The Regents of the University of California. All rights reserved. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. All advertising materials mentioning features or use of this software 48 * must display the following acknowledgement: 49 * This product includes software developed by the University of 50 * California, Berkeley and its contributors. 51 * 4. Neither the name of the University nor the names of its contributors 52 * may be used to endorse or promote products derived from this software 53 * without specific prior written permission. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65 * SUCH DAMAGE. 66 */ 67 /* 68 * Ideas for the new iostat statistics output modes taken from the NetBSD 69 * version of iostat: 70 */ 71 /* 72 * Copyright (c) 1996 John M. Vinopal 73 * All rights reserved. 74 * 75 * Redistribution and use in source and binary forms, with or without 76 * modification, are permitted provided that the following conditions 77 * are met: 78 * 1. Redistributions of source code must retain the above copyright 79 * notice, this list of conditions and the following disclaimer. 80 * 2. Redistributions in binary form must reproduce the above copyright 81 * notice, this list of conditions and the following disclaimer in the 82 * documentation and/or other materials provided with the distribution. 83 * 3. All advertising materials mentioning features or use of this software 84 * must display the following acknowledgement: 85 * This product includes software developed for the NetBSD Project 86 * by John M. Vinopal. 87 * 4. The name of the author may not be used to endorse or promote products 88 * derived from this software without specific prior written permission. 89 * 90 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 91 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 92 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 93 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 94 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 95 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 96 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 97 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 98 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 99 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 100 * SUCH DAMAGE. 101 */ 102 103 #include <sys/param.h> 104 #include <sys/errno.h> 105 106 #include <err.h> 107 #include <ctype.h> 108 #include <fcntl.h> 109 #include <kinfo.h> 110 #include <stdio.h> 111 #include <stdlib.h> 112 #include <string.h> 113 #include <unistd.h> 114 #include <limits.h> 115 #include <devstat.h> 116 117 struct statinfo cur, last; 118 uint64_t tk_nin, old_tk_nin, diff_tk_nin; 119 uint64_t tk_nout, old_tk_nout, diff_tk_nout; 120 struct kinfo_cputime cp_time, old_cp_time, diff_cp_time; 121 double cp_time_total; 122 int num_devices; 123 struct device_selection *dev_select; 124 int maxshowdevs; 125 int dflag = 0, Dflag=0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0; 126 127 /* local function declarations */ 128 static void usage(void); 129 static void phdr(int signo); 130 static void devstats(int perf_select); 131 static void cpustats(void); 132 133 static void 134 usage(void) 135 { 136 /* 137 * We also support the following 'traditional' syntax: 138 * iostat [drives] [wait [count]] 139 * This isn't mentioned in the man page, or the usage statement, 140 * but it is supported. 141 */ 142 fprintf(stderr, "usage: iostat [-CdhIKoT] [-c count]" 143 " [-n devs]\n" 144 "\t [-t type,if,pass] [-w wait] [drives]\n"); 145 } 146 147 int 148 main(int argc, char **argv) 149 { 150 int c; 151 int tflag = 0, hflag = 0, cflag = 0, wflag = 0, nflag = 0; 152 int count = 0, waittime = 0; 153 struct devstat_match *matches; 154 int num_matches = 0; 155 int hz; 156 int headercount; 157 long generation; 158 int num_devices_specified; 159 int num_selected, num_selections; 160 long select_generation; 161 char **specified_devices; 162 devstat_select_mode select_mode; 163 164 matches = NULL; 165 maxshowdevs = 3; 166 167 while ((c = getopt(argc, argv, "c:CdDhIKM:n:N:ot:Tw:")) != -1) { 168 switch(c) { 169 case 'c': 170 cflag++; 171 count = atoi(optarg); 172 if (count < 1) 173 errx(1, "count %d is < 1", count); 174 break; 175 case 'C': 176 Cflag++; 177 break; 178 case 'd': 179 dflag++; 180 break; 181 case 'D': 182 Dflag++; 183 break; 184 case 'h': 185 hflag++; 186 break; 187 case 'I': 188 Iflag++; 189 break; 190 case 'K': 191 Kflag++; 192 break; 193 case 'n': 194 nflag++; 195 maxshowdevs = atoi(optarg); 196 if (maxshowdevs < 0) 197 errx(1, "number of devices %d is < 0", 198 maxshowdevs); 199 break; 200 case 'o': 201 oflag++; 202 break; 203 case 't': 204 tflag++; 205 if (buildmatch(optarg, &matches, 206 &num_matches) != 0) 207 errx(1, "%s", devstat_errbuf); 208 break; 209 case 'T': 210 Tflag++; 211 break; 212 case 'w': 213 wflag++; 214 waittime = atoi(optarg); 215 if (waittime < 1) 216 errx(1, "wait time is < 1"); 217 break; 218 default: 219 usage(); 220 exit(1); 221 break; 222 } 223 } 224 225 argc -= optind; 226 argv += optind; 227 228 /* 229 * Make sure that the userland devstat version matches the kernel 230 * devstat version. If not, exit and print a message informing 231 * the user of his mistake. 232 */ 233 if (checkversion() < 0) 234 errx(1, "%s", devstat_errbuf); 235 236 /* 237 * Figure out how many devices we should display. 238 */ 239 if (nflag == 0) { 240 if (oflag > 0) { 241 if ((dflag > 0) && (Cflag == 0) && (Tflag == 0)) 242 maxshowdevs = 5; 243 else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0)) 244 maxshowdevs = 5; 245 else 246 maxshowdevs = 4; 247 } else { 248 if ((dflag > 0) && (Cflag == 0)) 249 maxshowdevs = 4; 250 else 251 maxshowdevs = 3; 252 } 253 } 254 255 /* find out how many devices we have */ 256 if ((num_devices = getnumdevs()) < 0) 257 err(1, "can't get number of devices"); 258 259 if ((cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo))) == 260 NULL) 261 err(1, "devinfo malloc failed"); 262 if ((last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo))) == 263 NULL) 264 err(1, "devinfo malloc failed"); 265 bzero(cur.dinfo, sizeof(struct devinfo)); 266 bzero(last.dinfo, sizeof(struct devinfo)); 267 268 /* 269 * Grab all the devices. We don't look to see if the list has 270 * changed here, since it almost certainly has. We only look for 271 * errors. 272 */ 273 if (getdevs(&cur) == -1) 274 errx(1, "%s", devstat_errbuf); 275 276 num_devices = cur.dinfo->numdevs; 277 generation = cur.dinfo->generation; 278 279 /* 280 * If the user specified any devices on the command line, see if 281 * they are in the list of devices we have now. 282 */ 283 if ((specified_devices = (char **)malloc(sizeof(char *))) == NULL) 284 err(1, "specified_devices malloc failed"); 285 for (num_devices_specified = 0; *argv; ++argv) { 286 if (isdigit(**argv)) 287 break; 288 num_devices_specified++; 289 specified_devices = (char **)realloc(specified_devices, 290 sizeof(char *) * 291 num_devices_specified); 292 specified_devices[num_devices_specified - 1] = *argv; 293 294 } 295 if (nflag == 0 && maxshowdevs < num_devices_specified) 296 maxshowdevs = num_devices_specified; 297 298 dev_select = NULL; 299 300 if ((num_devices_specified == 0) && (num_matches == 0)) 301 select_mode = DS_SELECT_ADD; 302 else 303 select_mode = DS_SELECT_ONLY; 304 305 /* 306 * At this point, selectdevs will almost surely indicate that the 307 * device list has changed, so we don't look for return values of 0 308 * or 1. If we get back -1, though, there is an error. 309 */ 310 if (selectdevs(&dev_select, &num_selected, 311 &num_selections, &select_generation, 312 generation, cur.dinfo->devices, num_devices, 313 matches, num_matches, 314 specified_devices, num_devices_specified, 315 select_mode, maxshowdevs, hflag) == -1) 316 errx(1, "%s", devstat_errbuf); 317 318 /* 319 * Look for the traditional wait time and count arguments. 320 */ 321 if (*argv) { 322 waittime = atoi(*argv); 323 324 /* Let the user know he goofed, but keep going anyway */ 325 if (wflag != 0) 326 warnx("discarding previous wait interval, using" 327 " %d instead", waittime); 328 wflag++; 329 330 if (*++argv) { 331 count = atoi(*argv); 332 if (cflag != 0) 333 warnx("discarding previous count, using %d" 334 " instead", count); 335 cflag++; 336 } else 337 count = -1; 338 } 339 340 /* 341 * If the user specified a count, but not an interval, we default 342 * to an interval of 1 second. 343 */ 344 if ((wflag == 0) && (cflag > 0)) 345 waittime = 1; 346 347 /* 348 * If the user specified a wait time, but not a count, we want to 349 * go on ad infinitum. This can be redundant if the user uses the 350 * traditional method of specifying the wait, since in that case we 351 * already set count = -1 above. Oh well. 352 */ 353 if ((wflag > 0) && (cflag == 0)) 354 count = -1; 355 356 if (kinfo_get_sched_hz(&hz)) 357 err(1, "kinfo_get_sched_hz"); 358 if (kinfo_get_sched_stathz(&hz)) 359 err(1, "kinfo_get_sched_stathz"); 360 361 /* 362 * If the user stops the program (control-Z) and then resumes it, 363 * print out the header again. 364 */ 365 signal(SIGCONT, phdr); 366 367 for (headercount = 1;;) { 368 struct devinfo *tmp_dinfo; 369 370 if (!--headercount) { 371 phdr(0); 372 headercount = 20; 373 } 374 if (kinfo_get_tty_tk_nin(&tk_nin)) 375 err(1, "kinfo_get_tty_tk_nin"); 376 if (kinfo_get_tty_tk_nout(&tk_nout)) 377 err(1, "kinfo_get_tty_tk_nout"); 378 if (kinfo_get_sched_cputime(&cp_time)) 379 err(1, "kinfo_get_sched_cputime"); 380 381 tmp_dinfo = last.dinfo; 382 last.dinfo = cur.dinfo; 383 cur.dinfo = tmp_dinfo; 384 385 last.busy_time = cur.busy_time; 386 387 /* 388 * Here what we want to do is refresh our device stats. 389 * getdevs() returns 1 when the device list has changed. 390 * If the device list has changed, we want to go through 391 * the selection process again, in case a device that we 392 * were previously displaying has gone away. 393 */ 394 switch (getdevs(&cur)) { 395 case -1: 396 errx(1, "%s", devstat_errbuf); 397 break; 398 case 1: { 399 int retval; 400 401 num_devices = cur.dinfo->numdevs; 402 generation = cur.dinfo->generation; 403 retval = selectdevs(&dev_select, &num_selected, 404 &num_selections, &select_generation, 405 generation, cur.dinfo->devices, 406 num_devices, matches, num_matches, 407 specified_devices, 408 num_devices_specified, 409 select_mode, maxshowdevs, hflag); 410 switch(retval) { 411 case -1: 412 errx(1, "%s", devstat_errbuf); 413 break; 414 case 1: 415 phdr(0); 416 headercount = 20; 417 break; 418 default: 419 break; 420 } 421 break; 422 } 423 default: 424 break; 425 } 426 427 /* 428 * We only want to re-select devices if we're in 'top' 429 * mode. This is the only mode where the devices selected 430 * could actually change. 431 */ 432 if (hflag > 0) { 433 int retval; 434 retval = selectdevs(&dev_select, &num_selected, 435 &num_selections, &select_generation, 436 generation, cur.dinfo->devices, 437 num_devices, matches, num_matches, 438 specified_devices, 439 num_devices_specified, 440 select_mode, maxshowdevs, hflag); 441 switch(retval) { 442 case -1: 443 errx(1,"%s", devstat_errbuf); 444 break; 445 case 1: 446 phdr(0); 447 headercount = 20; 448 break; 449 default: 450 break; 451 } 452 } 453 454 diff_tk_nin = tk_nin - old_tk_nin; 455 old_tk_nin = tk_nin; 456 diff_tk_nout = tk_nout - old_tk_nout; 457 old_tk_nout = tk_nout; 458 459 diff_cp_time.cp_user = cp_time.cp_user - old_cp_time.cp_user; 460 diff_cp_time.cp_nice = cp_time.cp_nice - old_cp_time.cp_nice; 461 diff_cp_time.cp_sys = cp_time.cp_sys - old_cp_time.cp_sys; 462 diff_cp_time.cp_intr = cp_time.cp_intr - old_cp_time.cp_intr; 463 diff_cp_time.cp_idle = cp_time.cp_idle - old_cp_time.cp_idle; 464 cp_time_total = diff_cp_time.cp_user + diff_cp_time.cp_nice + 465 diff_cp_time.cp_sys + diff_cp_time.cp_intr + 466 diff_cp_time.cp_idle; 467 old_cp_time = cp_time; 468 469 if (cp_time_total == 0.0) 470 cp_time_total = 1.0; 471 472 if ((dflag == 0) || (Tflag > 0)) 473 printf("%4.0f%5.0f", diff_tk_nin / cp_time_total * 1e6, 474 diff_tk_nout / cp_time_total * 1e6); 475 devstats(hflag); 476 if ((dflag == 0) || (Cflag > 0)) 477 cpustats(); 478 printf("\n"); 479 fflush(stdout); 480 481 if (count >= 0 && --count <= 0) 482 break; 483 484 sleep(waittime); 485 } 486 487 exit(0); 488 } 489 490 static void 491 phdr(__unused int signo) 492 { 493 int i; 494 int printed; 495 496 if ((dflag == 0) || (Tflag > 0)) 497 printf(" tty"); 498 for (i = 0, printed=0;(i < num_devices) && (printed < maxshowdevs);i++){ 499 int di; 500 if ((dev_select[i].selected != 0) 501 && (dev_select[i].selected <= maxshowdevs)) { 502 di = dev_select[i].position; 503 if (oflag > 0) 504 printf("%12.6s%d ", 505 cur.dinfo->devices[di].device_name, 506 cur.dinfo->devices[di].unit_number); 507 else 508 if (Dflag > 0) 509 printf("%19.6s%d ", 510 cur.dinfo->devices[di].device_name, 511 cur.dinfo->devices[di].unit_number); 512 else 513 printf("%15.6s%d ", 514 cur.dinfo->devices[di].device_name, 515 cur.dinfo->devices[di].unit_number); 516 printed++; 517 } 518 } 519 if ((dflag == 0) || (Cflag > 0)) 520 printf(" cpu\n"); 521 else 522 printf("\n"); 523 524 if ((dflag == 0) || (Tflag > 0)) 525 printf(" tin tout"); 526 527 for (i=0, printed = 0;(i < num_devices) && (printed < maxshowdevs);i++){ 528 if ((dev_select[i].selected != 0) 529 && (dev_select[i].selected <= maxshowdevs)) { 530 if (oflag > 0) { 531 if (Iflag == 0) 532 printf(" sps tps msps "); 533 else 534 printf(" blk xfr msps "); 535 } else { 536 if (Iflag == 0) { 537 if (Dflag > 0) 538 printf(" KB/t rtps MBr/s wtps MBw/s "); 539 else 540 printf(" KB/t tps MB/s "); 541 } 542 else 543 printf(" KB/t xfrs MB "); 544 } 545 printed++; 546 } 547 } 548 if ((dflag == 0) || (Cflag > 0)) 549 printf(" us ni sy in id\n"); 550 else 551 printf("\n"); 552 553 } 554 555 static void 556 devstats(int perf_select) 557 { 558 int dn; 559 long double kb_per_transfer; 560 long double transfers_per_second; 561 long double transfers_per_secondr, transfers_per_secondw; 562 long double mb_per_second; 563 long double mb_per_secondr, mb_per_secondw; 564 u_int64_t total_bytes, total_transfers, total_blocks; 565 long double busy_seconds; 566 long double total_mb; 567 long double blocks_per_second, ms_per_transaction; 568 569 /* 570 * Calculate elapsed time up front, since it's the same for all 571 * devices. 572 */ 573 busy_seconds = compute_etime(cur.busy_time, last.busy_time); 574 575 for (dn = 0; dn < num_devices; dn++) { 576 int di; 577 578 if (((perf_select == 0) && (dev_select[dn].selected == 0)) 579 || (dev_select[dn].selected > maxshowdevs)) 580 continue; 581 582 di = dev_select[dn].position; 583 584 if (compute_stats(&cur.dinfo->devices[di], 585 &last.dinfo->devices[di], busy_seconds, 586 &total_bytes, &total_transfers, 587 &total_blocks, &kb_per_transfer, 588 &transfers_per_second, &mb_per_second, 589 &blocks_per_second, &ms_per_transaction)!= 0) 590 errx(1, "%s", devstat_errbuf); 591 if (compute_stats_read(&cur.dinfo->devices[di], 592 &last.dinfo->devices[di], busy_seconds, 593 NULL, NULL, 594 NULL, NULL, 595 &transfers_per_secondr, &mb_per_secondr, 596 NULL, NULL)!= 0) 597 errx(1, "%s", devstat_errbuf); 598 if (compute_stats_write(&cur.dinfo->devices[di], 599 &last.dinfo->devices[di], busy_seconds, 600 NULL, NULL, 601 NULL, NULL, 602 &transfers_per_secondw, &mb_per_secondw, 603 NULL, NULL)!= 0) 604 errx(1, "%s", devstat_errbuf); 605 606 if (perf_select != 0) { 607 dev_select[dn].bytes = total_bytes; 608 if ((dev_select[dn].selected == 0) 609 || (dev_select[dn].selected > maxshowdevs)) 610 continue; 611 } 612 613 if (Kflag) { 614 int block_size = cur.dinfo->devices[di].block_size; 615 total_blocks = total_blocks * (block_size ? 616 block_size : 512) / 1024; 617 } 618 619 if (oflag > 0) { 620 int msdig = (ms_per_transaction < 100.0) ? 1 : 0; 621 622 if (Iflag == 0) 623 printf("%4.0Lf%4.0Lf%5.*Lf ", 624 blocks_per_second, 625 transfers_per_second, 626 msdig, 627 ms_per_transaction); 628 else 629 printf("%4.1ju%4.1ju%5.*Lf ", 630 (uintmax_t)total_blocks, 631 (uintmax_t)total_transfers, 632 msdig, 633 ms_per_transaction); 634 } else { 635 if (Iflag == 0) 636 if (Dflag > 0) { 637 printf(" %5.2Lf %4.0Lf %6.2Lf %4.0Lf %6.2Lf ", 638 kb_per_transfer, 639 transfers_per_secondr, 640 mb_per_secondr, 641 transfers_per_secondw, 642 mb_per_secondw); 643 } else { 644 printf(" %5.2Lf %4.0Lf %5.2Lf ", 645 kb_per_transfer, 646 transfers_per_second, 647 mb_per_second); 648 } 649 else { 650 total_mb = total_bytes; 651 total_mb /= 1024 * 1024; 652 653 printf(" %5.2Lf %3.1ju %5.2Lf ", 654 kb_per_transfer, 655 (uintmax_t)total_transfers, 656 total_mb); 657 } 658 } 659 } 660 } 661 662 static void 663 cpustats(void) 664 { 665 if (cp_time_total == 0.0) 666 cp_time_total = 1.0; 667 668 printf(" %2.0f", 100. * diff_cp_time.cp_user / cp_time_total); 669 printf(" %2.0f", 100. * diff_cp_time.cp_nice / cp_time_total); 670 printf(" %2.0f", 100. * diff_cp_time.cp_sys / cp_time_total); 671 printf(" %2.0f", 100. * diff_cp_time.cp_intr / cp_time_total); 672 printf(" %2.0f", 100. * diff_cp_time.cp_idle / cp_time_total); 673 } 674