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/user.h> 104 #include <sys/param.h> 105 #include <sys/errno.h> 106 107 #include <err.h> 108 #include <ctype.h> 109 #include <fcntl.h> 110 #include <kinfo.h> 111 #include <stdio.h> 112 #include <stdlib.h> 113 #include <string.h> 114 #include <unistd.h> 115 #include <limits.h> 116 #include <devstat.h> 117 118 struct statinfo cur, last; 119 uint64_t tk_nin, old_tk_nin, diff_tk_nin; 120 uint64_t tk_nout, old_tk_nout, diff_tk_nout; 121 struct kinfo_cputime cp_time, old_cp_time, diff_cp_time; 122 double cp_time_total; 123 int num_devices; 124 struct device_selection *dev_select; 125 int maxshowdevs; 126 int dflag = 0, Dflag=0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0; 127 128 /* local function declarations */ 129 static void usage(void); 130 static void phdr(int signo); 131 static void devstats(int perf_select); 132 static void cpustats(void); 133 134 static void 135 usage(void) 136 { 137 /* 138 * We also support the following 'traditional' syntax: 139 * iostat [drives] [wait [count]] 140 * This isn't mentioned in the man page, or the usage statement, 141 * but it is supported. 142 */ 143 fprintf(stderr, "usage: iostat [-CdhIKoT] [-c count]" 144 " [-n devs]\n" 145 "\t [-t type,if,pass] [-w wait] [drives]\n"); 146 } 147 148 int 149 main(int argc, char **argv) 150 { 151 int c; 152 int tflag = 0, hflag = 0, cflag = 0, wflag = 0, nflag = 0; 153 int count = 0, waittime = 0; 154 struct devstat_match *matches; 155 int num_matches = 0; 156 int hz; 157 int headercount; 158 long generation; 159 int num_devices_specified; 160 int num_selected, num_selections; 161 long select_generation; 162 char **specified_devices; 163 devstat_select_mode select_mode; 164 165 matches = NULL; 166 maxshowdevs = 3; 167 168 while ((c = getopt(argc, argv, "c:CdDhIKM:n:N:ot:Tw:")) != -1) { 169 switch(c) { 170 case 'c': 171 cflag++; 172 count = atoi(optarg); 173 if (count < 1) 174 errx(1, "count %d is < 1", count); 175 break; 176 case 'C': 177 Cflag++; 178 break; 179 case 'd': 180 dflag++; 181 break; 182 case 'D': 183 Dflag++; 184 break; 185 case 'h': 186 hflag++; 187 break; 188 case 'I': 189 Iflag++; 190 break; 191 case 'K': 192 Kflag++; 193 break; 194 case 'n': 195 nflag++; 196 maxshowdevs = atoi(optarg); 197 if (maxshowdevs < 0) 198 errx(1, "number of devices %d is < 0", 199 maxshowdevs); 200 break; 201 case 'o': 202 oflag++; 203 break; 204 case 't': 205 tflag++; 206 if (buildmatch(optarg, &matches, 207 &num_matches) != 0) 208 errx(1, "%s", devstat_errbuf); 209 break; 210 case 'T': 211 Tflag++; 212 break; 213 case 'w': 214 wflag++; 215 waittime = atoi(optarg); 216 if (waittime < 1) 217 errx(1, "wait time is < 1"); 218 break; 219 default: 220 usage(); 221 exit(1); 222 break; 223 } 224 } 225 226 argc -= optind; 227 argv += optind; 228 229 /* 230 * Make sure that the userland devstat version matches the kernel 231 * devstat version. If not, exit and print a message informing 232 * the user of his mistake. 233 */ 234 if (checkversion() < 0) 235 errx(1, "%s", devstat_errbuf); 236 237 /* 238 * Figure out how many devices we should display. 239 */ 240 if (nflag == 0) { 241 if (oflag > 0) { 242 if ((dflag > 0) && (Cflag == 0) && (Tflag == 0)) 243 maxshowdevs = 5; 244 else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0)) 245 maxshowdevs = 5; 246 else 247 maxshowdevs = 4; 248 } else { 249 if ((dflag > 0) && (Cflag == 0)) 250 maxshowdevs = 4; 251 else 252 maxshowdevs = 3; 253 } 254 } 255 256 /* find out how many devices we have */ 257 if ((num_devices = getnumdevs()) < 0) 258 err(1, "can't get number of devices"); 259 260 if ((cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo))) == 261 NULL) 262 err(1, "devinfo malloc failed"); 263 if ((last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo))) == 264 NULL) 265 err(1, "devinfo malloc failed"); 266 bzero(cur.dinfo, sizeof(struct devinfo)); 267 bzero(last.dinfo, sizeof(struct devinfo)); 268 269 /* 270 * Grab all the devices. We don't look to see if the list has 271 * changed here, since it almost certainly has. We only look for 272 * errors. 273 */ 274 if (getdevs(&cur) == -1) 275 errx(1, "%s", devstat_errbuf); 276 277 num_devices = cur.dinfo->numdevs; 278 generation = cur.dinfo->generation; 279 280 /* 281 * If the user specified any devices on the command line, see if 282 * they are in the list of devices we have now. 283 */ 284 if ((specified_devices = (char **)malloc(sizeof(char *))) == NULL) 285 err(1, "specified_devices malloc failed"); 286 for (num_devices_specified = 0; *argv; ++argv) { 287 if (isdigit(**argv)) 288 break; 289 num_devices_specified++; 290 specified_devices = (char **)realloc(specified_devices, 291 sizeof(char *) * 292 num_devices_specified); 293 specified_devices[num_devices_specified - 1] = *argv; 294 295 } 296 if (nflag == 0 && maxshowdevs < num_devices_specified) 297 maxshowdevs = num_devices_specified; 298 299 dev_select = NULL; 300 301 if ((num_devices_specified == 0) && (num_matches == 0)) 302 select_mode = DS_SELECT_ADD; 303 else 304 select_mode = DS_SELECT_ONLY; 305 306 /* 307 * At this point, selectdevs will almost surely indicate that the 308 * device list has changed, so we don't look for return values of 0 309 * or 1. If we get back -1, though, there is an error. 310 */ 311 if (selectdevs(&dev_select, &num_selected, 312 &num_selections, &select_generation, 313 generation, cur.dinfo->devices, num_devices, 314 matches, num_matches, 315 specified_devices, num_devices_specified, 316 select_mode, maxshowdevs, hflag) == -1) 317 errx(1, "%s", devstat_errbuf); 318 319 /* 320 * Look for the traditional wait time and count arguments. 321 */ 322 if (*argv) { 323 waittime = atoi(*argv); 324 325 /* Let the user know he goofed, but keep going anyway */ 326 if (wflag != 0) 327 warnx("discarding previous wait interval, using" 328 " %d instead", waittime); 329 wflag++; 330 331 if (*++argv) { 332 count = atoi(*argv); 333 if (cflag != 0) 334 warnx("discarding previous count, using %d" 335 " instead", count); 336 cflag++; 337 } else 338 count = -1; 339 } 340 341 /* 342 * If the user specified a count, but not an interval, we default 343 * to an interval of 1 second. 344 */ 345 if ((wflag == 0) && (cflag > 0)) 346 waittime = 1; 347 348 /* 349 * If the user specified a wait time, but not a count, we want to 350 * go on ad infinitum. This can be redundant if the user uses the 351 * traditional method of specifying the wait, since in that case we 352 * already set count = -1 above. Oh well. 353 */ 354 if ((wflag > 0) && (cflag == 0)) 355 count = -1; 356 357 if (kinfo_get_sched_hz(&hz)) 358 err(1, "kinfo_get_sched_hz"); 359 if (kinfo_get_sched_stathz(&hz)) 360 err(1, "kinfo_get_sched_stathz"); 361 362 /* 363 * If the user stops the program (control-Z) and then resumes it, 364 * print out the header again. 365 */ 366 signal(SIGCONT, phdr); 367 368 for (headercount = 1;;) { 369 struct devinfo *tmp_dinfo; 370 371 if (!--headercount) { 372 phdr(0); 373 headercount = 20; 374 } 375 if (kinfo_get_tty_tk_nin(&tk_nin)) 376 err(1, "kinfo_get_tty_tk_nin"); 377 if (kinfo_get_tty_tk_nout(&tk_nout)) 378 err(1, "kinfo_get_tty_tk_nout"); 379 if (kinfo_get_sched_cputime(&cp_time)) 380 err(1, "kinfo_get_sched_cputime"); 381 382 tmp_dinfo = last.dinfo; 383 last.dinfo = cur.dinfo; 384 cur.dinfo = tmp_dinfo; 385 386 last.busy_time = cur.busy_time; 387 388 /* 389 * Here what we want to do is refresh our device stats. 390 * getdevs() returns 1 when the device list has changed. 391 * If the device list has changed, we want to go through 392 * the selection process again, in case a device that we 393 * were previously displaying has gone away. 394 */ 395 switch (getdevs(&cur)) { 396 case -1: 397 errx(1, "%s", devstat_errbuf); 398 break; 399 case 1: { 400 int retval; 401 402 num_devices = cur.dinfo->numdevs; 403 generation = cur.dinfo->generation; 404 retval = selectdevs(&dev_select, &num_selected, 405 &num_selections, &select_generation, 406 generation, cur.dinfo->devices, 407 num_devices, matches, num_matches, 408 specified_devices, 409 num_devices_specified, 410 select_mode, maxshowdevs, hflag); 411 switch(retval) { 412 case -1: 413 errx(1, "%s", devstat_errbuf); 414 break; 415 case 1: 416 phdr(0); 417 headercount = 20; 418 break; 419 default: 420 break; 421 } 422 break; 423 } 424 default: 425 break; 426 } 427 428 /* 429 * We only want to re-select devices if we're in 'top' 430 * mode. This is the only mode where the devices selected 431 * could actually change. 432 */ 433 if (hflag > 0) { 434 int retval; 435 retval = selectdevs(&dev_select, &num_selected, 436 &num_selections, &select_generation, 437 generation, cur.dinfo->devices, 438 num_devices, matches, num_matches, 439 specified_devices, 440 num_devices_specified, 441 select_mode, maxshowdevs, hflag); 442 switch(retval) { 443 case -1: 444 errx(1,"%s", devstat_errbuf); 445 break; 446 case 1: 447 phdr(0); 448 headercount = 20; 449 break; 450 default: 451 break; 452 } 453 } 454 455 diff_tk_nin = tk_nin - old_tk_nin; 456 old_tk_nin = tk_nin; 457 diff_tk_nout = tk_nout - old_tk_nout; 458 old_tk_nout = tk_nout; 459 460 diff_cp_time.cp_user = cp_time.cp_user - old_cp_time.cp_user; 461 diff_cp_time.cp_nice = cp_time.cp_nice - old_cp_time.cp_nice; 462 diff_cp_time.cp_sys = cp_time.cp_sys - old_cp_time.cp_sys; 463 diff_cp_time.cp_intr = cp_time.cp_intr - old_cp_time.cp_intr; 464 diff_cp_time.cp_idle = cp_time.cp_idle - old_cp_time.cp_idle; 465 cp_time_total = diff_cp_time.cp_user + diff_cp_time.cp_nice + 466 diff_cp_time.cp_sys + diff_cp_time.cp_intr + 467 diff_cp_time.cp_idle; 468 old_cp_time = cp_time; 469 470 if (cp_time_total == 0.0) 471 cp_time_total = 1.0; 472 473 if ((dflag == 0) || (Tflag > 0)) 474 printf("%4.0f%5.0f", diff_tk_nin / cp_time_total * 1e6, 475 diff_tk_nout / cp_time_total * 1e6); 476 devstats(hflag); 477 if ((dflag == 0) || (Cflag > 0)) 478 cpustats(); 479 printf("\n"); 480 fflush(stdout); 481 482 if (count >= 0 && --count <= 0) 483 break; 484 485 sleep(waittime); 486 } 487 488 exit(0); 489 } 490 491 static void 492 phdr(__unused int signo) 493 { 494 int i; 495 int printed; 496 497 if ((dflag == 0) || (Tflag > 0)) 498 printf(" tty"); 499 for (i = 0, printed=0;(i < num_devices) && (printed < maxshowdevs);i++){ 500 int di; 501 if ((dev_select[i].selected != 0) 502 && (dev_select[i].selected <= maxshowdevs)) { 503 di = dev_select[i].position; 504 if (oflag > 0) 505 printf("%12.6s%d ", 506 cur.dinfo->devices[di].device_name, 507 cur.dinfo->devices[di].unit_number); 508 else 509 if (Dflag > 0) 510 printf("%19.6s%d ", 511 cur.dinfo->devices[di].device_name, 512 cur.dinfo->devices[di].unit_number); 513 else 514 printf("%15.6s%d ", 515 cur.dinfo->devices[di].device_name, 516 cur.dinfo->devices[di].unit_number); 517 printed++; 518 } 519 } 520 if ((dflag == 0) || (Cflag > 0)) 521 printf(" cpu\n"); 522 else 523 printf("\n"); 524 525 if ((dflag == 0) || (Tflag > 0)) 526 printf(" tin tout"); 527 528 for (i=0, printed = 0;(i < num_devices) && (printed < maxshowdevs);i++){ 529 if ((dev_select[i].selected != 0) 530 && (dev_select[i].selected <= maxshowdevs)) { 531 if (oflag > 0) { 532 if (Iflag == 0) 533 printf(" sps tps msps "); 534 else 535 printf(" blk xfr msps "); 536 } else { 537 if (Iflag == 0) { 538 if (Dflag > 0) 539 printf(" KB/t rtps MBr/s wtps MBw/s "); 540 else 541 printf(" KB/t tps MB/s "); 542 } 543 else 544 printf(" KB/t xfrs MB "); 545 } 546 printed++; 547 } 548 } 549 if ((dflag == 0) || (Cflag > 0)) 550 printf(" us ni sy in id\n"); 551 else 552 printf("\n"); 553 554 } 555 556 static void 557 devstats(int perf_select) 558 { 559 int dn; 560 long double kb_per_transfer; 561 long double transfers_per_second; 562 long double transfers_per_secondr, transfers_per_secondw; 563 long double mb_per_second; 564 long double mb_per_secondr, mb_per_secondw; 565 u_int64_t total_bytes, total_transfers, total_blocks; 566 long double busy_seconds; 567 long double total_mb; 568 long double blocks_per_second, ms_per_transaction; 569 570 /* 571 * Calculate elapsed time up front, since it's the same for all 572 * devices. 573 */ 574 busy_seconds = compute_etime(cur.busy_time, last.busy_time); 575 576 for (dn = 0; dn < num_devices; dn++) { 577 int di; 578 579 if (((perf_select == 0) && (dev_select[dn].selected == 0)) 580 || (dev_select[dn].selected > maxshowdevs)) 581 continue; 582 583 di = dev_select[dn].position; 584 585 if (compute_stats(&cur.dinfo->devices[di], 586 &last.dinfo->devices[di], busy_seconds, 587 &total_bytes, &total_transfers, 588 &total_blocks, &kb_per_transfer, 589 &transfers_per_second, &mb_per_second, 590 &blocks_per_second, &ms_per_transaction)!= 0) 591 errx(1, "%s", devstat_errbuf); 592 if (compute_stats_read(&cur.dinfo->devices[di], 593 &last.dinfo->devices[di], busy_seconds, 594 NULL, NULL, 595 NULL, NULL, 596 &transfers_per_secondr, &mb_per_secondr, 597 NULL, NULL)!= 0) 598 errx(1, "%s", devstat_errbuf); 599 if (compute_stats_write(&cur.dinfo->devices[di], 600 &last.dinfo->devices[di], busy_seconds, 601 NULL, NULL, 602 NULL, NULL, 603 &transfers_per_secondw, &mb_per_secondw, 604 NULL, NULL)!= 0) 605 errx(1, "%s", devstat_errbuf); 606 607 if (perf_select != 0) { 608 dev_select[dn].bytes = total_bytes; 609 if ((dev_select[dn].selected == 0) 610 || (dev_select[dn].selected > maxshowdevs)) 611 continue; 612 } 613 614 if (Kflag) { 615 int block_size = cur.dinfo->devices[di].block_size; 616 total_blocks = total_blocks * (block_size ? 617 block_size : 512) / 1024; 618 } 619 620 if (oflag > 0) { 621 int msdig = (ms_per_transaction < 100.0) ? 1 : 0; 622 623 if (Iflag == 0) 624 printf("%4.0Lf%4.0Lf%5.*Lf ", 625 blocks_per_second, 626 transfers_per_second, 627 msdig, 628 ms_per_transaction); 629 else 630 printf("%4.1ju%4.1ju%5.*Lf ", 631 (uintmax_t)total_blocks, 632 (uintmax_t)total_transfers, 633 msdig, 634 ms_per_transaction); 635 } else { 636 if (Iflag == 0) 637 if (Dflag > 0) { 638 printf(" %5.2Lf %4.0Lf %6.2Lf %4.0Lf %6.2Lf ", 639 kb_per_transfer, 640 transfers_per_secondr, 641 mb_per_secondr, 642 transfers_per_secondw, 643 mb_per_secondw); 644 } else { 645 printf(" %5.2Lf %4.0Lf %5.2Lf ", 646 kb_per_transfer, 647 transfers_per_second, 648 mb_per_second); 649 } 650 else { 651 total_mb = total_bytes; 652 total_mb /= 1024 * 1024; 653 654 printf(" %5.2Lf %3.1ju %5.2Lf ", 655 kb_per_transfer, 656 (uintmax_t)total_transfers, 657 total_mb); 658 } 659 } 660 } 661 } 662 663 static void 664 cpustats(void) 665 { 666 if (cp_time_total == 0.0) 667 cp_time_total = 1.0; 668 669 printf(" %2.0f", 100. * diff_cp_time.cp_user / cp_time_total); 670 printf(" %2.0f", 100. * diff_cp_time.cp_nice / cp_time_total); 671 printf(" %2.0f", 100. * diff_cp_time.cp_sys / cp_time_total); 672 printf(" %2.0f", 100. * diff_cp_time.cp_intr / cp_time_total); 673 printf(" %2.0f", 100. * diff_cp_time.cp_idle / cp_time_total); 674 } 675