2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 cc -Wall -Wno-long-double -I. -I ../sadc.tproj -O -o sar sar.c
38 #include <mach/mach.h>
39 #include <sys/param.h>
40 #include <sys/sysctl.h>
46 #define IFNET_32_BIT_COUNTERS 1
48 /* Options used only for launching sadc */
49 int t_interval
= 5; /* in seconds */
50 char * t_intervalp
= "5";
51 int n_samples
= 1; /* number of sample loops */
52 char * n_samplesp
= "1";
54 /* Used only for storing the binary output after launching sadc */
55 char *outfile
= NULL
; /* output file */
56 int ofd
= 0; /* output file descriptor */
59 * When launching sadc, this file descriptor reads sadc's stdout
61 * When not launching sadc, this file descriptor will be either
62 * the input file passed in with the -f flag
63 * or the standard input file /var/log/sa/saXX
65 int ifd
= 0; /* input file descriptor */
66 char *infile
= NULL
; /* input file */
70 /* Used when we have to luanch sadc */
72 int fd
[2]; /* read from fd[0], write to fd[1] */
74 char *optionstring1
= "Adgn:puo:";
75 char *optionstring1_usage
= "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP } ] [-o filename] t [n]";
76 char *optionstring2
= "Adgn:pue:f:i:s:";
77 char *optionstring2_usage
= "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP }] [-e time] [-f filename] [-i sec] [-s time]";
85 int dflag
= 0; /* drive statistics */
86 int gflag
= 0; /* page-out activity */
90 int nflag
= 0; /* network statistics */
92 char *sadc_mflagp
= "-m";
93 char *sadc_ppp_modep
= "PPP";
95 int pflag
= 0; /* page-in activity */
98 int uflag
= 0; /* cpu utilization - this is the only default */
102 int set_default_flag
= 1;
106 * To get the current time of day in seconds
107 * based on a 24 hour clock, pass in the time_t from time()
108 * the remainder is the current time in seconds
110 #define HOURS_PER_DAY 24
111 #define MINS_PER_HOUR 60
112 #define SECS_PER_MIN 60
113 #define SECS_PER_DAY (SECS_PER_MIN * MINS_PER_HOUR * HOURS_PER_DAY)
115 /* end time delimiter -- converted from hh:mm:ss to seconds */
119 int iseconds
= 0; /* interval seconds, default = 0 implies all samples are
122 /* start time delimiter -- converted from hh:mm:ss to seconds */
123 time_t start_time
= 0;
128 /* stat records average and previous */
129 struct vm_statistics prev_vmstat
, avg_vmstat
, cur_vmstat
;
130 host_cpu_load_info_data_t prev_cpuload
, avg_cpuload
, cur_cpuload
;
131 struct drivestats_report
*dr_head
= NULL
;
133 /* internal table of drive path mappings */
134 struct drivepath
*dp_table
= NULL
;
137 /* internal table of network interface statistics */
138 struct netstats_report
*nr_table
= NULL
;
140 struct netstats
*netstat_readbuf
= NULL
;
141 size_t netstat_readbuf_size
= 0;
144 int avg_interval
= 0;
148 /* Forward function declarations */
149 static void exit_usage();
150 static void open_output_file(char *path
);
151 static void open_input_file(char *path
);
152 static void read_record_hdr(struct record_hdr
*hdr
, int writeflag
);
153 static void read_record_data(char *buf
, size_t size
, int writeflag
);
154 static void write_record_hdr(struct record_hdr
*hdr
);
155 static void write_record_data(char *buf
, size_t size
);
156 static long convert_hms(char *string
);
157 static char *get_hms_string(time_t, char *);
158 static int find_restart_header(struct record_hdr
*);
159 static void print_all_column_headings (time_t timestamp
);
160 static void print_column_heading (int type
, char *timebufptr
, int mode
);
161 static void read_sample_set(int, time_t, struct record_hdr
*);
162 static void do_main_workloop();
163 static int bypass_sample_set(struct record_hdr
*, time_t);
164 static void skip_data(int);
165 static int get_cpu_sample(int flag
, struct record_hdr
*hdr
);
166 static void print_cpu_sample(char *timebufptr
);
167 static int get_vmstat_sample(int flag
, struct record_hdr
*hdr
);
168 static void print_vmstat_sample(char *timebufptr
);
170 static int get_drivestats_sample(int flag
, struct record_hdr
*hdr
);
171 static void init_drivestats(struct drivestats_report
*dr
);
172 static void print_drivestats_sample(char *timebufptr
);
173 static int get_drivepath_sample(int flag
, struct record_hdr
*hdr
);
175 static void set_cur_netstats(struct netstats_report
*nr
, struct netstats
*ns
);
176 static void init_prev_netstats(struct netstats_report
*nr
);
177 static int get_netstats_sample(int flag
, struct record_hdr
*hdr
);
178 static void print_netstats_sample(char *timebufptr
);
180 static void exit_average();
190 time_t curr_time
; /* current time in seconds */
192 char filenamebuf
[20];
193 char *optstring
= NULL
;
198 * Detirmine which option string to use
204 while((ch
=getopt(argc
, argv
, "aAbcdgkmn:pqruvwyo:e:f:i:s:")) != EOF
) {
207 if (optstringval
== 2)
209 optstring
=optionstring1
;
216 if (optstringval
== 1)
218 optstring
=optionstring2
;
229 /* still trying to determine which option string to use */
230 if (argc
- optind
> 0)
232 optstring
=optionstring1
; /* we should have a t_second value */
237 optstring
=optionstring2
;
242 optreset
= optind
= 1;
243 while ((ch
=getopt(argc
, argv
, optstring
)) != EOF
) {
247 set_default_flag
= 0;
252 set_default_flag
= 0;
257 set_default_flag
= 0;
262 set_default_flag
= 0;
267 set_default_flag
= 0;
272 set_default_flag
= 0;
277 set_default_flag
= 0;
282 set_default_flag
= 0;
287 if (!strncmp(optarg
, "PPP", 3))
288 network_mode
|= NET_PPP_MODE
;
289 else if (!strncmp(optarg
, "DEV", 3))
290 network_mode
|= NET_DEV_MODE
;
291 else if (!strncmp(optarg
, "EDEV", 4))
292 network_mode
|= NET_EDEV_MODE
;
295 set_default_flag
= 0;
300 set_default_flag
= 0;
305 set_default_flag
= 0;
310 set_default_flag
= 0;
315 set_default_flag
= 0;
320 set_default_flag
= 0;
325 set_default_flag
= 0;
330 set_default_flag
= 0;
334 /* open the output file */
337 (void)open_output_file(outfile
);
339 case 'e': /* eflag */
340 end_time
= convert_hms(optarg
);
348 iseconds
=atoi(optarg
);
351 start_time
= convert_hms(optarg
);
359 /* setup default uflag option */
362 dflag
= gflag
= pflag
= uflag
= 1;
366 * Add network stats to the load
367 * but avoid PPP data by default.
370 network_mode
= NET_DEV_MODE
| NET_EDEV_MODE
;;
372 flag_count
= 2; /* triggers column headings */
374 else if (set_default_flag
)
382 if (network_mode
& NET_PPP_MODE
)
384 if (!(network_mode
& NET_DEV_MODE
) &&
385 !(network_mode
& NET_EDEV_MODE
))
388 network_mode
|= NET_DEV_MODE
;
389 network_mode
|= NET_EDEV_MODE
;
398 /* set up signal handlers */
399 signal(SIGINT
, exit_average
);
400 signal(SIGQUIT
, exit_average
);
401 signal(SIGHUP
, exit_average
);
402 signal(SIGTERM
, exit_average
);
404 if (optstringval
== 1)
406 /* expecting a time interval */
413 t_interval
= strtol(argv
[0], &p
, 0);
414 t_intervalp
= argv
[0];
415 if (errno
|| (*p
!= '\0') || t_interval
<= 0 )
420 n_samples
= strtol(argv
[1], &p
, 0);
421 n_samplesp
= argv
[1];
422 if (errno
|| (*p
!= '\0') || n_samples
<= 0)
428 /* where does the input come from */
431 (void)open_input_file(infile
);
433 else if (optstringval
== 2)
436 * Create a filename of the form /var/log/sa/sadd
437 * where "dd" is the date of the month
439 curr_time
= time((time_t *)0); /* returns time in seconds */
442 timebuf will be a 26-character string of the form:
443 Thu Nov 24 18:22:48 1986\n\0
446 ctime_r(&curr_time
, timebuf
);
447 strncpy(filenamebuf
, "/var/log/sa/sa", 14);
448 strncpy(&filenamebuf
[14], &timebuf
[8], 2);
449 if (filenamebuf
[14] == ' ')
450 filenamebuf
[14] = '0';
451 filenamebuf
[16]='\0';
452 infile
= filenamebuf
;
453 (void)open_input_file(infile
);
455 else if (optstringval
== 1)
460 fprintf(stderr
, "sar: pipe(2) failed, errno = (%d)\n",errno
);
464 if ((pid
=fork()) == 0)
470 /* This is the child */
471 /* Close all file descriptors except the one we need */
473 for (i
=0; i
<= KERN_MAXFILESPERPROC
; i
++) {
474 if ((i
!= fd
[0]) && (i
!= fd
[1]))
478 efd
= open("/tmp/errlog", O_CREAT
|O_APPEND
|O_RDWR
, 0666);
479 if (dup2(efd
,2) == -1) {
483 /* Dup the two file descriptors to stdin and stdout */
484 if (dup2(fd
[0],0) == -1) {
487 if (dup2(fd
[1],1) == -1) {
490 /* Exec the child process */
491 if (network_mode
& NET_PPP_MODE
)
492 execl("/usr/lib/sa/sadc", "sadc", sadc_mflagp
, sadc_ppp_modep
, t_intervalp
, n_samplesp
, NULL
);
494 execl("/usr/lib/sa/sadc", "sadc", t_intervalp
, n_samplesp
, NULL
);
496 perror("execlp sadc");
497 exit(2); /* This call of exit(2) should never be reached... */
500 { /* This is the parent */
502 fprintf(stderr
, "sar: fork(2) failed, errno = (%d)\n",errno
);
505 close (fd
[1]); /* parent does not write to the pipe */
506 ifd
= fd
[0]; /* parent will read from the pipe */
511 /* we're confused about source of input data - bail out */
512 fprintf(stderr
, "sar: no input file recognized\n");
516 /* start reading input data and format the output */
517 (void)do_main_workloop();
518 (void)exit_average();
525 fprintf(stderr
, "\n%s\n\n", optionstring1_usage
);
526 fprintf(stderr
, "%s\n", optionstring2_usage
);
531 open_output_file(char *path
)
533 if ((ofd
= open(path
, O_CREAT
|O_APPEND
|O_TRUNC
|O_WRONLY
, 0664)) == -1 )
535 /* failed to open path */
536 fprintf(stderr
, "sar: failed to open output file [%s]\n", path
);
543 open_input_file(char *path
)
545 if ((ifd
= open(path
, O_RDONLY
, 0)) == -1)
547 /* failed to open path */
548 fprintf(stderr
, "sar: failed to open input file [%d][%s]\n", ifd
, path
);
554 read_record_hdr(hdr
, writeflag
)
555 struct record_hdr
*hdr
;
563 size
= sizeof(struct record_hdr
);
567 num
= read(ifd
, &hdr
[n
], size
);
577 fprintf(stderr
, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno
, (int)num
, (int)size
);
582 if (oflag
&& writeflag
)
583 write_record_hdr(hdr
);
589 read_record_data(buf
, size
, writeflag
)
600 num
= read(ifd
, &buf
[n
], size
);
606 else if (num
== 0) /* EOF */
610 fprintf(stderr
, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno
, (int)num
, (int)size
);
615 if (oflag
&& writeflag
)
616 write_record_data(buf
, n
);
622 write_record_hdr(hdr
)
623 struct record_hdr
*hdr
;
628 if ((num
= write(ofd
, hdr
, sizeof(struct record_hdr
))) == -1)
630 fprintf(stderr
, "sar: write_record_hdr failed, errno=%d\n", errno
);
637 write_record_data(char *buf
, size_t nbytes
)
641 if ((num
= write(ofd
, buf
, nbytes
)) == -1)
643 fprintf(stderr
, "sar: write_record_data failed, errno=%d\n", errno
);
650 * Convert a string of one of the forms
652 * into the number of seconds.
660 int hh
= 0; /* hours */
661 int mm
= 0; /* minutes */
662 int ss
= 0; /* seconds */
668 if (string
== NULL
|| *string
== '\0')
671 for (i
=0; string
[i
] != '\0'; i
++)
673 if ((!isdigit(string
[i
])) && (string
[i
] != ':'))
679 if (sscanf(string
, "%d:%d:%d", &hh
, &mm
, &ss
) != 3)
681 if (sscanf(string
, "%d:%d", &hh
, &mm
) != 2)
683 if (sscanf(string
, "%d", &hh
) != 1)
690 if (hh
< 0 || hh
>= HOURS_PER_DAY
||
691 mm
< 0 || mm
>= MINS_PER_HOUR
||
692 ss
< 0 || ss
> SECS_PER_MIN
)
697 seconds
= ((((hh
* MINS_PER_HOUR
) + mm
) * SECS_PER_MIN
) + ss
);
698 timestamp
= time((time_t *)0);
699 tm
=localtime(×tamp
);
700 seconds
-= tm
->tm_gmtoff
;
705 fprintf(stderr
, "sar: time format usage is hh[:mm[:ss]]\n");
712 * Use ctime_r to convert a time value into
713 * a 26-character string of the form:
715 * Thu Nov 24 18:22:48 1986\n\0
719 get_hms_string(tdata
, tbuf
)
735 /* sample set flags */
743 struct record_hdr hdr
;
744 time_t cur_timestamp
= 0; /* seconds - Coordinated Universal Time */
745 time_t next_timestamp
= 0; /* seconds - Coordinated Universal Time */
747 if (!find_restart_header(&hdr
))
750 cur_timestamp
= hdr
.rec_timestamp
;
752 /* convert sflag's start_time from 24 hour clock time to UTC seconds */
753 if (start_time
< (cur_timestamp
% SECS_PER_DAY
))
754 start_time
= cur_timestamp
;
756 start_time
+= cur_timestamp
- (cur_timestamp
% SECS_PER_DAY
);
758 /* convert end_time, from 24 hour clock time to UTC seconds */
760 end_time
+= cur_timestamp
- (cur_timestamp
% SECS_PER_DAY
);
763 fprintf(stderr
, "start = %ld, end = %ld, cur=%ld, [24hour - %ld]\n",
764 start_time
, end_time
, cur_timestamp
,(cur_timestamp
% SECS_PER_DAY
));
767 while (cur_timestamp
< start_time
)
769 bypass_sample_set(&hdr
, cur_timestamp
);
770 cur_timestamp
= hdr
.rec_timestamp
;
773 next_timestamp
= cur_timestamp
+ iseconds
;
774 print_all_column_headings(cur_timestamp
);
775 read_sample_set(INIT_SET
, cur_timestamp
, &hdr
);
776 cur_timestamp
= hdr
.rec_timestamp
;
778 while ((end_time
== 0) || (next_timestamp
< end_time
))
780 if (cur_timestamp
< next_timestamp
)
782 bypass_sample_set (&hdr
, cur_timestamp
);
783 cur_timestamp
= hdr
.rec_timestamp
;
787 /* need to know the seconds interval when printing averages */
788 if (avg_interval
== 0)
791 avg_interval
= iseconds
;
793 avg_interval
= cur_timestamp
- next_timestamp
;
795 next_timestamp
= cur_timestamp
+ iseconds
;
796 read_sample_set(PRINT_SET
, cur_timestamp
, &hdr
);
797 cur_timestamp
= hdr
.rec_timestamp
;
805 * Find and fill in a restart header. We don't write
806 * the binary data when looking for SAR_RESTART.
807 * Return: 1 on success
811 find_restart_header (ret_hdr
)
812 struct record_hdr
*ret_hdr
;
814 struct record_hdr hdr
;
821 read_record_hdr(&hdr
, FALSE
); /* exits on error */
823 if (hdr
.rec_type
== SAR_RESTART
)
827 write_record_hdr(&hdr
); /* writes the RESTART record */
834 * not the record we want...
835 * read past data and try again
840 { /* seek past data in the file */
841 if ((lseek(ifd
, (hdr
.rec_count
* hdr
.rec_size
), SEEK_CUR
)) == -1)
844 fprintf(stderr
, "sar: lseek failed, errno=%d\n", errno
);
849 /* compute data size - malloc a new buf if it's not big enough */
852 /* have to read from the pipe */
853 if (bufsize
< (hdr
.rec_count
* hdr
.rec_size
))
857 bufsize
= hdr
.rec_count
* hdr
.rec_size
;
858 if((buf
= (char *)malloc(bufsize
)) == NULL
)
860 fprintf(stderr
, "sar: malloc failed\n");
865 read_record_data(buf
, (hdr
.rec_count
* hdr
.rec_size
), FALSE
);
872 print_all_column_headings(timestamp
)
878 timebufp
= get_hms_string (timestamp
, timebuf
);
880 if (uflag
) /* print cpu headers */
881 print_column_heading(SAR_CPU
, timebufp
, 0);
883 if (gflag
) /* print page-out activity */
884 print_column_heading(SAR_VMSTAT
, timebufp
, 0);
886 if (pflag
) /* print page-in activity */
887 print_column_heading(SAR_VMSTAT
, timebufp
, 1);
889 if (dflag
) /* print drive stats */
890 print_column_heading(SAR_DRIVESTATS
, timebufp
, 0);
892 if (nflag
) /* print network stats */
894 if (network_mode
& NET_DEV_MODE
)
895 print_column_heading(SAR_NETSTATS
, timebufp
, NET_DEV_MODE
);
897 if (network_mode
& NET_EDEV_MODE
)
898 print_column_heading(SAR_NETSTATS
, timebufp
, NET_EDEV_MODE
);
904 * Find and fill in a timestamp header.
905 * Write the binary data when looking for SAR_TIMESTAMP
906 * Don't do anything with the data, just read past it.
907 * Return: 1 on success
911 bypass_sample_set (ret_hdr
, timestamp
)
912 struct record_hdr
*ret_hdr
;
915 struct record_hdr hdr
;
920 read_record_hdr(&hdr
, TRUE
); /* exits on error */
922 if (hdr
.rec_type
== SAR_TIMESTAMP
)
931 * not the record we want...
932 * read past data and try again
939 * we're reading from a file and we don't have to write the
940 * binary data so seek past data in the file
943 if ((lseek(ifd
, (hdr
.rec_count
* hdr
.rec_size
), SEEK_CUR
)) == -1)
946 fprintf(stderr
, "sar: lseek failed, errno=%d\n", errno
);
953 * We end up here when reading from pipe.
954 * malloc a new buffer if current is not big enough
956 if (bufsize
< (hdr
.rec_count
* hdr
.rec_size
))
960 bufsize
= hdr
.rec_count
* hdr
.rec_size
;
961 if((buf
= (char *)malloc(bufsize
)) == NULL
)
963 fprintf(stderr
, "sar: malloc failed\n");
969 read_record_data(buf
, (hdr
.rec_count
* hdr
.rec_size
), TRUE
);
971 } /* end if hdr.rec_count */
977 * INIT_SET: This initializes the first sample for each type.
978 * PRINT_SET: This read, compute and print out sample data.
981 read_sample_set(flag
, timestamp
, ret_hdr
)
984 struct record_hdr
*ret_hdr
;
986 struct record_hdr hdr
;
990 char *indent_string_wide
;
991 char *indent_string_narrow
;
994 int sar_drivestats
=0;
996 int sar_netstats
= 0;
998 indent_string_wide
= " ";
999 indent_string_narrow
= " ";
1000 indent_string
= indent_string_narrow
;
1002 read_record_hdr(&hdr
, TRUE
);
1004 while (hdr
.rec_type
!= SAR_TIMESTAMP
)
1006 switch (hdr
.rec_type
)
1009 sar_cpu
= get_cpu_sample(flag
, &hdr
);
1012 sar_vmstat
=get_vmstat_sample(flag
, &hdr
);
1015 sar_drivepath
= get_drivepath_sample(flag
, &hdr
);
1016 if (sar_drivepath
< 0)
1017 fprintf(stderr
, "sar: drivepath sync code error %d\n", sar_drivepath
);
1019 case SAR_DRIVESTATS
:
1020 sar_drivestats
= get_drivestats_sample(flag
, &hdr
);
1023 sar_netstats
= get_netstats_sample(flag
, &hdr
);
1029 read_record_hdr(&hdr
, TRUE
);
1032 /* return the timestamp header */
1035 if (flag
== PRINT_SET
)
1038 timebufp
= get_hms_string(timestamp
, timebuf
);
1040 if (uflag
&& sar_cpu
)
1041 print_cpu_sample(timebufp
);
1043 if((gflag
|| pflag
) && sar_vmstat
)
1044 print_vmstat_sample(timebufp
);
1046 if (dflag
&& sar_drivestats
)
1047 print_drivestats_sample(timebufp
);
1049 if (nflag
&& sar_netstats
)
1050 print_netstats_sample(timebufp
);
1062 /* seek past data in the file */
1063 if ((lseek(ifd
, bufsize
, SEEK_CUR
) == -1))
1066 fprintf(stderr
, "sar: lseek failed, errno=%d\n", errno
);
1072 /* have to read from the pipe */
1073 if((buf
= (char *)malloc(bufsize
)) == NULL
)
1075 fprintf(stderr
, "sar: malloc failed\n");
1078 /* even though we skip this data, we still write it if necessary */
1079 read_record_data(buf
, bufsize
, TRUE
);
1088 get_cpu_sample(flag
, hdr
)
1090 struct record_hdr
*hdr
;
1094 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1096 if (datasize
!= sizeof(host_cpu_load_info_data_t
))
1098 /* read past the data but don't do anything with it */
1099 skip_data(datasize
);
1103 read_record_data ((char *)&cur_cpuload
, (int)sizeof(host_cpu_load_info_data_t
), TRUE
);
1105 if (flag
== INIT_SET
)
1107 prev_cpuload
= cur_cpuload
;
1108 bzero(&avg_cpuload
, sizeof(avg_cpuload
));
1114 print_cpu_sample(timebufptr
)
1121 cur_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1122 -= prev_cpuload
.cpu_ticks
[CPU_STATE_USER
];
1124 prev_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1125 += cur_cpuload
.cpu_ticks
[CPU_STATE_USER
];
1127 time
+= cur_cpuload
.cpu_ticks
[CPU_STATE_USER
];
1129 cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1130 -= prev_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
];
1132 prev_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1133 += cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
];
1135 time
+= cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
];
1137 cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1138 -= prev_cpuload
.cpu_ticks
[CPU_STATE_IDLE
];
1140 prev_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1141 += cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
];
1143 time
+= cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
];
1145 avg_cpuload
.cpu_ticks
[CPU_STATE_USER
] += rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1146 / (time
? time
: 1));
1148 avg_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
] += rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1149 / (time
? time
: 1));
1151 avg_cpuload
.cpu_ticks
[CPU_STATE_IDLE
] += rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1152 / (time
? time
: 1));
1155 print_column_heading(SAR_CPU
, timebufptr
, 0);
1157 fprintf(stdout
, "%s%5.0f ", timebufptr
,
1158 rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1159 / (time
? time
: 1)));
1161 fprintf(stdout
, "%4.0f ",
1162 rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1163 / (time
? time
: 1)));
1165 fprintf(stdout
, "%4.0f\n",
1166 rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1167 / (time
? time
: 1)));
1171 get_vmstat_sample(flag
, hdr
)
1173 struct record_hdr
*hdr
;
1177 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1179 if (datasize
!= sizeof(struct vm_statistics
))
1181 /* read past the data but don't do anything with it */
1182 skip_data(datasize
);
1186 read_record_data ((char *)&cur_vmstat
, (int)sizeof(struct vm_statistics
), TRUE
);
1188 if (flag
== INIT_SET
)
1190 prev_vmstat
= cur_vmstat
;
1191 bzero(&avg_vmstat
, sizeof(avg_vmstat
));
1198 print_vmstat_sample(char *timebufptr
)
1201 cur_vmstat
.faults
-= prev_vmstat
.faults
;
1202 prev_vmstat
.faults
+= cur_vmstat
.faults
;
1203 avg_vmstat
.faults
+= cur_vmstat
.faults
;
1205 cur_vmstat
.cow_faults
-= prev_vmstat
.cow_faults
;
1206 prev_vmstat
.cow_faults
+= cur_vmstat
.cow_faults
;
1207 avg_vmstat
.cow_faults
+= cur_vmstat
.cow_faults
;
1209 cur_vmstat
.zero_fill_count
-= prev_vmstat
.zero_fill_count
;
1210 prev_vmstat
.zero_fill_count
+= cur_vmstat
.zero_fill_count
;
1211 avg_vmstat
.zero_fill_count
+= cur_vmstat
.zero_fill_count
;
1213 cur_vmstat
.reactivations
-= prev_vmstat
.reactivations
;
1214 prev_vmstat
.reactivations
+= cur_vmstat
.reactivations
;
1215 avg_vmstat
.reactivations
+= cur_vmstat
.reactivations
;
1217 cur_vmstat
.pageins
-= prev_vmstat
.pageins
;
1218 prev_vmstat
.pageins
+= cur_vmstat
.pageins
;
1219 avg_vmstat
.pageins
+= cur_vmstat
.pageins
;
1221 cur_vmstat
.pageouts
-= prev_vmstat
.pageouts
;
1222 prev_vmstat
.pageouts
+= cur_vmstat
.pageouts
;
1223 avg_vmstat
.pageouts
+= cur_vmstat
.pageouts
;
1229 print_column_heading(SAR_VMSTAT
, timebufptr
, 0);
1230 fprintf(stdout
, "%s %8.1f \n", timebufptr
, (float)((float)cur_vmstat
.pageouts
/avg_interval
));
1236 print_column_heading(SAR_VMSTAT
, timebufptr
, 1);
1237 fprintf(stdout
, "%s %8.1f %8.1f %8.1f\n", timebufptr
,
1238 (float)((float)cur_vmstat
.pageins
/ avg_interval
),
1239 (float)((float)cur_vmstat
.cow_faults
/avg_interval
),
1240 (float)((float)cur_vmstat
.faults
/avg_interval
));
1246 get_drivestats_sample(flag
, hdr
)
1248 struct record_hdr
*hdr
;
1250 struct drivestats
*databuf
;
1251 struct drivestats_report
*dr
;
1257 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1258 datacount
= hdr
->rec_count
;
1260 if (hdr
->rec_size
!= sizeof(struct drivestats
))
1262 /* something isn't right... read past the data but don't analyze it */
1263 skip_data(datasize
);
1267 /* malloc read buffer */
1268 if ((databuf
= (struct drivestats
*)malloc(datasize
)) == NULL
)
1270 fprintf(stderr
, "sar: malloc failed\n");
1271 exit (EXIT_FAILURE
);
1274 bzero(databuf
, datasize
);
1276 read_record_data ((char *)databuf
, datasize
, TRUE
);
1278 /* clear all global current fields */
1279 for(dr
= dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1283 dr
->cur_BytesRead
= 0;
1285 dr
->cur_BytesWritten
= 0;
1286 dr
->cur_LatentReadTime
= 0;
1287 dr
->cur_LatentWriteTime
= 0;
1288 dr
->cur_ReadErrors
= 0;
1289 dr
->cur_WriteErrors
= 0;
1290 dr
->cur_ReadRetries
= 0;
1291 dr
->cur_WriteRetries
= 0;
1292 dr
->cur_TotalReadTime
= 0;
1293 dr
->cur_TotalWriteTime
=0;
1296 /* By this point, we have read in a complete set of diskstats from the sadc
1298 * The order of the drives in not guaranteed.
1299 * The global report structure is a linked list, but may need initialization
1300 * We need to traverse this list and transfer the current
1301 * read data. If a disk entry isn't found, then we need to allocate one
1304 for (i
=0; i
< datacount
; i
++)
1306 struct drivestats_report
*dr_last
= NULL
;
1308 index
= databuf
[i
].drivepath_id
; /* use this as index into dp_table */
1310 /* find disk entry or allocate new one*/
1311 for(dr
= dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1314 if(index
== dr
->drivepath_id
)
1320 /* allocate new entry */
1321 if((dr
= (struct drivestats_report
*)malloc(sizeof(struct drivestats_report
))) == NULL
)
1323 fprintf(stderr
, "sar: malloc error\n");
1326 bzero((char *)dr
, sizeof(struct drivestats_report
));
1327 dr
->blocksize
= databuf
[i
].blocksize
;
1328 dr
->drivepath_id
= index
;
1332 /* get the BSDName which should be in the table by now */
1333 if ((index
< dp_count
) && (dp_table
[index
].state
!= DPSTATE_UNINITIALIZED
))
1334 strncpy(dr
->name
, dp_table
[index
].BSDName
, MAXDRIVENAME
+1);
1336 strcpy(dr
->name
, "disk??");
1338 if (dr_head
== NULL
)
1341 dr_head
->next
= NULL
;
1345 dr_last
->next
= (char *)dr
;
1347 } /* end if dr == NULL */
1350 dr
->cur_Reads
= databuf
[i
].Reads
;
1351 dr
->cur_BytesRead
= databuf
[i
].BytesRead
;
1352 dr
->cur_Writes
= databuf
[i
].Writes
;
1353 dr
->cur_BytesWritten
= databuf
[i
].BytesWritten
;
1354 dr
->cur_LatentReadTime
= databuf
[i
].LatentReadTime
;
1355 dr
->cur_LatentWriteTime
= databuf
[i
].LatentWriteTime
;
1356 dr
->cur_ReadErrors
= databuf
[i
].ReadErrors
;
1357 dr
->cur_WriteErrors
= databuf
[i
].WriteErrors
;
1358 dr
->cur_ReadRetries
= databuf
[i
].ReadRetries
;
1359 dr
->cur_WriteRetries
= databuf
[i
].WriteRetries
;
1360 dr
->cur_TotalReadTime
= databuf
[i
].TotalReadTime
;
1361 dr
->cur_TotalWriteTime
=databuf
[i
].TotalWriteTime
;
1362 } /* end for loop */
1364 /* Reinitialize the prev and avg fields when
1365 * This is a new disk
1366 * This is a changed disk - name change implies disk swapping
1367 * This disk is not present in this sample
1369 for(dr
= dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1371 if (dr
->drivepath_id
>= dp_count
)
1373 /* something is amiss */
1378 index
= dr
->drivepath_id
; /* use this as index into dp_table */
1381 if ((flag
== INIT_SET
) ||
1382 (dp_table
[index
].state
== DPSTATE_NEW
) ||
1383 (dp_table
[index
].state
== DPSTATE_CHANGED
) ||
1387 * prev will be set to cur
1388 * activate the state in dp_table
1391 dp_table
[index
].state
= DPSTATE_ACTIVE
;
1393 init_drivestats(dr
);
1400 init_drivestats(struct drivestats_report
*dr
)
1403 dr
->prev_Reads
= dr
->cur_Reads
;
1405 dr
->prev_BytesRead
= dr
->cur_BytesRead
;
1406 dr
->avg_BytesRead
= 0;
1407 dr
->prev_Writes
= dr
->cur_Writes
;
1409 dr
->prev_BytesWritten
= dr
->cur_BytesWritten
;
1410 dr
->avg_BytesWritten
= 0;
1411 dr
->prev_LatentReadTime
= dr
->cur_LatentReadTime
;
1412 dr
->avg_LatentReadTime
= 0;
1413 dr
->prev_LatentWriteTime
= dr
->cur_LatentWriteTime
;
1414 dr
->avg_LatentWriteTime
= 0;
1415 dr
->prev_ReadErrors
= dr
->cur_ReadErrors
;
1416 dr
->avg_ReadErrors
= 0;
1417 dr
->prev_WriteErrors
= dr
->cur_WriteErrors
;
1418 dr
->avg_WriteErrors
= 0;
1419 dr
->prev_ReadRetries
= dr
->cur_ReadRetries
;
1420 dr
->avg_ReadRetries
= 0;
1421 dr
->prev_WriteRetries
= dr
->cur_WriteRetries
;
1422 dr
->avg_WriteRetries
= 0;
1423 dr
->prev_TotalReadTime
= dr
->cur_TotalReadTime
;
1424 dr
->avg_TotalReadTime
= 0;
1425 dr
->prev_TotalWriteTime
= dr
->cur_TotalWriteTime
;
1426 dr
->avg_TotalWriteTime
= 0;
1431 print_drivestats_sample(char *timebufptr
)
1433 struct drivestats_report
*dr
;
1434 long double transfers_per_second
;
1435 long double kb_per_transfer
, mb_per_second
;
1436 u_int64_t interval_bytes
, interval_transfers
, interval_blocks
;
1437 u_int64_t interval_time
;
1438 long double blocks_per_second
, ms_per_transaction
;
1441 print_column_heading(SAR_DRIVESTATS
, timebufptr
, 0);
1443 for (dr
=dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1449 * This sanity check is for drives that get removed and then
1450 * returned during the sampling sleep interval. If anything
1451 * looks out of sync, reinit and skip this entry. There is
1452 * no way to guard against this entirely.
1454 if ((dr
->cur_Reads
< dr
->prev_Reads
) ||
1455 (dr
->cur_BytesRead
< dr
->prev_BytesRead
) ||
1456 (dr
->cur_Writes
< dr
->prev_Writes
) ||
1457 (dr
->cur_BytesWritten
< dr
->prev_BytesWritten
))
1459 init_drivestats(dr
);
1465 dr
->cur_Reads
-= dr
->prev_Reads
;
1466 dr
->prev_Reads
+= dr
->cur_Reads
;
1467 dr
->avg_Reads
+= dr
->cur_Reads
;
1469 dr
->cur_BytesRead
-= dr
->prev_BytesRead
;
1470 dr
->prev_BytesRead
+= dr
->cur_BytesRead
;
1471 dr
->avg_BytesRead
+= dr
->cur_BytesRead
;
1473 dr
->cur_Writes
-= dr
->prev_Writes
;
1474 dr
->prev_Writes
+= dr
->cur_Writes
;
1475 dr
->avg_Writes
+= dr
->cur_Writes
;
1477 dr
->cur_BytesWritten
-= dr
->prev_BytesWritten
;
1478 dr
->prev_BytesWritten
+= dr
->cur_BytesWritten
;
1479 dr
->avg_BytesWritten
+= dr
->cur_BytesWritten
;
1481 dr
->cur_LatentReadTime
-= dr
->prev_LatentReadTime
;
1482 dr
->prev_LatentReadTime
+= dr
->cur_LatentReadTime
;
1483 dr
->avg_LatentReadTime
+= dr
->cur_LatentReadTime
;
1485 dr
->cur_LatentWriteTime
-= dr
->prev_LatentWriteTime
;
1486 dr
->prev_LatentWriteTime
+= dr
->cur_LatentWriteTime
;
1487 dr
->avg_LatentWriteTime
+= dr
->cur_LatentWriteTime
;
1489 dr
->cur_ReadErrors
-= dr
->prev_ReadErrors
;
1490 dr
->prev_ReadErrors
+= dr
->cur_ReadErrors
;
1491 dr
->avg_ReadErrors
+= dr
->cur_ReadErrors
;
1493 dr
->cur_WriteErrors
-= dr
->prev_WriteErrors
;
1494 dr
->prev_WriteErrors
+= dr
->cur_WriteErrors
;
1495 dr
->avg_WriteErrors
+= dr
->cur_WriteErrors
;
1497 dr
->cur_ReadRetries
-= dr
->prev_ReadRetries
;
1498 dr
->prev_ReadRetries
+= dr
->cur_ReadRetries
;
1499 dr
->avg_ReadRetries
+= dr
->cur_ReadRetries
;
1501 dr
->cur_WriteRetries
-= dr
->prev_WriteRetries
;
1502 dr
->prev_WriteRetries
+= dr
->cur_WriteRetries
;
1503 dr
->avg_WriteRetries
+= dr
->cur_WriteRetries
;
1505 dr
->cur_TotalReadTime
-= dr
->prev_TotalReadTime
;
1506 dr
->prev_TotalReadTime
+= dr
->cur_TotalReadTime
;
1507 dr
->avg_TotalReadTime
+= dr
->cur_TotalReadTime
;
1509 dr
->cur_TotalWriteTime
-= dr
->prev_TotalWriteTime
;
1510 dr
->prev_TotalWriteTime
+= dr
->cur_TotalWriteTime
;
1511 dr
->avg_TotalWriteTime
+= dr
->cur_TotalWriteTime
;
1514 interval_bytes
= dr
->cur_BytesRead
+ dr
->cur_BytesWritten
;
1517 interval_transfers
= dr
->cur_Reads
+ dr
->cur_Writes
;
1520 interval_time
= dr
->cur_LatentReadTime
+ dr
->cur_LatentWriteTime
;
1522 interval_blocks
= interval_bytes
/ dr
->blocksize
;
1523 blocks_per_second
= interval_blocks
/ avg_interval
;
1524 transfers_per_second
= interval_transfers
/ avg_interval
;
1525 mb_per_second
= (interval_bytes
/ avg_interval
) / (1024 *1024);
1527 kb_per_transfer
= (interval_transfers
> 0) ?
1528 ((long double)interval_bytes
/ interval_transfers
)
1531 /* times are in nanoseconds, convert to milliseconds */
1532 ms_per_transaction
= (interval_transfers
> 0) ?
1533 ((long double)interval_time
/ interval_transfers
)
1536 /* print device name */
1537 fprintf(stdout
, "%s %-10s", timebufptr
, dr
->name
);
1539 /* print transfers per second */
1540 fprintf(stdout
, "%4.0Lf ", transfers_per_second
);
1542 /* print blocks per second - in device blocksize */
1543 fprintf(stdout
, "%4.0Lf\n", blocks_per_second
);
1548 * Print averages before exiting.
1555 if (avg_counter
<= 0 )
1565 if (uflag
) /* print cpu averages */
1568 print_column_heading(SAR_CPU
, 0, 0);
1570 fprintf(stdout
, "Average: %5d ",
1571 (int)avg_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1572 / (avg_counter
? avg_counter
: 1));
1574 fprintf(stdout
, "%4d ",
1575 (int)avg_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1576 / (avg_counter
? avg_counter
: 1));
1578 fprintf(stdout
, "%4d \n",
1579 (int)avg_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1580 / (avg_counter
? avg_counter
: 1));
1586 if (gflag
) /* print page-out averages */
1589 print_column_heading(SAR_VMSTAT
, 0, 0);
1591 fprintf(stdout
, "Average: %8.1f\n",
1592 (float)((avg_vmstat
.pageouts
/ (avg_counter
? avg_counter
: 1)) / avg_interval
));
1596 if (pflag
) /* print page-in averages */
1599 print_column_heading(SAR_VMSTAT
, 0, 1);
1601 fprintf(stdout
, "Average: %8.1f %8.1f %8.1f\n",
1602 (float)(((float)avg_vmstat
.pageins
/ (avg_counter
? avg_counter
: 1)) / avg_interval
),
1603 (float)(((float)avg_vmstat
.cow_faults
/ (avg_counter
? avg_counter
: 1)) / avg_interval
),
1604 (float)(((float)avg_vmstat
.faults
/ (avg_counter
? avg_counter
: 1)) / avg_interval
));
1608 if (dflag
) /* print drivestats averages */
1610 struct drivestats_report
*dr
;
1611 long double transfers_per_second
;
1612 long double kb_per_transfer
, mb_per_second
;
1613 u_int64_t total_bytes
, total_transfers
, total_blocks
;
1614 u_int64_t total_time
;
1615 long double blocks_per_second
, ms_per_transaction
;
1619 print_column_heading(SAR_DRIVESTATS
, 0, 0);
1621 for (dr
=dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1623 /* don't bother to print out averages for disks that were removed */
1627 fprintf(stdout
, " %s %s\n",
1628 dp_table
[dr
->drivepath_id
].BSDName
, dp_table
[dr
->drivepath_id
].ioreg_path
);
1631 total_bytes
= dr
->avg_BytesRead
+ dr
->avg_BytesWritten
;
1634 total_transfers
= dr
->avg_Reads
+ dr
->avg_Writes
;
1637 total_time
= dr
->avg_LatentReadTime
+ dr
->avg_LatentWriteTime
;
1639 total_blocks
= total_bytes
/ dr
->blocksize
;
1640 blocks_per_second
= total_blocks
/ avg_interval
;
1641 transfers_per_second
= total_transfers
/ avg_interval
;
1642 mb_per_second
= (total_bytes
/ avg_interval
) / (1024 *1024);
1644 kb_per_transfer
= (total_transfers
> 0) ?
1645 ((long double)total_bytes
/ total_transfers
)
1648 /* times are in nanoseconds, convert to milliseconds */
1649 ms_per_transaction
= (total_transfers
> 0) ?
1650 ((long double)total_time
/ total_transfers
)
1652 msdig
= (ms_per_transaction
< 100.0) ? 1 : 0;
1653 fprintf(stdout
, "Average: %-10s %4.0Lf %4.0Lf\n",
1655 (transfers_per_second
/ dr
->avg_count
),
1656 (blocks_per_second
/ dr
->avg_count
));
1660 } /* end if dflag */
1666 if (network_mode
& NET_DEV_MODE
)
1669 print_column_heading(SAR_NETSTATS
, 0, NET_DEV_MODE
);
1670 for (i
= 0; i
< nr_count
; i
++)
1672 if (!nr_table
[i
].valid
)
1675 if(nr_table
[i
].avg_count
== 0)
1678 avg_count
= nr_table
[i
].avg_count
;
1680 fprintf(stdout
, "Average: %-8.8s", nr_table
[i
].tname_unit
);
1682 fprintf (stdout
, "%8llu ",
1683 ((nr_table
[i
].avg_ipackets
/ avg_count
) / avg_interval
));
1685 fprintf (stdout
, "%10llu ",
1686 ((nr_table
[i
].avg_ibytes
/ avg_count
) / avg_interval
));
1688 fprintf (stdout
, "%8llu ",
1689 ((nr_table
[i
].avg_opackets
/ avg_count
) / avg_interval
));
1691 fprintf (stdout
, "%10llu\n",
1692 ((nr_table
[i
].avg_obytes
/ avg_count
) / avg_interval
));
1698 if (network_mode
& NET_EDEV_MODE
)
1702 print_column_heading(SAR_NETSTATS
, 0, NET_EDEV_MODE
);
1704 for (i
= 0; i
< nr_count
; i
++)
1706 if (!nr_table
[i
].valid
)
1709 if(nr_table
[i
].avg_count
== 0)
1712 avg_count
= nr_table
[i
].avg_count
;
1714 fprintf(stdout
, "Average: %-8.8s ", nr_table
[i
].tname_unit
);
1716 fprintf (stdout
, "%7llu ",
1717 ((nr_table
[i
].avg_ierrors
/ avg_count
) / avg_interval
));
1719 fprintf (stdout
, "%7llu ",
1720 ((nr_table
[i
].avg_oerrors
/ avg_count
) / avg_interval
));
1722 fprintf (stdout
, "%5llu ",
1723 ((nr_table
[i
].avg_collisions
/ avg_count
) / avg_interval
));
1725 fprintf (stdout
, " %5llu\n",
1726 ((nr_table
[i
].avg_drops
/ avg_count
) / avg_interval
));
1732 } /* end if nflag */
1738 * Return < 0 failure, debugging purposes only
1739 * Return = 0 data skipped
1740 * Return > 0 success
1744 get_drivepath_sample(flag
, hdr
)
1746 struct record_hdr
*hdr
;
1749 struct drivepath dp
;
1750 struct drivestats_report
*dr
;
1753 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1755 if (datasize
!= sizeof(struct drivepath
))
1757 /* read past the data but don't do anything with it */
1758 skip_data(datasize
);
1762 read_record_data ((char *)&dp
, (int)sizeof(struct drivepath
), TRUE
);
1765 * If state is new -- put a new entry in the dp_table.
1766 * If state is changed -- traverse the drivestats_report table
1767 * and copy new name.
1769 if (dp
.state
== DPSTATE_NEW
)
1772 if (dp_table
== NULL
)
1774 if (dp
.drivepath_id
!= 0)
1776 /* First setup of internal drivepath table */
1777 dp_table
= (struct drivepath
*)malloc(sizeof(struct drivepath
));
1778 if (dp_table
== NULL
)
1784 fprintf(stdout
, "New Disk: [%s] %s\n", dp
.BSDName
, dp
.ioreg_path
);
1786 /* traverse table and find next uninitialized entry */
1787 for (i
= 0; i
< dp_count
; i
++)
1789 if (dp_table
[i
].state
== DPSTATE_UNINITIALIZED
)
1791 if (dp
.drivepath_id
!= i
)
1793 /* the table is out of sync - this should not happen */
1801 * If we get here, we've run out of table entries.
1802 * Double the size of the table, then assign the next entry.
1804 if (dp
.drivepath_id
!= i
)
1806 /* the table is out of sync - this should not happen */
1810 dp_table
= (struct drivepath
*)realloc(dp_table
, n
* sizeof(struct drivepath
));
1811 bzero(&dp_table
[dp_count
], dp_count
* sizeof(struct drivepath
));
1812 dp_table
[dp_count
] = dp
;
1817 else if (dp
.state
== DPSTATE_CHANGED
)
1820 /* Update the name in the table */
1821 if ((dp
.drivepath_id
< dp_count
) && (dp_table
[dp
.drivepath_id
].state
!= DPSTATE_UNINITIALIZED
))
1823 if (strcmp(dp_table
[dp
.drivepath_id
].ioreg_path
, dp
.ioreg_path
) != 0)
1825 /* something is amiss */
1832 fprintf(stdout
, "Change: [%s] %s\n", dp
.BSDName
,
1833 dp_table
[dp
.drivepath_id
].ioreg_path
);
1835 strcpy(dp_table
[dp
.drivepath_id
].BSDName
, dp
.BSDName
);
1837 for(dr
= dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1839 if (dr
->drivepath_id
== dp
.drivepath_id
)
1840 strcpy(dr
->name
, dp
.BSDName
);
1852 * Bytes and packet counts are used to track
1853 * counter wraps. So, don't enforce the
1854 * NET_DEV_MODE or NET_EDEV_MODE in here.
1855 * Maintain all the stats.
1858 set_cur_netstats(struct netstats_report
*nr
, struct netstats
*ns
)
1861 nr
->cur_ipackets
= ns
->net_ipackets
;
1862 nr
->cur_ibytes
= ns
->net_ibytes
;
1863 nr
->cur_opackets
= ns
->net_opackets
;
1864 nr
->cur_obytes
= ns
->net_obytes
;
1866 nr
->cur_ierrors
= ns
->net_ierrors
;
1867 nr
->cur_oerrors
= ns
->net_oerrors
;
1868 nr
->cur_collisions
= ns
->net_collisions
;
1869 nr
->cur_drops
= ns
->net_drops
;
1871 nr
->cur_imcasts
= ns
->net_imcasts
;
1872 nr
->cur_omcasts
= ns
->net_omcasts
;
1877 init_prev_netstats(struct netstats_report
*nr
)
1883 nr
->prev_ipackets
= nr
->cur_ipackets
;
1884 nr
->avg_ipackets
= 0;
1885 nr
->prev_ibytes
= nr
->cur_ibytes
;
1887 nr
->prev_opackets
= nr
->cur_opackets
;
1888 nr
->avg_opackets
= 0;
1889 nr
->prev_obytes
= nr
->cur_obytes
;
1892 nr
->prev_ierrors
= nr
->cur_ierrors
;
1893 nr
->avg_ierrors
= 0;
1894 nr
->prev_oerrors
= nr
->cur_oerrors
;
1895 nr
->avg_oerrors
= 0;
1896 nr
->prev_collisions
= nr
->cur_collisions
;
1897 nr
->avg_collisions
= 0;
1898 nr
->prev_drops
= nr
->cur_drops
;
1901 /* track these, but never displayed */
1902 nr
->prev_imcasts
= nr
->cur_imcasts
;
1903 nr
->avg_imcasts
= 0;
1904 nr
->prev_omcasts
= nr
->cur_omcasts
;
1905 nr
->avg_omcasts
= 0;
1913 get_netstats_sample(flag
, hdr
)
1915 struct record_hdr
*hdr
;
1917 struct netstats
*databuf
= NULL
;
1922 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1923 datacount
= hdr
->rec_count
;
1925 if (hdr
->rec_size
!= sizeof(struct netstats
))
1927 /* something isn't right... read past the data but don't analyze it */
1928 skip_data(datasize
);
1932 /* malloc new or bigger read buffer */
1933 if((netstat_readbuf
== NULL
) || (netstat_readbuf_size
< datasize
))
1935 if (netstat_readbuf
)
1936 free (netstat_readbuf
);
1938 if ((netstat_readbuf
= (struct netstats
*)malloc(datasize
)) == NULL
)
1940 fprintf(stderr
, "sar: malloc failed\n");
1941 exit (EXIT_FAILURE
);
1943 netstat_readbuf_size
= datasize
;
1946 bzero(netstat_readbuf
, netstat_readbuf_size
);
1947 databuf
= netstat_readbuf
;
1949 read_record_data ((char *)databuf
, datasize
, TRUE
);
1951 if (nr_table
== NULL
)
1953 /* initial internal table setup */
1954 nr_table
= (struct netstats_report
*)malloc(datacount
* sizeof(struct netstats_report
));
1955 nr_count
= datacount
;
1956 bzero(nr_table
, (datacount
* sizeof(struct netstats_report
)));
1958 /* on first init, this is faster than finding our way to NEW_ENTRY */
1959 for (i
= 0; i
< datacount
; i
++)
1961 if (!(network_mode
& NET_PPP_MODE
))
1963 if (!strncmp(databuf
[i
].tname_unit
, "ppp", 3))
1965 * Skip ppp interfaces.
1966 * ie don't even put them in this internal table.
1969 strncpy(nr_table
[i
].tname_unit
, databuf
[i
].tname_unit
, MAX_TNAME_UNIT_SIZE
);
1970 nr_table
[i
].tname_unit
[MAX_TNAME_UNIT_SIZE
] = '\0';
1971 set_cur_netstats(&nr_table
[i
], &databuf
[i
]);
1972 init_prev_netstats(&nr_table
[i
]);
1978 * clear all the present flags.
1979 * As we traverse the current sample set
1980 * and update the internal table, the flag
1983 for (i
= 0; i
< nr_count
; i
++)
1985 nr_table
[i
].present
= 0;
1989 * Find and update table entries.
1992 for (i
=0; i
<datacount
; i
++)
1999 name
= databuf
[i
].tname_unit
;
2002 if (!(network_mode
& NET_PPP_MODE
))
2004 if (!strncmp(name
, "ppp", 3))
2005 continue; /* skip ppp interfaces */
2008 /* Find the matching entry using the interface name */
2009 for (j
=0; j
< nr_count
&& !found
; j
++)
2011 if (nr_table
[j
].valid
)
2013 if(!strcmp(nr_table
[j
].tname_unit
, name
))
2016 nr_table
[j
].present
= 1;
2017 set_cur_netstats(&nr_table
[j
], &databuf
[i
]);
2022 if (!found
) /* this is a new entry */
2024 /* Find an invalid entry in the table and init it */
2025 for (j
=0; j
< nr_count
; j
++)
2027 if (!nr_table
[j
].valid
)
2034 /* we ran out of entries... grow the table */
2036 nr_table
= (struct netstats_report
*)realloc(nr_table
, n
* sizeof(struct netstats_report
));
2037 bzero(&nr_table
[nr_count
], nr_count
* sizeof (struct netstats_report
));
2038 nr_index
= nr_count
;
2042 strncpy(nr_table
[nr_index
].tname_unit
, databuf
[i
].tname_unit
, MAX_TNAME_UNIT_SIZE
);
2043 nr_table
[nr_index
].tname_unit
[MAX_TNAME_UNIT_SIZE
] = '\0';
2044 set_cur_netstats(&nr_table
[nr_index
], &databuf
[i
]);
2045 init_prev_netstats(&nr_table
[nr_index
]);
2051 * Traverse the internal table. Any valid entry that wasn't
2052 * present in this sample is cleared for reuse.
2054 for (i
= 0; i
< nr_count
; i
++)
2056 if (nr_table
[i
].valid
)
2058 if (nr_table
[i
].present
== 0)
2059 bzero(&nr_table
[i
], sizeof(struct netstats_report
));
2066 print_netstats_sample(char *timebufptr
)
2070 for (i
=0; i
< nr_count
; i
++)
2072 if (!nr_table
[i
].valid
)
2076 * This is where we attempt to handle counters that
2077 * might wrap ... the kernel netstats are only 32 bits.
2079 * Interfaces may go away and then return within the
2080 * sampling period. This can't be detected and it
2081 * may look like a counter wrap. An interface generation
2082 * counter will help... but isn't implemented at this time.
2086 * The ppp interfaces are very likely to come and go during
2087 * a sampling period. During the normal life of a ppp interface,
2088 * it's less likely that the packet counter will wrap, so if
2089 * it appears to have done so, is probably because the
2090 * interface unit number has been reused.
2091 * We reinitialize that interface in that case.
2093 if (network_mode
& NET_PPP_MODE
)
2096 * ppp interfaces won't even make it into this table
2097 * when NET_PPP_MODE isn't set
2099 if (!strncmp(nr_table
[i
].tname_unit
, "ppp", 3))
2102 * Both ipackets and opackets have to be less
2103 * than the previous counter to cause us to reinit.
2106 if ((nr_table
[i
].cur_ipackets
< nr_table
[i
].prev_ipackets
)
2107 && (nr_table
[i
].cur_opackets
< nr_table
[i
].prev_opackets
))
2109 init_prev_netstats(&nr_table
[i
]);
2115 nr_table
[i
].avg_count
++;
2117 #ifdef IFNET_32_BIT_COUNTERS
2118 while (nr_table
[i
].cur_ipackets
< nr_table
[i
].prev_ipackets
)
2119 nr_table
[i
].cur_ipackets
+= 0x100000000LL
;
2120 #endif /* IFNET_32_BIT_COUNTERS */
2121 nr_table
[i
].cur_ipackets
-= nr_table
[i
].prev_ipackets
;
2122 nr_table
[i
].prev_ipackets
+= nr_table
[i
].cur_ipackets
;
2123 nr_table
[i
].avg_ipackets
+= nr_table
[i
].cur_ipackets
;
2126 #ifdef IFNET_32_BIT_COUNTERS
2127 while (nr_table
[i
].cur_ibytes
< nr_table
[i
].prev_ibytes
)
2128 nr_table
[i
].cur_ibytes
+= 0x100000000LL
;
2129 #endif /* IFNET_32_BIT_COUNTERS */
2130 nr_table
[i
].cur_ibytes
-= nr_table
[i
].prev_ibytes
;
2131 nr_table
[i
].prev_ibytes
+= nr_table
[i
].cur_ibytes
;
2132 nr_table
[i
].avg_ibytes
+= nr_table
[i
].cur_ibytes
;
2135 #ifdef IFNET_32_BIT_COUNTERS
2136 while (nr_table
[i
].cur_opackets
< nr_table
[i
].prev_opackets
)
2137 nr_table
[i
].cur_opackets
+= 0x100000000LL
;
2138 #endif /* IFNET_32_BIT_COUNTERS */
2139 nr_table
[i
].cur_opackets
-= nr_table
[i
].prev_opackets
;
2140 nr_table
[i
].prev_opackets
+= nr_table
[i
].cur_opackets
;
2141 nr_table
[i
].avg_opackets
+= nr_table
[i
].cur_opackets
;
2143 #ifdef IFNET_32_BIT_COUNTERS
2144 while (nr_table
[i
].cur_obytes
< nr_table
[i
].prev_obytes
)
2145 nr_table
[i
].cur_obytes
+= 0x100000000LL
;
2146 #endif /* IFNET_32_BIT_COUNTERS */
2147 nr_table
[i
].cur_obytes
-= nr_table
[i
].prev_obytes
;
2148 nr_table
[i
].prev_obytes
+= nr_table
[i
].cur_obytes
;
2149 nr_table
[i
].avg_obytes
+= nr_table
[i
].cur_obytes
;
2152 #ifdef IFNET_32_BIT_COUNTERS
2153 while (nr_table
[i
].cur_ierrors
< nr_table
[i
].prev_ierrors
)
2154 nr_table
[i
].cur_ierrors
+= 0x100000000LL
;
2155 #endif /* IFNET_32_BIT_COUNTERS */
2156 nr_table
[i
].cur_ierrors
-= nr_table
[i
].prev_ierrors
;
2157 nr_table
[i
].prev_ierrors
+= nr_table
[i
].cur_ierrors
;
2158 nr_table
[i
].avg_ierrors
+= nr_table
[i
].cur_ierrors
;
2160 #ifdef IFNET_32_BIT_COUNTERS
2161 while (nr_table
[i
].cur_oerrors
< nr_table
[i
].prev_oerrors
)
2162 nr_table
[i
].cur_oerrors
+= 0x100000000LL
;
2163 #endif /* IFNET_32_BIT_COUNTERS */
2164 nr_table
[i
].cur_oerrors
-= nr_table
[i
].prev_oerrors
;
2165 nr_table
[i
].prev_oerrors
+= nr_table
[i
].cur_oerrors
;
2166 nr_table
[i
].avg_oerrors
+= nr_table
[i
].cur_oerrors
;
2168 #ifdef IFNET_32_BIT_COUNTERS
2169 while (nr_table
[i
].cur_collisions
< nr_table
[i
].prev_collisions
)
2170 nr_table
[i
].cur_collisions
+= 0x100000000LL
;
2171 #endif /* IFNET_32_BIT_COUNTERS */
2172 nr_table
[i
].cur_collisions
-= nr_table
[i
].prev_collisions
;
2173 nr_table
[i
].prev_collisions
+= nr_table
[i
].cur_collisions
;
2174 nr_table
[i
].avg_collisions
+= nr_table
[i
].cur_collisions
;
2176 #ifdef IFNET_32_BIT_COUNTERS
2177 while (nr_table
[i
].cur_drops
< nr_table
[i
].prev_drops
)
2178 nr_table
[i
].cur_drops
+= 0x100000000LL
;
2179 #endif /* IFNET_32_BIT_COUNTERS */
2180 nr_table
[i
].cur_drops
-= nr_table
[i
].prev_drops
;
2181 nr_table
[i
].prev_drops
+= nr_table
[i
].cur_drops
;
2182 nr_table
[i
].avg_drops
+= nr_table
[i
].cur_drops
;
2185 #ifdef IFNET_32_BIT_COUNTERS
2186 while (nr_table
[i
].cur_imcasts
< nr_table
[i
].prev_imcasts
)
2187 nr_table
[i
].cur_imcasts
+= 0x100000000LL
;
2188 #endif /* IFNET_32_BIT_COUNTERS */
2189 nr_table
[i
].cur_imcasts
-= nr_table
[i
].prev_imcasts
;
2190 nr_table
[i
].prev_imcasts
+= nr_table
[i
].cur_imcasts
;
2191 nr_table
[i
].avg_imcasts
+= nr_table
[i
].cur_imcasts
;
2193 #ifdef IFNET_32_BIT_COUNTERS
2194 while (nr_table
[i
].cur_omcasts
< nr_table
[i
].prev_omcasts
)
2195 nr_table
[i
].cur_omcasts
+= 0x100000000LL
;
2196 #endif /* IFNET_32_BIT_COUNTERS */
2197 nr_table
[i
].cur_omcasts
-= nr_table
[i
].prev_omcasts
;
2198 nr_table
[i
].prev_omcasts
+= nr_table
[i
].cur_omcasts
;
2199 nr_table
[i
].avg_omcasts
+= nr_table
[i
].cur_omcasts
;
2203 if (!(flag_count
> 1))
2204 fprintf(stdout
, "\n");
2206 if (network_mode
& NET_DEV_MODE
)
2209 print_column_heading(SAR_NETSTATS
, timebufptr
, NET_DEV_MODE
);
2211 for (i
=0; i
< nr_count
; i
++)
2213 if (!nr_table
[i
].valid
)
2216 if (!(network_mode
& NET_PPP_MODE
))
2218 if (!strncmp(nr_table
[i
].tname_unit
, "ppp", 3))
2220 continue; /* skip any ppp interfaces */
2224 /* print the interface name */
2225 fprintf(stdout
, "%s %-8.8s", timebufptr
, nr_table
[i
].tname_unit
);
2227 fprintf (stdout
, "%8llu ",
2228 (nr_table
[i
].cur_ipackets
/ avg_interval
));
2230 fprintf (stdout
, "%10llu ",
2231 (nr_table
[i
].cur_ibytes
/ avg_interval
));
2233 fprintf (stdout
, "%8llu ",
2234 (nr_table
[i
].cur_opackets
/ avg_interval
));
2236 fprintf (stdout
, "%10llu\n",
2237 (nr_table
[i
].cur_obytes
/ avg_interval
));
2242 if (network_mode
& NET_EDEV_MODE
)
2246 print_column_heading(SAR_NETSTATS
, timebufptr
, NET_EDEV_MODE
);
2249 for (i
=0; i
< nr_count
; i
++)
2251 if (!nr_table
[i
].valid
)
2254 if (!(network_mode
& NET_PPP_MODE
))
2256 if (!strncmp(nr_table
[i
].tname_unit
, "ppp", 3))
2258 continue; /* skip any ppp interfaces */
2262 /* print the interface name */
2263 fprintf(stdout
, "%s %-8.8s ", timebufptr
, nr_table
[i
].tname_unit
);
2265 fprintf (stdout
, "%7llu ",
2266 (nr_table
[i
].cur_ierrors
/ avg_interval
));
2268 fprintf (stdout
, "%7llu ",
2269 (nr_table
[i
].cur_oerrors
/ avg_interval
));
2271 fprintf (stdout
, "%5llu ",
2272 (nr_table
[i
].cur_collisions
/ avg_interval
));
2274 fprintf (stdout
, " %5llu\n",
2275 (nr_table
[i
].cur_drops
/ avg_interval
));
2282 print_column_heading(int type
, char *timebufptr
, int mode
)
2291 if (!(flag_count
> 1))
2292 fprintf(stdout
, "\n");
2297 fprintf (stdout
, "\n%s %%usr %%sys %%idle\n", p
);
2301 if (mode
== 0) /* gflag */
2302 fprintf(stdout
, "\n%s pgout/s\n", p
);
2303 else if (mode
== 1) /* pflag */
2304 fprintf(stdout
, "\n%s pgin/s pflt/s vflt/s\n", p
);
2306 case SAR_DRIVESTATS
:
2307 fprintf(stdout
, "\n%s device r+w/s blks/s\n", p
);
2310 if (mode
== NET_DEV_MODE
)
2312 fprintf(stdout
, "\n%s %-8.8s %8.8s %10.10s %8.8s %10.10s\n", p
,
2313 " IFACE", "Ipkts/s", "Ibytes/s", "Opkts/s", "Obytes/s");
2315 else if (mode
== NET_EDEV_MODE
)
2317 fprintf(stdout
, "\n%s %-8.8s %7.7s %7.7s %5s %s\n", p
,
2318 " IFACE", "Ierrs/s", "Oerrs/s", "Coll/s", "Drop/s");