1/* 2 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights 3 * Reserved. 4 * 5 * This file contains Original Code and/or Modifications of Original Code 6 * as defined in and that are subject to the Apple Public Source License 7 * Version 2.0 (the 'License'). You may not use this file except in 8 * compliance with the License. Please obtain a copy of the License at 9 * http://www.opensource.apple.com/apsl/ and read it before using this 10 * file. 11 * 12 * The Original Code and all software distributed under the License are 13 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 17 * Please see the License for the specific language governing rights and 18 * limitations under the License. 19*/ 20 21/* 22 cc -Wall -I. -I ../sadc.tproj -O -o sar sar.c 23*/ 24 25#include <stdio.h> 26#include <stdlib.h> 27#include <unistd.h> 28#include <ctype.h> 29#include <time.h> 30#include <fcntl.h> 31#include <errno.h> 32#include <signal.h> 33#include <mach/mach.h> 34#include <sys/param.h> 35#include <sys/sysctl.h> 36 37#include <sadc.h> 38#include <sar.h> 39 40 41#define IFNET_32_BIT_COUNTERS 1 42 43/* Options used only for launching sadc */ 44int t_interval = 5; /* in seconds */ 45char * t_intervalp = "5"; 46int n_samples = 1; /* number of sample loops */ 47char * n_samplesp = "1"; 48 49/* Used only for storing the binary output after launching sadc */ 50char *outfile = NULL; /* output file */ 51int ofd = 0; /* output file descriptor */ 52 53/* 54 * When launching sadc, this file descriptor reads sadc's stdout 55 * via pipe. 56 * When not launching sadc, this file descriptor will be either 57 * the input file passed in with the -f flag 58 * or the standard input file /var/log/sa/saXX 59 */ 60int ifd = 0; /* input file descriptor */ 61char *infile = NULL; /* input file */ 62 63 64 65/* Used when we have to luanch sadc */ 66pid_t pid; 67int fd[2]; /* read from fd[0], write to fd[1] */ 68 69char *optionstring1 = "Adgn:puo:"; 70char *optionstring1_usage = "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP } ] [-o filename] t [n]"; 71char *optionstring2 = "Adgn:pue:f:i:s:"; 72char *optionstring2_usage = "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP }] [-e time] [-f filename] [-i sec] [-s time]"; 73 74 75/* option flags */ 76int aflag = 0; 77int Aflag = 0; 78int bflag = 0; 79int cflag = 0; 80int dflag = 0; /* drive statistics */ 81int gflag = 0; /* page-out activity */ 82int kflag = 0; 83int mflag = 0; 84 85int nflag = 0; /* network statistics */ 86int network_mode = 0; 87char *sadc_mflagp = "-m"; 88char *sadc_ppp_modep = "PPP"; 89 90int pflag = 0; /* page-in activity */ 91int qflag = 0; 92int rflag = 0; 93int uflag = 0; /* cpu utilization - this is the only default */ 94int vflag = 0; 95int wflag = 0; 96int yflag = 0; 97int set_default_flag = 1; 98int flag_count = 0; 99 100/* 101 * To get the current time of day in seconds 102 * based on a 24 hour clock, pass in the time_t from time() 103 * the remainder is the current time in seconds 104*/ 105#define HOURS_PER_DAY 24 106#define MINS_PER_HOUR 60 107#define SECS_PER_MIN 60 108#define SECS_PER_DAY (SECS_PER_MIN * MINS_PER_HOUR * HOURS_PER_DAY) 109 110/* end time delimiter -- converted from hh:mm:ss to seconds */ 111time_t end_time = 0; 112 113int iflag = 0; 114int iseconds = 0; /* interval seconds, default = 0 implies all samples are 115 * printed */ 116 117/* start time delimiter -- converted from hh:mm:ss to seconds */ 118time_t start_time = 0; 119 120int oflag = 0; 121int fflag = 0; 122 123/* stat records average and previous */ 124struct vm_statistics prev_vmstat, avg_vmstat, cur_vmstat; 125host_cpu_load_info_data_t prev_cpuload, avg_cpuload, cur_cpuload; 126struct drivestats_report *dr_head = NULL; 127 128/* internal table of drive path mappings */ 129struct drivepath *dp_table = NULL; 130int dp_count = 0; 131 132/* internal table of network interface statistics */ 133struct netstats_report *nr_table = NULL; 134int nr_count; 135struct netstats *netstat_readbuf = NULL; 136size_t netstat_readbuf_size = 0; 137 138int avg_counter = 0; 139int avg_interval = 0; 140 141extern int errno; 142 143/* Forward function declarations */ 144static void exit_usage(); 145static void open_output_file(char *path); 146static void open_input_file(char *path); 147static void read_record_hdr(struct record_hdr *hdr, int writeflag); 148static void read_record_data(char *buf, size_t size, int writeflag); 149static void write_record_hdr(struct record_hdr *hdr); 150static void write_record_data(char *buf, size_t size); 151static time_t convert_hms(char *string); 152static char *get_hms_string(time_t, char *); 153static int find_restart_header(struct record_hdr *); 154static void print_all_column_headings (time_t timestamp); 155static void print_column_heading (int type, char *timebufptr, int mode); 156static void read_sample_set(int, time_t, struct record_hdr *); 157static void do_main_workloop(); 158static int bypass_sample_set(struct record_hdr *, time_t); 159static void skip_data(int); 160static int get_cpu_sample(int flag, struct record_hdr *hdr); 161static void print_cpu_sample(char *timebufptr); 162static int get_vmstat_sample(int flag, struct record_hdr *hdr); 163static void print_vmstat_sample(char *timebufptr); 164 165static int get_drivestats_sample(int flag, struct record_hdr *hdr); 166static void init_drivestats(struct drivestats_report *dr); 167static void print_drivestats_sample(char *timebufptr); 168static int get_drivepath_sample(int flag, struct record_hdr *hdr); 169 170static void set_cur_netstats(struct netstats_report *nr, struct netstats *ns); 171static void init_prev_netstats(struct netstats_report *nr); 172static int get_netstats_sample(int flag, struct record_hdr *hdr); 173static void print_netstats_sample(char *timebufptr); 174 175static void exit_average(); 176 177int 178main(argc, argv) 179 int argc; 180 char *argv[]; 181{ 182 183 char ch; 184 185 time_t curr_time; /* current time in seconds */ 186 char timebuf[26]; 187 char filenamebuf[20]; 188 char *optstring = NULL; 189 int optstringval; 190 int i; 191 192 /* 193 * Detirmine which option string to use 194 */ 195 196 optreset=0; 197 optstringval=0; 198 199 while((ch=getopt(argc, argv, "aAbcdgkmn:pqruvwyo:e:f:i:s:")) != EOF) { 200 switch(ch) { 201 case 'o': 202 if (optstringval == 2) 203 exit_usage(); 204 optstring=optionstring1; 205 optstringval=1; 206 break; 207 case 'e': 208 case 'f': 209 case 'i': 210 case 's': 211 if (optstringval == 1) 212 exit_usage(); 213 optstring=optionstring2; 214 optstringval=2; 215 break; 216 default: 217 /* ignore for now */ 218 break; 219 } 220 } 221 222 if (!optstring) 223 { 224 /* still trying to determine which option string to use */ 225 if (argc - optind > 0) 226 { 227 optstring=optionstring1; /* we should have a t_second value */ 228 optstringval=1; 229 } 230 else 231 { 232 optstring=optionstring2; 233 optstringval=2; 234 } 235 } 236 237 optreset = optind = 1; 238 while ((ch=getopt(argc, argv, optstring)) != EOF) { 239 switch (ch) { 240 case 'a': 241 aflag = 1; 242 set_default_flag = 0; 243 flag_count++; 244 break; 245 case 'A': 246 Aflag = 1; 247 set_default_flag = 0; 248 flag_count++; 249 break; 250 case 'b': 251 bflag = 1; 252 set_default_flag = 0; 253 flag_count++; 254 break; 255 case 'c': 256 cflag = 1; 257 set_default_flag = 0; 258 flag_count++; 259 break; 260 case 'd': 261 dflag = 1; 262 set_default_flag = 0; 263 flag_count++; 264 break; 265 case 'g': 266 gflag = 1; 267 set_default_flag = 0; 268 flag_count++; 269 break; 270 case 'k': 271 kflag = 1; 272 set_default_flag = 0; 273 flag_count++; 274 break; 275 case 'm': 276 mflag = 1; 277 set_default_flag = 0; 278 flag_count++; 279 break; 280 case 'n': 281 nflag= 1; 282 if (!strncmp(optarg, "PPP", 3)) 283 network_mode |= NET_PPP_MODE; 284 else if (!strncmp(optarg, "DEV", 3)) 285 network_mode |= NET_DEV_MODE; 286 else if (!strncmp(optarg, "EDEV", 4)) 287 network_mode |= NET_EDEV_MODE; 288 else 289 exit_usage(); 290 set_default_flag = 0; 291 flag_count++; 292 break; 293 case 'p': 294 pflag = 1; 295 set_default_flag = 0; 296 flag_count++; 297 break; 298 case 'q': 299 qflag = 1; 300 set_default_flag = 0; 301 flag_count++; 302 break; 303 case 'r': 304 rflag = 1; 305 set_default_flag = 0; 306 flag_count++; 307 break; 308 case 'u': 309 uflag= 1; 310 set_default_flag = 0; 311 flag_count++; 312 break; 313 case 'v': 314 vflag = 1; 315 set_default_flag = 0; 316 flag_count++; 317 break; 318 case 'w': 319 wflag = 1; 320 set_default_flag = 0; 321 flag_count++; 322 break; 323 case 'y': 324 yflag = 1; 325 set_default_flag = 0; 326 flag_count++; 327 break; 328 case 'o': 329 /* open the output file */ 330 oflag = 1; 331 outfile=optarg; 332 (void)open_output_file(outfile); 333 break; 334 case 'e': /* eflag */ 335 end_time = convert_hms(optarg); 336 break; 337 case 'f': 338 fflag = 1; 339 infile=optarg; 340 break; 341 case 'i': 342 iflag = 1; 343 iseconds=atoi(optarg); 344 break; 345 case 's': 346 start_time = convert_hms(optarg); 347 break; 348 default: 349 exit_usage(); 350 break; 351 } 352 } 353 354 /* setup default uflag option */ 355 if (Aflag) 356 { 357 dflag = gflag = pflag = uflag = 1; 358 if (!nflag) 359 { 360 /* 361 * Add network stats to the load 362 * but avoid PPP data by default. 363 */ 364 nflag = 1; 365 network_mode = NET_DEV_MODE | NET_EDEV_MODE;; 366 } 367 flag_count = 2; /* triggers column headings */ 368 } 369 else if (set_default_flag) 370 { 371 uflag=1; 372 flag_count++; 373 } 374 375 if (nflag) 376 { 377 if (network_mode & NET_PPP_MODE) 378 { 379 if (!(network_mode & NET_DEV_MODE) && 380 !(network_mode & NET_EDEV_MODE)) 381 { 382 /* set defaults */ 383 network_mode |= NET_DEV_MODE; 384 network_mode |= NET_EDEV_MODE; 385 flag_count++; 386 } 387 } 388 } 389 390 argc -= optind; 391 argv += optind; 392 393 /* set up signal handlers */ 394 signal(SIGINT, exit_average); 395 signal(SIGQUIT, exit_average); 396 signal(SIGHUP, exit_average); 397 signal(SIGTERM, exit_average); 398 399 if (optstringval == 1) 400 { 401 /* expecting a time interval */ 402 403 char *p; 404 405 if (argc >= 1) 406 { 407 errno = 0; 408 t_interval = strtol(argv[0], &p, 0); 409 t_intervalp = argv[0]; 410 if (errno || (*p != '\0') || t_interval <= 0 ) 411 exit_usage(); 412 if (argc >= 2) 413 { 414 errno=0; 415 n_samples = strtol(argv[1], &p, 0); 416 n_samplesp = argv[1]; 417 if (errno || (*p != '\0') || n_samples <= 0) 418 exit_usage(); 419 } 420 } 421 } 422 423 /* where does the input come from */ 424 if (fflag) 425 { 426 (void)open_input_file(infile); 427 } 428 else if (optstringval == 2) 429 { 430 /* 431 * Create a filename of the form /var/log/sa/sadd 432 * where "dd" is the date of the month 433 */ 434 curr_time = time((time_t *)0); /* returns time in seconds */ 435 436 /* 437 timebuf will be a 26-character string of the form: 438 Thu Nov 24 18:22:48 1986\n\0 439 */ 440 441 ctime_r(&curr_time, timebuf); 442 strncpy(filenamebuf, "/var/log/sa/sa", 14); 443 strncpy(&filenamebuf[14], &timebuf[8], 2); 444 if (filenamebuf[14] == ' ') 445 filenamebuf[14] = '0'; 446 filenamebuf[16]='\0'; 447 infile = filenamebuf; 448 (void)open_input_file(infile); 449 } 450 else if (optstringval == 1) 451 { 452 /* launch sadc */ 453 if (pipe(fd) == -1) 454 { 455 fprintf(stderr, "sar: pipe(2) failed, errno = (%d)\n",errno); 456 exit(1); 457 } 458 459 if ((pid=fork()) == 0) 460 { 461#if 0 462 int efd; 463#endif 464 int fdlimit = getdtablesize(); 465 466 /* This is the child */ 467 /* Close all file descriptors except the one we need */ 468 469 for (i=0; i < fdlimit; i++) { 470 if ((i != fd[0]) && (i != fd[1])) 471 (void)close(i); 472 } 473#if 0 474 efd = open("/tmp/errlog", O_CREAT|O_APPEND|O_RDWR, 0666); 475 if (dup2(efd,2) == -1) { 476 exit(1); 477 } 478#endif 479 /* Dup the two file descriptors to stdin and stdout */ 480 if (dup2(fd[0],0) == -1) { 481 exit(1); 482 } 483 if (dup2(fd[1],1) == -1) { 484 exit(1); 485 } 486 /* Exec the child process */ 487 if (network_mode & NET_PPP_MODE) 488 execl("/usr/lib/sa/sadc", "sadc", sadc_mflagp, sadc_ppp_modep, t_intervalp, n_samplesp, NULL); 489 else 490 execl("/usr/lib/sa/sadc", "sadc", t_intervalp, n_samplesp, NULL); 491 492 perror("execlp sadc"); 493 exit(2); /* This call of exit(2) should never be reached... */ 494 } 495 else 496 { /* This is the parent */ 497 if (pid == -1) { 498 fprintf(stderr, "sar: fork(2) failed, errno = (%d)\n",errno); 499 exit(1); 500 } 501 close (fd[1]); /* parent does not write to the pipe */ 502 ifd = fd[0]; /* parent will read from the pipe */ 503 } 504 } 505 else 506 { 507 /* we're confused about source of input data - bail out */ 508 fprintf(stderr, "sar: no input file recognized\n"); 509 exit_usage(); 510 } 511 512 /* start reading input data and format the output */ 513 (void)do_main_workloop(); 514 (void)exit_average(); 515 exit(0); 516} 517 518static void 519exit_usage() 520{ 521 fprintf(stderr, "\n%s\n\n", optionstring1_usage); 522 fprintf(stderr, "%s\n", optionstring2_usage); 523 exit(EXIT_FAILURE); 524} 525 526static void 527open_output_file(char *path) 528{ 529 if ((ofd = open(path, O_CREAT|O_APPEND|O_TRUNC|O_WRONLY, 0664)) == -1 ) 530 { 531 /* failed to open path */ 532 fprintf(stderr, "sar: failed to open output file [%s]\n", path); 533 exit_usage(); 534 } 535} 536 537 538static void 539open_input_file(char *path) 540{ 541 if ((ifd = open(path, O_RDONLY, 0)) == -1) 542 { 543 /* failed to open path */ 544 fprintf(stderr, "sar: failed to open input file [%d][%s]\n", ifd, path); 545 exit_usage(); 546 } 547} 548 549static void 550read_record_hdr(hdr, writeflag) 551 struct record_hdr *hdr; 552 int writeflag; 553{ 554 errno = 0; 555 int num = 0; 556 int n = 0; 557 size_t size = 0; 558 559 size = sizeof(struct record_hdr); 560 561 while (size) 562 { 563 num = read(ifd, &hdr[n], size); 564 if (num > 0) 565 { 566 n += num; 567 size -= num; 568 } 569 else if (num == 0) 570 exit_average(); 571 else 572 { 573 fprintf(stderr, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno, (int)num, (int)size); 574 exit(EXIT_FAILURE); 575 } 576 } 577 578 if (oflag && writeflag) 579 write_record_hdr(hdr); 580 581 return; 582} 583 584static void 585read_record_data(buf, size, writeflag) 586 char * buf; 587 size_t size; 588 int writeflag; 589{ 590 errno = 0; 591 size_t num = 0; 592 size_t n = 0; 593 594 while (size) 595 { 596 num = read(ifd, &buf[n], size); 597 if (num > 0) 598 { 599 n += num; 600 size -= num; 601 } 602 else if (num == 0) /* EOF */ 603 exit_average(); 604 else 605 { 606 fprintf(stderr, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno, (int)num, (int)size); 607 exit(EXIT_FAILURE); 608 } 609 } 610 611 if (oflag && writeflag) 612 write_record_data(buf, n); 613 614 return; 615} 616 617static void 618write_record_hdr(hdr) 619 struct record_hdr *hdr; 620{ 621 errno = 0; 622 int num; 623 624 if ((num = write(ofd, hdr, sizeof(struct record_hdr))) == -1) 625 { 626 fprintf(stderr, "sar: write_record_hdr failed, errno=%d\n", errno); 627 exit(EXIT_FAILURE); 628 } 629 return; 630} 631 632static void 633write_record_data(char *buf, size_t nbytes) 634{ 635 errno = 0; 636 int num; 637 if ((num = write(ofd, buf, nbytes)) == -1) 638 { 639 fprintf(stderr, "sar: write_record_data failed, errno=%d\n", errno); 640 exit(EXIT_FAILURE); 641 } 642 return; 643} 644 645/* 646 * Convert a string of one of the forms 647 * hh hh:mm hh:mm:ss 648 * into the number of seconds. 649 * exit on error 650*/ 651 652static time_t 653convert_hms(string) 654 char *string; 655{ 656 int hh = 0; /* hours */ 657 int mm = 0; /* minutes */ 658 int ss = 0; /* seconds */ 659 time_t seconds; 660 time_t timestamp; 661 struct tm *tm; 662 int i; 663 664 if (string == NULL || *string == '\0') 665 goto convert_err; 666 667 for (i=0; string[i] != '\0'; i++) 668 { 669 if ((!isdigit(string[i])) && (string[i] != ':')) 670 { 671 goto convert_err; 672 } 673 } 674 675 if (sscanf(string, "%d:%d:%d", &hh, &mm, &ss) != 3) 676 { 677 if (sscanf(string, "%d:%d", &hh, &mm) != 2) 678 { 679 if (sscanf(string, "%d", &hh) != 1) 680 { 681 goto convert_err; 682 } 683 } 684 } 685 686 if (hh < 0 || hh >= HOURS_PER_DAY || 687 mm < 0 || mm >= MINS_PER_HOUR || 688 ss < 0 || ss > SECS_PER_MIN) 689 { 690 goto convert_err; 691 } 692 693 seconds = ((((hh * MINS_PER_HOUR) + mm) * SECS_PER_MIN) + ss); 694 timestamp = time((time_t *)0); 695 tm=localtime(×tamp); 696 seconds -= tm->tm_gmtoff; 697 698 return(seconds); 699 700 convert_err: 701 fprintf(stderr, "sar: time format usage is hh[:mm[:ss]]\n"); 702 exit_usage(); 703 return(0); 704} 705 706 707/* 708 * Use ctime_r to convert a time value into 709 * a 26-character string of the form: 710 * 711 * Thu Nov 24 18:22:48 1986\n\0 712 */ 713 714static char * 715get_hms_string(tdata, tbuf) 716 time_t tdata; 717 char *tbuf; 718{ 719 time_t t; 720 char *p; 721 722 t = tdata; 723 ctime_r(&t, tbuf); 724 p=&tbuf[11]; 725 tbuf[19] = 0; 726 727 return(p); 728} 729 730 731/* sample set flags */ 732#define INIT_SET 0 733#define PRINT_SET 1 734#define PRINT_AVG 2 735 736static void 737do_main_workloop() 738{ 739 struct record_hdr hdr; 740 time_t cur_timestamp = 0; /* seconds - Coordinated Universal Time */ 741 time_t next_timestamp = 0; /* seconds - Coordinated Universal Time */ 742 743 if (!find_restart_header(&hdr)) 744 exit(1); 745 746 cur_timestamp = hdr.rec_timestamp; 747 748 /* convert sflag's start_time from 24 hour clock time to UTC seconds */ 749 if (start_time < (cur_timestamp % SECS_PER_DAY)) 750 start_time = cur_timestamp; 751 else 752 start_time += cur_timestamp - (cur_timestamp % SECS_PER_DAY); 753 754 /* convert end_time, from 24 hour clock time to UTC seconds */ 755 if (end_time != 0) 756 end_time += cur_timestamp - (cur_timestamp % SECS_PER_DAY); 757 758#if 0 759 fprintf(stderr, "start = %ld, end = %ld, cur=%ld, [24hour - %ld]\n", 760 start_time, end_time, cur_timestamp,(cur_timestamp % SECS_PER_DAY)); 761#endif 762 763 while (cur_timestamp < start_time) 764 { 765 bypass_sample_set(&hdr, cur_timestamp); 766 cur_timestamp = hdr.rec_timestamp; 767 } 768 769 next_timestamp = cur_timestamp + iseconds; 770 print_all_column_headings(cur_timestamp); 771 read_sample_set(INIT_SET, cur_timestamp, &hdr); 772 cur_timestamp = hdr.rec_timestamp; 773 774 while ((end_time == 0) || (next_timestamp < end_time)) 775 { 776 if (cur_timestamp < next_timestamp) 777 { 778 bypass_sample_set (&hdr, cur_timestamp); 779 cur_timestamp = hdr.rec_timestamp; 780 } 781 else 782 { 783 /* need to know the seconds interval when printing averages */ 784 if (avg_interval == 0) 785 { 786 if (iseconds) 787 avg_interval = iseconds; 788 else 789 avg_interval = cur_timestamp - next_timestamp; 790 } 791 next_timestamp = cur_timestamp + iseconds; 792 read_sample_set(PRINT_SET, cur_timestamp, &hdr); 793 cur_timestamp = hdr.rec_timestamp; 794 } 795 } 796 exit_average(); 797} 798 799 800/* 801 * Find and fill in a restart header. We don't write 802 * the binary data when looking for SAR_RESTART. 803 * Return: 1 on success 804 * 0 on failure 805 */ 806static int 807find_restart_header (ret_hdr) 808 struct record_hdr *ret_hdr; 809{ 810 struct record_hdr hdr; 811 int bufsize = 0; 812 char *buf = NULL; 813 814 errno = 0; 815 816 restart_loop: 817 read_record_hdr(&hdr, FALSE); /* exits on error */ 818 819 if (hdr.rec_type == SAR_RESTART) 820 { 821 *ret_hdr = hdr; 822 if (oflag) 823 write_record_hdr(&hdr); /* writes the RESTART record */ 824 if (buf) 825 free(buf); 826 return(1); 827 } 828 829 /* 830 * not the record we want... 831 * read past data and try again 832 */ 833 if (hdr.rec_count) 834 { 835 if (fflag) 836 { /* seek past data in the file */ 837 if ((lseek(ifd, (hdr.rec_count * hdr.rec_size), SEEK_CUR)) == -1) 838 { 839 /*exit on error */ 840 fprintf(stderr, "sar: lseek failed, errno=%d\n", errno); 841 exit(EXIT_FAILURE); 842 } 843 844 } 845 /* compute data size - malloc a new buf if it's not big enough */ 846 else 847 { 848 /* have to read from the pipe */ 849 if (bufsize < (hdr.rec_count * hdr.rec_size)) 850 { 851 if (buf) 852 free(buf); 853 bufsize = hdr.rec_count * hdr.rec_size; 854 if((buf = (char *)malloc(bufsize)) == NULL) 855 { 856 fprintf(stderr, "sar: malloc failed\n"); 857 return(0); 858 } 859 } 860 /* exits on error */ 861 read_record_data(buf, (hdr.rec_count * hdr.rec_size), FALSE); 862 } 863 } 864 goto restart_loop; 865} 866 867static void 868print_all_column_headings(timestamp) 869 time_t timestamp; 870{ 871 char timebuf[26]; 872 char *timebufp; 873 874 timebufp = get_hms_string (timestamp, timebuf); 875 876 if (uflag) /* print cpu headers */ 877 print_column_heading(SAR_CPU, timebufp, 0); 878 879 if (gflag) /* print page-out activity */ 880 print_column_heading(SAR_VMSTAT, timebufp, 0); 881 882 if (pflag ) /* print page-in activity */ 883 print_column_heading(SAR_VMSTAT, timebufp, 1); 884 885 if (dflag) /* print drive stats */ 886 print_column_heading(SAR_DRIVESTATS, timebufp, 0); 887 888 if (nflag) /* print network stats */ 889 { 890 if (network_mode & NET_DEV_MODE) 891 print_column_heading(SAR_NETSTATS, timebufp, NET_DEV_MODE); 892 893 if (network_mode & NET_EDEV_MODE) 894 print_column_heading(SAR_NETSTATS, timebufp, NET_EDEV_MODE); 895 } 896} 897 898 899/* 900 * Find and fill in a timestamp header. 901 * Write the binary data when looking for SAR_TIMESTAMP 902 * Don't do anything with the data, just read past it. 903 * Return: 1 on success 904 * 0 on failure 905 */ 906static int 907bypass_sample_set (ret_hdr, timestamp) 908 struct record_hdr *ret_hdr; 909 time_t timestamp; 910{ 911 struct record_hdr hdr; 912 int bufsize = 0; 913 char *buf = NULL; 914 915 bypass_loop: 916 read_record_hdr(&hdr, TRUE); /* exits on error */ 917 918 if (hdr.rec_type == SAR_TIMESTAMP) 919 { 920 *ret_hdr = hdr; 921 if (buf) 922 free(buf); 923 return(1); 924 } 925 926 /* 927 * not the record we want... 928 * read past data and try again 929 */ 930 if (hdr.rec_count) 931 { 932 if (fflag && !oflag) 933 { 934 /* 935 * we're reading from a file and we don't have to write the 936 * binary data so seek past data in the file 937 */ 938 errno = 0; 939 if ((lseek(ifd, (hdr.rec_count * hdr.rec_size), SEEK_CUR)) == -1) 940 { 941 /*exit on error */ 942 fprintf(stderr, "sar: lseek failed, errno=%d\n", errno); 943 exit(EXIT_FAILURE); 944 } 945 } 946 else 947 { 948 /* 949 * We end up here when reading from pipe. 950 * malloc a new buffer if current is not big enough 951 */ 952 if (bufsize < (hdr.rec_count * hdr.rec_size)) 953 { 954 if (buf) 955 free(buf); 956 bufsize = hdr.rec_count * hdr.rec_size; 957 if((buf = (char *)malloc(bufsize)) == NULL) 958 { 959 fprintf(stderr, "sar: malloc failed\n"); 960 exit(EXIT_FAILURE); 961 } 962 } 963 964 /* exits on error */ 965 read_record_data(buf, (hdr.rec_count * hdr.rec_size), TRUE); 966 } 967 } /* end if hdr.rec_count */ 968 goto bypass_loop; 969} 970 971 972/* 973 * INIT_SET: This initializes the first sample for each type. 974 * PRINT_SET: This read, compute and print out sample data. 975 */ 976static void 977read_sample_set(flag, timestamp, ret_hdr) 978 int flag; 979 time_t timestamp; 980 struct record_hdr *ret_hdr; 981{ 982 struct record_hdr hdr; 983 char timebuf[26]; 984 char *timebufp; 985 char *indent_string; 986 char *indent_string_wide; 987 char *indent_string_narrow; 988 int sar_cpu = 0; 989 int sar_vmstat=0; 990 int sar_drivestats=0; 991 int sar_drivepath=0; 992 int sar_netstats = 0; 993 994 indent_string_wide = " "; 995 indent_string_narrow = " "; 996 indent_string = indent_string_narrow; 997 998 read_record_hdr(&hdr, TRUE); 999 1000 while (hdr.rec_type != SAR_TIMESTAMP) 1001 { 1002 switch (hdr.rec_type) 1003 { 1004 case SAR_CPU: 1005 sar_cpu = get_cpu_sample(flag, &hdr); 1006 break; 1007 case SAR_VMSTAT: 1008 sar_vmstat=get_vmstat_sample(flag, &hdr); 1009 break; 1010 case SAR_DRIVEPATH: 1011 sar_drivepath = get_drivepath_sample(flag, &hdr); 1012 if (sar_drivepath < 0) 1013 fprintf(stderr, "sar: drivepath sync code error %d\n", sar_drivepath); 1014 break; 1015 case SAR_DRIVESTATS: 1016 sar_drivestats = get_drivestats_sample(flag, &hdr); 1017 break; 1018 case SAR_NETSTATS: 1019 sar_netstats = get_netstats_sample(flag, &hdr); 1020 break; 1021 default: 1022 break; 1023 } 1024 1025 read_record_hdr(&hdr, TRUE); 1026 } 1027 1028 /* return the timestamp header */ 1029 *ret_hdr = hdr; 1030 1031 if (flag == PRINT_SET) 1032 { 1033 avg_counter++; 1034 timebufp = get_hms_string(timestamp, timebuf); 1035 1036 if (uflag && sar_cpu) 1037 print_cpu_sample(timebufp); 1038 1039 if((gflag || pflag) && sar_vmstat) 1040 print_vmstat_sample(timebufp); 1041 1042 if (dflag && sar_drivestats) 1043 print_drivestats_sample(timebufp); 1044 1045 if (nflag && sar_netstats) 1046 print_netstats_sample(timebufp); 1047 } 1048} 1049 1050static void 1051skip_data(bufsize) 1052 int bufsize; 1053{ 1054 char *buf = NULL; 1055 1056 if (fflag) 1057 { 1058 /* seek past data in the file */ 1059 if ((lseek(ifd, bufsize, SEEK_CUR) == -1)) 1060 { 1061 /*exit on error */ 1062 fprintf(stderr, "sar: lseek failed, errno=%d\n", errno); 1063 exit(EXIT_FAILURE); 1064 } 1065 } 1066 else 1067 { 1068 /* have to read from the pipe */ 1069 if((buf = (char *)malloc(bufsize)) == NULL) 1070 { 1071 fprintf(stderr, "sar: malloc failed\n"); 1072 exit(EXIT_FAILURE); 1073 } 1074 /* even though we skip this data, we still write it if necessary */ 1075 read_record_data(buf, bufsize, TRUE); 1076 } 1077 if (buf) 1078 free(buf); 1079 1080 return; 1081} 1082 1083static int 1084get_cpu_sample(flag, hdr) 1085 int flag; 1086 struct record_hdr *hdr; 1087{ 1088 int datasize; 1089 1090 datasize = hdr->rec_count * hdr->rec_size; 1091 1092 if (datasize != sizeof(host_cpu_load_info_data_t)) 1093 { 1094 /* read past the data but don't do anything with it */ 1095 skip_data(datasize); 1096 return(0); 1097 } 1098 1099 read_record_data ((char *)&cur_cpuload, (int)sizeof(host_cpu_load_info_data_t), TRUE ); 1100 1101 if (flag == INIT_SET) 1102 { 1103 prev_cpuload = cur_cpuload; 1104 bzero(&avg_cpuload, sizeof(avg_cpuload)); 1105 } 1106 return(1); 1107} 1108 1109static void 1110print_cpu_sample(timebufptr) 1111 char * timebufptr; 1112{ 1113 1114 double time; 1115 1116 time = 0.0; 1117 cur_cpuload.cpu_ticks[CPU_STATE_USER] 1118 -= prev_cpuload.cpu_ticks[CPU_STATE_USER]; 1119 1120 prev_cpuload.cpu_ticks[CPU_STATE_USER] 1121 += cur_cpuload.cpu_ticks[CPU_STATE_USER]; 1122 1123 time += cur_cpuload.cpu_ticks[CPU_STATE_USER]; 1124 1125 cur_cpuload.cpu_ticks[CPU_STATE_NICE] 1126 -= prev_cpuload.cpu_ticks[CPU_STATE_NICE]; 1127 1128 prev_cpuload.cpu_ticks[CPU_STATE_NICE] 1129 += cur_cpuload.cpu_ticks[CPU_STATE_NICE]; 1130 1131 time += cur_cpuload.cpu_ticks[CPU_STATE_NICE]; 1132 1133 cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM] 1134 -= prev_cpuload.cpu_ticks[CPU_STATE_SYSTEM]; 1135 1136 prev_cpuload.cpu_ticks[CPU_STATE_SYSTEM] 1137 += cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]; 1138 1139 time += cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]; 1140 1141 cur_cpuload.cpu_ticks[CPU_STATE_IDLE] 1142 -= prev_cpuload.cpu_ticks[CPU_STATE_IDLE]; 1143 1144 prev_cpuload.cpu_ticks[CPU_STATE_IDLE] 1145 += cur_cpuload.cpu_ticks[CPU_STATE_IDLE]; 1146 1147 time += cur_cpuload.cpu_ticks[CPU_STATE_IDLE]; 1148 1149 avg_cpuload.cpu_ticks[CPU_STATE_USER] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_USER] 1150 / (time ? time : 1)); 1151 1152 avg_cpuload.cpu_ticks[CPU_STATE_NICE] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_NICE] 1153 / (time ? time : 1)); 1154 1155 avg_cpuload.cpu_ticks[CPU_STATE_SYSTEM] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM] 1156 / (time ? time : 1)); 1157 1158 avg_cpuload.cpu_ticks[CPU_STATE_IDLE] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_IDLE] 1159 / (time ? time : 1)); 1160 1161 if(flag_count > 1) 1162 print_column_heading(SAR_CPU, timebufptr, 0); 1163 1164 fprintf(stdout, "%s%5.0f ", timebufptr, 1165 rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_USER] 1166 / (time ? time : 1))); 1167 1168 fprintf(stdout, "%4.0f ", 1169 rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_NICE] 1170 / (time ? time : 1))); 1171 1172 fprintf(stdout, "%4.0f ", 1173 rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM] 1174 / (time ? time : 1))); 1175 1176 fprintf(stdout, "%4.0f\n", 1177 rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_IDLE] 1178 / (time ? time : 1))); 1179} 1180 1181static int 1182get_vmstat_sample(flag, hdr) 1183 int flag; 1184 struct record_hdr *hdr; 1185{ 1186 int datasize; 1187 1188 datasize = hdr->rec_count * hdr->rec_size; 1189 1190 if (datasize != sizeof(struct vm_statistics)) 1191 { 1192 /* read past the data but don't do anything with it */ 1193 skip_data(datasize); 1194 return(0); 1195 } 1196 1197 read_record_data ((char *)&cur_vmstat, (int)sizeof(struct vm_statistics), TRUE ); 1198 1199 if (flag == INIT_SET) 1200 { 1201 prev_vmstat = cur_vmstat; 1202 bzero(&avg_vmstat, sizeof(avg_vmstat)); 1203 } 1204 return(1); 1205} 1206 1207 1208static void 1209print_vmstat_sample(char *timebufptr) 1210{ 1211 1212 cur_vmstat.faults -= prev_vmstat.faults; 1213 prev_vmstat.faults += cur_vmstat.faults; 1214 avg_vmstat.faults += cur_vmstat.faults; 1215 1216 cur_vmstat.cow_faults -= prev_vmstat.cow_faults; 1217 prev_vmstat.cow_faults += cur_vmstat.cow_faults; 1218 avg_vmstat.cow_faults += cur_vmstat.cow_faults; 1219 1220 cur_vmstat.zero_fill_count -= prev_vmstat.zero_fill_count; 1221 prev_vmstat.zero_fill_count += cur_vmstat.zero_fill_count; 1222 avg_vmstat.zero_fill_count += cur_vmstat.zero_fill_count; 1223 1224 cur_vmstat.reactivations -= prev_vmstat.reactivations; 1225 prev_vmstat.reactivations += cur_vmstat.reactivations; 1226 avg_vmstat.reactivations += cur_vmstat.reactivations; 1227 1228 cur_vmstat.pageins -= prev_vmstat.pageins; 1229 prev_vmstat.pageins += cur_vmstat.pageins; 1230 avg_vmstat.pageins += cur_vmstat.pageins; 1231 1232 cur_vmstat.pageouts -= prev_vmstat.pageouts; 1233 prev_vmstat.pageouts += cur_vmstat.pageouts; 1234 avg_vmstat.pageouts += cur_vmstat.pageouts; 1235 1236 1237 if (gflag) 1238 { 1239 if (flag_count > 1) 1240 print_column_heading(SAR_VMSTAT, timebufptr, 0); 1241 fprintf(stdout, "%s %8.1f \n", timebufptr, (float)((float)cur_vmstat.pageouts/avg_interval)); 1242 } 1243 1244 if (pflag) 1245 { 1246 if (flag_count > 1) 1247 print_column_heading(SAR_VMSTAT, timebufptr, 1); 1248 fprintf(stdout, "%s %8.1f %8.1f %8.1f\n", timebufptr, 1249 (float)((float)cur_vmstat.pageins / avg_interval), 1250 (float)((float)cur_vmstat.cow_faults/avg_interval), 1251 (float)((float)cur_vmstat.faults/avg_interval)); 1252 } 1253 fflush(stdout); 1254} 1255 1256static int 1257get_drivestats_sample(flag, hdr) 1258 int flag; 1259 struct record_hdr *hdr; 1260{ 1261 struct drivestats *databuf; 1262 struct drivestats_report *dr; 1263 size_t datasize; 1264 int datacount; 1265 int index; 1266 int i; 1267 1268 datasize = hdr->rec_count * hdr->rec_size; 1269 datacount = hdr->rec_count; 1270 1271 if (hdr->rec_size != sizeof(struct drivestats)) 1272 { 1273 /* something isn't right... read past the data but don't analyze it */ 1274 skip_data(datasize); 1275 return(0); 1276 } 1277 1278 /* malloc read buffer */ 1279 if ((databuf = (struct drivestats *)malloc(datasize)) == NULL) 1280 { 1281 fprintf(stderr, "sar: malloc failed\n"); 1282 exit (EXIT_FAILURE); 1283 } 1284 1285 bzero(databuf, datasize); 1286 1287 read_record_data ((char *)databuf, datasize, TRUE ); 1288 1289 /* clear all global current fields */ 1290 for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next) 1291 { 1292 dr->present = 0; 1293 dr->cur_Reads = 0; 1294 dr->cur_BytesRead = 0; 1295 dr->cur_Writes = 0; 1296 dr->cur_BytesWritten = 0; 1297 dr->cur_LatentReadTime = 0; 1298 dr->cur_LatentWriteTime = 0; 1299 dr->cur_ReadErrors = 0; 1300 dr->cur_WriteErrors = 0; 1301 dr->cur_ReadRetries = 0; 1302 dr->cur_WriteRetries = 0; 1303 dr->cur_TotalReadTime = 0; 1304 dr->cur_TotalWriteTime=0; 1305 } 1306 1307 /* By this point, we have read in a complete set of diskstats from the sadc 1308 * data collector. 1309 * The order of the drives in not guaranteed. 1310 * The global report structure is a linked list, but may need initialization 1311 * We need to traverse this list and transfer the current 1312 * read data. If a disk entry isn't found, then we need to allocate one 1313 * initilize it. 1314 */ 1315 for (i=0; i< datacount; i++) 1316 { 1317 struct drivestats_report *dr_last = NULL; 1318 1319 index = databuf[i].drivepath_id; /* use this as index into dp_table */ 1320 1321 /* find disk entry or allocate new one*/ 1322 for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next) 1323 { 1324 dr_last = dr; 1325 if(index == dr->drivepath_id) 1326 break; 1327 } 1328 1329 if (dr == NULL) 1330 { 1331 /* allocate new entry */ 1332 if((dr = (struct drivestats_report *)malloc(sizeof(struct drivestats_report))) == NULL) 1333 { 1334 fprintf(stderr, "sar: malloc error\n"); 1335 exit(EXIT_FAILURE); 1336 } 1337 bzero((char *)dr, sizeof(struct drivestats_report)); 1338 dr->blocksize = databuf[i].blocksize; 1339 dr->drivepath_id = index; 1340 dr->next = NULL; 1341 dr->avg_count = 0; 1342 1343 /* get the BSDName which should be in the table by now */ 1344 if ((index < dp_count) && (dp_table[index].state != DPSTATE_UNINITIALIZED)) 1345 strncpy(dr->name, dp_table[index].BSDName, MAXDRIVENAME+1); 1346 else 1347 strcpy(dr->name, "disk??"); 1348 1349 if (dr_head == NULL) 1350 { 1351 dr_head = dr; 1352 dr_head->next = NULL; 1353 } 1354 else 1355 { 1356 dr_last->next = (char *)dr; 1357 } 1358 } /* end if dr == NULL */ 1359 1360 dr->present = TRUE; 1361 dr->cur_Reads = databuf[i].Reads; 1362 dr->cur_BytesRead = databuf[i].BytesRead; 1363 dr->cur_Writes = databuf[i].Writes; 1364 dr->cur_BytesWritten = databuf[i].BytesWritten; 1365 dr->cur_LatentReadTime = databuf[i].LatentReadTime; 1366 dr->cur_LatentWriteTime = databuf[i].LatentWriteTime; 1367 dr->cur_ReadErrors = databuf[i].ReadErrors; 1368 dr->cur_WriteErrors = databuf[i].WriteErrors; 1369 dr->cur_ReadRetries = databuf[i].ReadRetries; 1370 dr->cur_WriteRetries = databuf[i].WriteRetries; 1371 dr->cur_TotalReadTime = databuf[i].TotalReadTime; 1372 dr->cur_TotalWriteTime=databuf[i].TotalWriteTime; 1373 } /* end for loop */ 1374 1375 /* Reinitialize the prev and avg fields when 1376 * This is a new disk 1377 * This is a changed disk - name change implies disk swapping 1378 * This disk is not present in this sample 1379 */ 1380 for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next) 1381 { 1382 if (dr->drivepath_id >= dp_count) 1383 { 1384 /* something is amiss */ 1385 continue; 1386 } 1387 else 1388 { 1389 index = dr->drivepath_id; /* use this as index into dp_table */ 1390 } 1391 1392 if ((flag == INIT_SET) || 1393 (dp_table[index].state == DPSTATE_NEW) || 1394 (dp_table[index].state == DPSTATE_CHANGED) || 1395 (!dr->present)) 1396 { 1397 /* 1398 * prev will be set to cur 1399 * activate the state in dp_table 1400 */ 1401 if (dr->present) 1402 dp_table[index].state = DPSTATE_ACTIVE; 1403 1404 init_drivestats(dr); 1405 } 1406 } 1407 return(1); 1408} 1409 1410static void 1411init_drivestats(struct drivestats_report *dr) 1412{ 1413 dr->avg_count = 0; 1414 dr->prev_Reads = dr->cur_Reads; 1415 dr->avg_Reads = 0; 1416 dr->prev_BytesRead = dr->cur_BytesRead; 1417 dr->avg_BytesRead = 0; 1418 dr->prev_Writes = dr->cur_Writes; 1419 dr->avg_Writes = 0; 1420 dr->prev_BytesWritten = dr->cur_BytesWritten; 1421 dr->avg_BytesWritten = 0; 1422 dr->prev_LatentReadTime = dr->cur_LatentReadTime; 1423 dr->avg_LatentReadTime = 0; 1424 dr->prev_LatentWriteTime = dr->cur_LatentWriteTime ; 1425 dr->avg_LatentWriteTime = 0; 1426 dr->prev_ReadErrors = dr->cur_ReadErrors ; 1427 dr->avg_ReadErrors = 0; 1428 dr->prev_WriteErrors = dr->cur_WriteErrors ; 1429 dr->avg_WriteErrors = 0; 1430 dr->prev_ReadRetries = dr->cur_ReadRetries ; 1431 dr->avg_ReadRetries = 0; 1432 dr->prev_WriteRetries = dr->cur_WriteRetries ; 1433 dr->avg_WriteRetries = 0; 1434 dr->prev_TotalReadTime = dr->cur_TotalReadTime ; 1435 dr->avg_TotalReadTime = 0; 1436 dr->prev_TotalWriteTime = dr->cur_TotalWriteTime ; 1437 dr->avg_TotalWriteTime = 0; 1438} 1439 1440 1441static void 1442print_drivestats_sample(char *timebufptr) 1443{ 1444 struct drivestats_report *dr; 1445 long double transfers_per_second; 1446 long double kb_per_transfer, mb_per_second; 1447 u_int64_t interval_bytes, interval_transfers, interval_blocks; 1448 u_int64_t interval_time; 1449 long double blocks_per_second, ms_per_transaction; 1450 1451 if (flag_count > 1) 1452 print_column_heading(SAR_DRIVESTATS, timebufptr, 0); 1453 1454 for (dr=dr_head; dr; dr=(struct drivestats_report *)dr->next) 1455 { 1456 if(!dr->present) 1457 continue; 1458 1459 /* 1460 * This sanity check is for drives that get removed and then 1461 * returned during the sampling sleep interval. If anything 1462 * looks out of sync, reinit and skip this entry. There is 1463 * no way to guard against this entirely. 1464 */ 1465 if ((dr->cur_Reads < dr->prev_Reads) || 1466 (dr->cur_BytesRead < dr->prev_BytesRead) || 1467 (dr->cur_Writes < dr->prev_Writes) || 1468 (dr->cur_BytesWritten < dr->prev_BytesWritten)) 1469 { 1470 init_drivestats(dr); 1471 continue; 1472 } 1473 1474 dr->avg_count++; 1475 1476 dr->cur_Reads -= dr->prev_Reads; 1477 dr->prev_Reads += dr->cur_Reads; 1478 dr->avg_Reads += dr->cur_Reads; 1479 1480 dr->cur_BytesRead -= dr->prev_BytesRead; 1481 dr->prev_BytesRead += dr->cur_BytesRead; 1482 dr->avg_BytesRead += dr->cur_BytesRead; 1483 1484 dr->cur_Writes -= dr->prev_Writes ; 1485 dr->prev_Writes += dr->cur_Writes ; 1486 dr->avg_Writes += dr->cur_Writes ; 1487 1488 dr->cur_BytesWritten -= dr->prev_BytesWritten ; 1489 dr->prev_BytesWritten += dr->cur_BytesWritten ; 1490 dr->avg_BytesWritten += dr->cur_BytesWritten ; 1491 1492 dr->cur_LatentReadTime -= dr->prev_LatentReadTime ; 1493 dr->prev_LatentReadTime += dr->cur_LatentReadTime ; 1494 dr->avg_LatentReadTime += dr->cur_LatentReadTime ; 1495 1496 dr->cur_LatentWriteTime -= dr->prev_LatentWriteTime ; 1497 dr->prev_LatentWriteTime += dr->cur_LatentWriteTime ; 1498 dr->avg_LatentWriteTime += dr->cur_LatentWriteTime ; 1499 1500 dr->cur_ReadErrors -= dr->prev_ReadErrors ; 1501 dr->prev_ReadErrors += dr->cur_ReadErrors ; 1502 dr->avg_ReadErrors += dr->cur_ReadErrors ; 1503 1504 dr->cur_WriteErrors -= dr->prev_WriteErrors ; 1505 dr->prev_WriteErrors += dr->cur_WriteErrors ; 1506 dr->avg_WriteErrors += dr->cur_WriteErrors ; 1507 1508 dr->cur_ReadRetries -= dr->prev_ReadRetries ; 1509 dr->prev_ReadRetries += dr->cur_ReadRetries ; 1510 dr->avg_ReadRetries += dr->cur_ReadRetries ; 1511 1512 dr->cur_WriteRetries -= dr->prev_WriteRetries ; 1513 dr->prev_WriteRetries += dr->cur_WriteRetries; 1514 dr->avg_WriteRetries += dr->cur_WriteRetries; 1515 1516 dr->cur_TotalReadTime -= dr->prev_TotalReadTime ; 1517 dr->prev_TotalReadTime += dr->cur_TotalReadTime ; 1518 dr->avg_TotalReadTime += dr->cur_TotalReadTime ; 1519 1520 dr->cur_TotalWriteTime -= dr->prev_TotalWriteTime ; 1521 dr->prev_TotalWriteTime += dr->cur_TotalWriteTime ; 1522 dr->avg_TotalWriteTime += dr->cur_TotalWriteTime ; 1523 1524 /* I/O volume */ 1525 interval_bytes = dr->cur_BytesRead + dr->cur_BytesWritten; 1526 1527 /* I/O counts */ 1528 interval_transfers = dr->cur_Reads + dr->cur_Writes; 1529 1530 /* I/O time */ 1531 interval_time = dr->cur_LatentReadTime + dr->cur_LatentWriteTime; 1532 1533 interval_blocks = interval_bytes / dr->blocksize; 1534 blocks_per_second = interval_blocks / avg_interval; 1535 transfers_per_second = interval_transfers / avg_interval; 1536 mb_per_second = (interval_bytes / avg_interval) / (1024 *1024); 1537 1538 kb_per_transfer = (interval_transfers > 0) ? 1539 ((long double)interval_bytes / interval_transfers) 1540 / 1024 : 0; 1541 1542 /* times are in nanoseconds, convert to milliseconds */ 1543 ms_per_transaction = (interval_transfers > 0) ? 1544 ((long double)interval_time / interval_transfers) 1545 / 1000 : 0; 1546 1547 /* print device name */ 1548 fprintf(stdout, "%s %-10s", timebufptr, dr->name); 1549 1550 /* print transfers per second */ 1551 fprintf(stdout, "%4.0Lf ", transfers_per_second); 1552 1553 /* print blocks per second - in device blocksize */ 1554 fprintf(stdout, "%4.0Lf\n", blocks_per_second); 1555 } 1556} 1557 1558/* 1559 * Print averages before exiting. 1560 */ 1561static void 1562exit_average() 1563{ 1564 int i; 1565 1566 if (avg_counter <= 0 ) 1567 exit(0); 1568 1569 if (oflag) 1570 { 1571 if (ofd) 1572 close (ofd); 1573 ofd = 0; 1574 } 1575 1576 if (uflag) /* print cpu averages */ 1577 { 1578 if(flag_count > 1) 1579 print_column_heading(SAR_CPU, 0, 0); 1580 1581 fprintf(stdout, "Average: %5d ", 1582 (int)avg_cpuload.cpu_ticks[CPU_STATE_USER] 1583 / (avg_counter ? avg_counter : 1)); 1584 1585 fprintf(stdout, "%4d ", 1586 (int)avg_cpuload.cpu_ticks[CPU_STATE_NICE] 1587 / (avg_counter ? avg_counter : 1)); 1588 1589 fprintf(stdout, "%4d ", 1590 (int)avg_cpuload.cpu_ticks[CPU_STATE_SYSTEM] 1591 / (avg_counter ? avg_counter : 1)); 1592 1593 fprintf(stdout, "%4d \n", 1594 (int)avg_cpuload.cpu_ticks[CPU_STATE_IDLE] 1595 / (avg_counter ? avg_counter : 1)); 1596 1597 fflush(stdout); 1598 } 1599 1600 1601 if (gflag) /* print page-out averages */ 1602 { 1603 if (flag_count > 1) 1604 print_column_heading(SAR_VMSTAT, 0, 0); 1605 1606 fprintf(stdout, "Average: %8.1f\n", 1607 (float)((avg_vmstat.pageouts / (avg_counter ? avg_counter : 1)) / avg_interval)); 1608 fflush(stdout); 1609 } 1610 1611 if (pflag) /* print page-in averages */ 1612 { 1613 if (flag_count > 1) 1614 print_column_heading(SAR_VMSTAT, 0, 1); 1615 1616 fprintf(stdout, "Average: %8.1f %8.1f %8.1f\n", 1617 (float)(((float)avg_vmstat.pageins / (avg_counter ? avg_counter : 1)) / avg_interval), 1618 (float)(((float)avg_vmstat.cow_faults / (avg_counter ? avg_counter : 1)) / avg_interval), 1619 (float)(((float)avg_vmstat.faults / (avg_counter ? avg_counter : 1)) / avg_interval)); 1620 fflush(stdout); 1621 } 1622 1623 if (dflag) /* print drivestats averages */ 1624 { 1625 struct drivestats_report *dr; 1626 long double transfers_per_second; 1627 long double kb_per_transfer, mb_per_second; 1628 u_int64_t total_bytes, total_transfers, total_blocks; 1629 u_int64_t total_time; 1630 long double blocks_per_second, ms_per_transaction; 1631 int msdig; 1632 1633 if (flag_count > 1) 1634 print_column_heading(SAR_DRIVESTATS, 0, 0); 1635 1636 for (dr=dr_head; dr; dr=(struct drivestats_report *)dr->next) 1637 { 1638 /* don't bother to print out averages for disks that were removed */ 1639 if (!dr->present) 1640 continue; 1641 1642 fprintf(stdout, " %s %s\n", 1643 dp_table[dr->drivepath_id].BSDName, dp_table[dr->drivepath_id].ioreg_path); 1644 1645 /* I/O volume */ 1646 total_bytes = dr->avg_BytesRead + dr->avg_BytesWritten; 1647 1648 /* I/O counts */ 1649 total_transfers = dr->avg_Reads + dr->avg_Writes; 1650 1651 /* I/O time */ 1652 total_time = dr->avg_LatentReadTime + dr->avg_LatentWriteTime; 1653 1654 total_blocks = total_bytes / dr->blocksize; 1655 blocks_per_second = total_blocks / avg_interval; 1656 transfers_per_second = total_transfers / avg_interval; 1657 mb_per_second = (total_bytes / avg_interval) / (1024 *1024); 1658 1659 kb_per_transfer = (total_transfers > 0) ? 1660 ((long double)total_bytes / total_transfers) 1661 / 1024 : 0; 1662 1663 /* times are in nanoseconds, convert to milliseconds */ 1664 ms_per_transaction = (total_transfers > 0) ? 1665 ((long double)total_time / total_transfers) 1666 / 1000 : 0; 1667 msdig = (ms_per_transaction < 100.0) ? 1 : 0; 1668 fprintf(stdout, "Average: %-10s %4.0Lf %4.0Lf\n", 1669 dr->name, 1670 (transfers_per_second / dr->avg_count), 1671 (blocks_per_second / dr->avg_count)); 1672 1673 fflush(stdout); 1674 } 1675 } /* end if dflag */ 1676 1677 if (nflag) 1678 { 1679 int avg_count; 1680 1681 if (network_mode & NET_DEV_MODE) 1682 { 1683 if (flag_count > 1) 1684 print_column_heading(SAR_NETSTATS, 0, NET_DEV_MODE); 1685 for (i = 0; i < nr_count; i++) 1686 { 1687 if (!nr_table[i].valid) 1688 continue; 1689 1690 if(nr_table[i].avg_count == 0) 1691 avg_count = 1; 1692 else 1693 avg_count = nr_table[i].avg_count; 1694 1695 fprintf(stdout, "Average: %-8.8s", nr_table[i].tname_unit); 1696 1697 fprintf (stdout, "%8llu ", 1698 ((nr_table[i].avg_ipackets / avg_count) / avg_interval)); 1699 1700 fprintf (stdout, "%10llu ", 1701 ((nr_table[i].avg_ibytes / avg_count) / avg_interval)); 1702 1703 fprintf (stdout, "%8llu ", 1704 ((nr_table[i].avg_opackets / avg_count) / avg_interval)); 1705 1706 fprintf (stdout, "%10llu\n", 1707 ((nr_table[i].avg_obytes / avg_count) / avg_interval)); 1708 1709 fflush(stdout); 1710 } 1711 } 1712 1713 if (network_mode & NET_EDEV_MODE) 1714 { 1715 1716 if(flag_count > 1) 1717 print_column_heading(SAR_NETSTATS, 0, NET_EDEV_MODE); 1718 1719 for (i = 0; i < nr_count; i++) 1720 { 1721 if (!nr_table[i].valid) 1722 continue; 1723 1724 if(nr_table[i].avg_count == 0) 1725 avg_count = 1; 1726 else 1727 avg_count = nr_table[i].avg_count; 1728 1729 fprintf(stdout, "Average: %-8.8s ", nr_table[i].tname_unit); 1730 1731 fprintf (stdout, "%7llu ", 1732 ((nr_table[i].avg_ierrors / avg_count) / avg_interval)); 1733 1734 fprintf (stdout, "%7llu ", 1735 ((nr_table[i].avg_oerrors / avg_count) / avg_interval)); 1736 1737 fprintf (stdout, "%5llu ", 1738 ((nr_table[i].avg_collisions / avg_count) / avg_interval)); 1739 1740 fprintf (stdout, " %5llu\n", 1741 ((nr_table[i].avg_drops / avg_count) / avg_interval)); 1742 1743 fflush(stdout); 1744 } 1745 } 1746 1747 } /* end if nflag */ 1748 exit(0); 1749} 1750 1751 1752/* 1753 * Return < 0 failure, debugging purposes only 1754 * Return = 0 data skipped 1755 * Return > 0 success 1756 */ 1757 1758static int 1759get_drivepath_sample(flag, hdr) 1760 int flag; 1761 struct record_hdr *hdr; 1762{ 1763 size_t datasize; 1764 struct drivepath dp; 1765 struct drivestats_report *dr; 1766 int i, n; 1767 1768 datasize = hdr->rec_count * hdr->rec_size; 1769 1770 if (datasize != sizeof(struct drivepath)) 1771 { 1772 /* read past the data but don't do anything with it */ 1773 skip_data(datasize); 1774 return(0); 1775 } 1776 1777 read_record_data ((char *)&dp, (int)sizeof(struct drivepath), TRUE ); 1778 1779 /* 1780 * If state is new -- put a new entry in the dp_table. 1781 * If state is changed -- traverse the drivestats_report table 1782 * and copy new name. 1783 */ 1784 if (dp.state == DPSTATE_NEW) 1785 { 1786 1787 if (dp_table == NULL) 1788 { 1789 if (dp.drivepath_id != 0) 1790 return(-1); 1791 /* First setup of internal drivepath table */ 1792 dp_table = (struct drivepath *)malloc(sizeof(struct drivepath)); 1793 if (dp_table == NULL) 1794 return(-2); 1795 dp_count = 1; 1796 } 1797 1798 if (dflag) 1799 fprintf(stdout, "New Disk: [%s] %s\n", dp.BSDName, dp.ioreg_path); 1800 1801 /* traverse table and find next uninitialized entry */ 1802 for (i = 0; i< dp_count; i++) 1803 { 1804 if (dp_table[i].state == DPSTATE_UNINITIALIZED) 1805 { 1806 if (dp.drivepath_id != i) 1807 { 1808 /* the table is out of sync - this should not happen */ 1809 return (-3); 1810 } 1811 dp_table[i] = dp; 1812 return(1); 1813 } 1814 } 1815 /* 1816 * If we get here, we've run out of table entries. 1817 * Double the size of the table, then assign the next entry. 1818 */ 1819 if (dp.drivepath_id != i) 1820 { 1821 /* the table is out of sync - this should not happen */ 1822 return (-4); 1823 } 1824 n = dp_count * 2; 1825 dp_table = (struct drivepath *)realloc(dp_table, n * sizeof(struct drivepath)); 1826 bzero(&dp_table[dp_count], dp_count * sizeof(struct drivepath)); 1827 dp_table[dp_count] = dp; 1828 dp_count = n; 1829 return(1); 1830 1831 } 1832 else if (dp.state == DPSTATE_CHANGED) 1833 { 1834 1835 /* Update the name in the table */ 1836 if ((dp.drivepath_id < dp_count) && (dp_table[dp.drivepath_id].state != DPSTATE_UNINITIALIZED)) 1837 { 1838 if (strcmp(dp_table[dp.drivepath_id].ioreg_path, dp.ioreg_path) != 0) 1839 { 1840 /* something is amiss */ 1841 return (-5); 1842 } 1843 else 1844 { 1845 if (dflag) 1846 { 1847 fprintf(stdout, "Change: [%s] %s\n", dp.BSDName, 1848 dp_table[dp.drivepath_id].ioreg_path); 1849 } 1850 strcpy(dp_table[dp.drivepath_id].BSDName, dp.BSDName); 1851 1852 for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next) 1853 { 1854 if (dr->drivepath_id == dp.drivepath_id) 1855 strcpy(dr->name, dp.BSDName); 1856 } 1857 return(1); 1858 } 1859 } 1860 else 1861 return(-6); 1862 } 1863 return(-7); 1864} 1865 1866/* 1867 * Bytes and packet counts are used to track 1868 * counter wraps. So, don't enforce the 1869 * NET_DEV_MODE or NET_EDEV_MODE in here. 1870 * Maintain all the stats. 1871 */ 1872static void 1873set_cur_netstats(struct netstats_report *nr, struct netstats *ns) 1874{ 1875 1876 nr->cur_ipackets = ns->net_ipackets; 1877 nr->cur_ibytes = ns->net_ibytes; 1878 nr->cur_opackets = ns->net_opackets; 1879 nr->cur_obytes = ns->net_obytes; 1880 1881 nr->cur_ierrors = ns->net_ierrors; 1882 nr->cur_oerrors = ns->net_oerrors; 1883 nr->cur_collisions = ns->net_collisions; 1884 nr->cur_drops = ns->net_drops; 1885 1886 nr->cur_imcasts = ns->net_imcasts; 1887 nr->cur_omcasts = ns->net_omcasts; 1888 1889} 1890 1891static void 1892init_prev_netstats(struct netstats_report *nr) 1893{ 1894 nr->avg_count = 0; 1895 nr->valid = 1; 1896 nr->present = 1; 1897 1898 nr->prev_ipackets = nr->cur_ipackets; 1899 nr->avg_ipackets = 0; 1900 nr->prev_ibytes = nr->cur_ibytes; 1901 nr->avg_ibytes = 0; 1902 nr->prev_opackets = nr->cur_opackets; 1903 nr->avg_opackets = 0; 1904 nr->prev_obytes = nr->cur_obytes; 1905 nr->avg_obytes = 0; 1906 1907 nr->prev_ierrors = nr->cur_ierrors; 1908 nr->avg_ierrors = 0; 1909 nr->prev_oerrors = nr->cur_oerrors ; 1910 nr->avg_oerrors = 0; 1911 nr->prev_collisions = nr->cur_collisions ; 1912 nr->avg_collisions = 0; 1913 nr->prev_drops = nr->cur_drops ; 1914 nr->avg_drops = 0; 1915 1916 /* track these, but never displayed */ 1917 nr->prev_imcasts = nr->cur_imcasts; 1918 nr->avg_imcasts = 0; 1919 nr->prev_omcasts = nr->cur_omcasts; 1920 nr->avg_omcasts = 0; 1921} 1922 1923/* 1924 * Success : 1 1925 * Failure : 0 1926 */ 1927static int 1928get_netstats_sample(flag, hdr) 1929 int flag; 1930 struct record_hdr *hdr; 1931{ 1932 struct netstats *databuf = NULL; 1933 size_t datasize; 1934 int datacount; 1935 int i, j; 1936 1937 datasize = hdr->rec_count * hdr->rec_size; 1938 datacount = hdr->rec_count; 1939 1940 if (hdr->rec_size != sizeof(struct netstats)) 1941 { 1942 /* something isn't right... read past the data but don't analyze it */ 1943 skip_data(datasize); 1944 return(0); 1945 } 1946 1947 /* malloc new or bigger read buffer */ 1948 if((netstat_readbuf == NULL) || (netstat_readbuf_size < datasize)) 1949 { 1950 if (netstat_readbuf) 1951 free (netstat_readbuf); 1952 1953 if ((netstat_readbuf = (struct netstats *)malloc(datasize)) == NULL) 1954 { 1955 fprintf(stderr, "sar: malloc failed\n"); 1956 exit (EXIT_FAILURE); 1957 } 1958 netstat_readbuf_size = datasize; 1959 } 1960 1961 bzero(netstat_readbuf, netstat_readbuf_size); 1962 databuf = netstat_readbuf; 1963 1964 read_record_data ((char *)databuf, datasize, TRUE ); 1965 1966 if (nr_table == NULL) 1967 { 1968 /* initial internal table setup */ 1969 nr_table = (struct netstats_report *)malloc(datacount * sizeof(struct netstats_report)); 1970 nr_count = datacount; 1971 bzero(nr_table, (datacount * sizeof(struct netstats_report))); 1972 1973 /* on first init, this is faster than finding our way to NEW_ENTRY */ 1974 for (i = 0; i < datacount; i++) 1975 { 1976 if (!(network_mode & NET_PPP_MODE)) 1977 { 1978 if (!strncmp(databuf[i].tname_unit, "ppp", 3)) 1979 continue; /* 1980 * Skip ppp interfaces. 1981 * ie don't even put them in this internal table. 1982 */ 1983 } 1984 strncpy(nr_table[i].tname_unit, databuf[i].tname_unit, MAX_TNAME_UNIT_SIZE); 1985 nr_table[i].tname_unit[MAX_TNAME_UNIT_SIZE] = '\0'; 1986 set_cur_netstats(&nr_table[i], &databuf[i]); 1987 init_prev_netstats(&nr_table[i]); 1988 } 1989 return(1); 1990 } 1991 1992 /* 1993 * clear all the present flags. 1994 * As we traverse the current sample set 1995 * and update the internal table, the flag 1996 * is reset. 1997 */ 1998 for (i = 0; i < nr_count; i++) 1999 { 2000 nr_table[i].present = 0; 2001 } 2002 2003 /* 2004 * Find and update table entries. 2005 * Init new entries. 2006 */ 2007 for (i=0; i<datacount; i++) 2008 { 2009 int found; 2010 char *name; 2011 int nr_index; 2012 int n; 2013 2014 name = databuf[i].tname_unit; 2015 found = 0; 2016 2017 if (!(network_mode & NET_PPP_MODE)) 2018 { 2019 if (!strncmp(name, "ppp", 3)) 2020 continue; /* skip ppp interfaces */ 2021 } 2022 2023 /* Find the matching entry using the interface name */ 2024 for (j=0; j < nr_count && !found; j++) 2025 { 2026 if (nr_table[j].valid) 2027 { 2028 if(!strcmp(nr_table[j].tname_unit, name)) 2029 { 2030 found = 1; 2031 nr_table[j].present = 1; 2032 set_cur_netstats(&nr_table[j], &databuf[i]); 2033 } 2034 } 2035 } /* end for */ 2036 2037 if (!found) /* this is a new entry */ 2038 { 2039 /* Find an invalid entry in the table and init it */ 2040 for (j=0; j < nr_count; j++) 2041 { 2042 if (!nr_table[j].valid) 2043 { 2044 nr_index = j; 2045 goto NEW_ENTRY; 2046 } 2047 } 2048 2049 /* we ran out of entries... grow the table */ 2050 n = nr_count * 2; 2051 nr_table = (struct netstats_report *)realloc(nr_table, n * sizeof(struct netstats_report)); 2052 bzero(&nr_table[nr_count], nr_count * sizeof (struct netstats_report)); 2053 nr_index = nr_count; 2054 nr_count = n; 2055 2056 NEW_ENTRY: 2057 strncpy(nr_table[nr_index].tname_unit, databuf[i].tname_unit, MAX_TNAME_UNIT_SIZE); 2058 nr_table[nr_index].tname_unit[MAX_TNAME_UNIT_SIZE] = '\0'; 2059 set_cur_netstats(&nr_table[nr_index], &databuf[i]); 2060 init_prev_netstats(&nr_table[nr_index]); 2061 } 2062 2063 } /* end for */ 2064 2065 /* 2066 * Traverse the internal table. Any valid entry that wasn't 2067 * present in this sample is cleared for reuse. 2068 */ 2069 for (i = 0; i < nr_count; i++) 2070 { 2071 if (nr_table[i].valid) 2072 { 2073 if (nr_table[i].present == 0) 2074 bzero(&nr_table[i], sizeof(struct netstats_report)); 2075 } 2076 } 2077 return (1); 2078} 2079 2080static void 2081print_netstats_sample(char *timebufptr) 2082{ 2083 int i; 2084 2085 for (i=0; i < nr_count; i++) 2086 { 2087 if (!nr_table[i].valid) 2088 continue; 2089 2090 /* 2091 * This is where we attempt to handle counters that 2092 * might wrap ... the kernel netstats are only 32 bits. 2093 * 2094 * Interfaces may go away and then return within the 2095 * sampling period. This can't be detected and it 2096 * may look like a counter wrap. An interface generation 2097 * counter will help... but isn't implemented at this time. 2098 */ 2099 2100 /* 2101 * The ppp interfaces are very likely to come and go during 2102 * a sampling period. During the normal life of a ppp interface, 2103 * it's less likely that the packet counter will wrap, so if 2104 * it appears to have done so, is probably because the 2105 * interface unit number has been reused. 2106 * We reinitialize that interface in that case. 2107 */ 2108 if (network_mode & NET_PPP_MODE) 2109 { 2110 /* 2111 * ppp interfaces won't even make it into this table 2112 * when NET_PPP_MODE isn't set 2113 */ 2114 if (!strncmp(nr_table[i].tname_unit, "ppp", 3)) 2115 { 2116 /* 2117 * Both ipackets and opackets have to be less 2118 * than the previous counter to cause us to reinit. 2119 */ 2120 2121 if ((nr_table[i].cur_ipackets < nr_table[i].prev_ipackets) 2122 && (nr_table[i].cur_opackets < nr_table[i].prev_opackets)) 2123 { 2124 init_prev_netstats(&nr_table[i]); 2125 continue; 2126 } 2127 } 2128 } 2129 2130 nr_table[i].avg_count ++; 2131 2132#ifdef IFNET_32_BIT_COUNTERS 2133 while (nr_table[i].cur_ipackets < nr_table[i].prev_ipackets) 2134 nr_table[i].cur_ipackets += 0x100000000LL; 2135#endif /* IFNET_32_BIT_COUNTERS */ 2136 nr_table[i].cur_ipackets -= nr_table[i].prev_ipackets; 2137 nr_table[i].prev_ipackets += nr_table[i].cur_ipackets; 2138 nr_table[i].avg_ipackets += nr_table[i].cur_ipackets; 2139 2140 2141#ifdef IFNET_32_BIT_COUNTERS 2142 while (nr_table[i].cur_ibytes < nr_table[i].prev_ibytes) 2143 nr_table[i].cur_ibytes += 0x100000000LL; 2144#endif /* IFNET_32_BIT_COUNTERS */ 2145 nr_table[i].cur_ibytes -= nr_table[i].prev_ibytes; 2146 nr_table[i].prev_ibytes += nr_table[i].cur_ibytes; 2147 nr_table[i].avg_ibytes += nr_table[i].cur_ibytes; 2148 2149 2150#ifdef IFNET_32_BIT_COUNTERS 2151 while (nr_table[i].cur_opackets < nr_table[i].prev_opackets) 2152 nr_table[i].cur_opackets += 0x100000000LL; 2153#endif /* IFNET_32_BIT_COUNTERS */ 2154 nr_table[i].cur_opackets -= nr_table[i].prev_opackets; 2155 nr_table[i].prev_opackets += nr_table[i].cur_opackets; 2156 nr_table[i].avg_opackets += nr_table[i].cur_opackets; 2157 2158#ifdef IFNET_32_BIT_COUNTERS 2159 while (nr_table[i].cur_obytes < nr_table[i].prev_obytes) 2160 nr_table[i].cur_obytes += 0x100000000LL; 2161#endif /* IFNET_32_BIT_COUNTERS */ 2162 nr_table[i].cur_obytes -= nr_table[i].prev_obytes; 2163 nr_table[i].prev_obytes += nr_table[i].cur_obytes; 2164 nr_table[i].avg_obytes += nr_table[i].cur_obytes; 2165 2166 2167#ifdef IFNET_32_BIT_COUNTERS 2168 while (nr_table[i].cur_ierrors < nr_table[i].prev_ierrors) 2169 nr_table[i].cur_ierrors += 0x100000000LL; 2170#endif /* IFNET_32_BIT_COUNTERS */ 2171 nr_table[i].cur_ierrors -= nr_table[i].prev_ierrors; 2172 nr_table[i].prev_ierrors += nr_table[i].cur_ierrors; 2173 nr_table[i].avg_ierrors += nr_table[i].cur_ierrors; 2174 2175#ifdef IFNET_32_BIT_COUNTERS 2176 while (nr_table[i].cur_oerrors < nr_table[i].prev_oerrors) 2177 nr_table[i].cur_oerrors += 0x100000000LL; 2178#endif /* IFNET_32_BIT_COUNTERS */ 2179 nr_table[i].cur_oerrors -= nr_table[i].prev_oerrors; 2180 nr_table[i].prev_oerrors += nr_table[i].cur_oerrors; 2181 nr_table[i].avg_oerrors += nr_table[i].cur_oerrors; 2182 2183#ifdef IFNET_32_BIT_COUNTERS 2184 while (nr_table[i].cur_collisions < nr_table[i].prev_collisions) 2185 nr_table[i].cur_collisions += 0x100000000LL; 2186#endif /* IFNET_32_BIT_COUNTERS */ 2187 nr_table[i].cur_collisions -= nr_table[i].prev_collisions; 2188 nr_table[i].prev_collisions += nr_table[i].cur_collisions; 2189 nr_table[i].avg_collisions += nr_table[i].cur_collisions; 2190 2191#ifdef IFNET_32_BIT_COUNTERS 2192 while (nr_table[i].cur_drops < nr_table[i].prev_drops) 2193 nr_table[i].cur_drops += 0x100000000LL; 2194#endif /* IFNET_32_BIT_COUNTERS */ 2195 nr_table[i].cur_drops -= nr_table[i].prev_drops; 2196 nr_table[i].prev_drops += nr_table[i].cur_drops; 2197 nr_table[i].avg_drops += nr_table[i].cur_drops; 2198 2199 2200#ifdef IFNET_32_BIT_COUNTERS 2201 while (nr_table[i].cur_imcasts < nr_table[i].prev_imcasts) 2202 nr_table[i].cur_imcasts += 0x100000000LL; 2203#endif /* IFNET_32_BIT_COUNTERS */ 2204 nr_table[i].cur_imcasts -= nr_table[i].prev_imcasts; 2205 nr_table[i].prev_imcasts += nr_table[i].cur_imcasts; 2206 nr_table[i].avg_imcasts += nr_table[i].cur_imcasts; 2207 2208#ifdef IFNET_32_BIT_COUNTERS 2209 while (nr_table[i].cur_omcasts < nr_table[i].prev_omcasts) 2210 nr_table[i].cur_omcasts += 0x100000000LL; 2211#endif /* IFNET_32_BIT_COUNTERS */ 2212 nr_table[i].cur_omcasts -= nr_table[i].prev_omcasts; 2213 nr_table[i].prev_omcasts += nr_table[i].cur_omcasts; 2214 nr_table[i].avg_omcasts += nr_table[i].cur_omcasts; 2215 } 2216 2217 2218 if (!(flag_count > 1)) 2219 fprintf(stdout, "\n"); 2220 2221 if (network_mode & NET_DEV_MODE) 2222 { 2223 if (flag_count > 1) 2224 print_column_heading(SAR_NETSTATS, timebufptr, NET_DEV_MODE); 2225 2226 for (i=0; i < nr_count; i++) 2227 { 2228 if (!nr_table[i].valid) 2229 continue; 2230 2231 if (!(network_mode & NET_PPP_MODE)) 2232 { 2233 if (!strncmp(nr_table[i].tname_unit, "ppp", 3)) 2234 { 2235 continue; /* skip any ppp interfaces */ 2236 } 2237 } 2238 2239 /* print the interface name */ 2240 fprintf(stdout, "%s %-8.8s", timebufptr, nr_table[i].tname_unit); 2241 2242 fprintf (stdout, "%8llu ", 2243 (nr_table[i].cur_ipackets / avg_interval)); 2244 2245 fprintf (stdout, "%10llu ", 2246 (nr_table[i].cur_ibytes / avg_interval)); 2247 2248 fprintf (stdout, "%8llu ", 2249 (nr_table[i].cur_opackets / avg_interval)); 2250 2251 fprintf (stdout, "%10llu\n", 2252 (nr_table[i].cur_obytes / avg_interval)); 2253 } 2254 } 2255 2256 2257 if (network_mode & NET_EDEV_MODE) 2258 { 2259 if(flag_count > 1) 2260 { 2261 print_column_heading(SAR_NETSTATS, timebufptr, NET_EDEV_MODE); 2262 } 2263 2264 for (i=0; i < nr_count; i++) 2265 { 2266 if (!nr_table[i].valid) 2267 continue; 2268 2269 if (!(network_mode & NET_PPP_MODE)) 2270 { 2271 if (!strncmp(nr_table[i].tname_unit, "ppp", 3)) 2272 { 2273 continue; /* skip any ppp interfaces */ 2274 } 2275 } 2276 2277 /* print the interface name */ 2278 fprintf(stdout, "%s %-8.8s ", timebufptr, nr_table[i].tname_unit); 2279 2280 fprintf (stdout, "%7llu ", 2281 (nr_table[i].cur_ierrors / avg_interval)); 2282 2283 fprintf (stdout, "%7llu ", 2284 (nr_table[i].cur_oerrors / avg_interval)); 2285 2286 fprintf (stdout, "%5llu ", 2287 (nr_table[i].cur_collisions / avg_interval)); 2288 2289 fprintf (stdout, " %5llu\n", 2290 (nr_table[i].cur_drops / avg_interval)); 2291 } 2292 fflush(stdout); 2293 } 2294} 2295 2296static void 2297print_column_heading(int type, char *timebufptr, int mode) 2298{ 2299 char *p; 2300 2301 p = timebufptr; 2302 2303 if (p == NULL) 2304 p = "Average:"; 2305 2306 if (!(flag_count > 1)) 2307 fprintf(stdout, "\n"); 2308 2309 switch (type) 2310 { 2311 case SAR_CPU: 2312 fprintf (stdout, "\n%s %%usr %%nice %%sys %%idle\n", p); 2313 break; 2314 2315 case SAR_VMSTAT: 2316 if (mode == 0) /* gflag */ 2317 fprintf(stdout, "\n%s pgout/s\n", p); 2318 else if (mode == 1) /* pflag */ 2319 fprintf(stdout, "\n%s pgin/s pflt/s vflt/s\n", p); 2320 break; 2321 case SAR_DRIVESTATS: 2322 fprintf(stdout, "\n%s device r+w/s blks/s\n", p); 2323 break; 2324 case SAR_NETSTATS: 2325 if (mode == NET_DEV_MODE) 2326 { 2327 fprintf(stdout, "\n%s %-8.8s %8.8s %10.10s %8.8s %10.10s\n", p, 2328 " IFACE", "Ipkts/s", "Ibytes/s", "Opkts/s", "Obytes/s"); 2329 } 2330 else if (mode == NET_EDEV_MODE) 2331 { 2332 fprintf(stdout, "\n%s %-8.8s %7.7s %7.7s %5s %s\n", p, 2333 " IFACE", "Ierrs/s", "Oerrs/s", "Coll/s", "Drop/s"); 2334 } 2335 break; 2336 default: 2337 break; 2338 } 2339} 2340 2341