2 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
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
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.
22 cc -Wall -I. -I ../sadc.tproj -O -o sar sar.c
33 #include <mach/mach.h>
34 #include <sys/param.h>
35 #include <sys/sysctl.h>
41 #define IFNET_32_BIT_COUNTERS 1
43 /* Options used only for launching sadc */
44 int t_interval
= 5; /* in seconds */
45 char * t_intervalp
= "5";
46 int n_samples
= 1; /* number of sample loops */
47 char * n_samplesp
= "1";
49 /* Used only for storing the binary output after launching sadc */
50 char *outfile
= NULL
; /* output file */
51 int ofd
= 0; /* output file descriptor */
54 * When launching sadc, this file descriptor reads sadc's stdout
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
60 int ifd
= 0; /* input file descriptor */
61 char *infile
= NULL
; /* input file */
65 /* Used when we have to luanch sadc */
67 int fd
[2]; /* read from fd[0], write to fd[1] */
69 char *optionstring1
= "Adgn:puo:";
70 char *optionstring1_usage
= "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP } ] [-o filename] t [n]";
71 char *optionstring2
= "Adgn:pue:f:i:s:";
72 char *optionstring2_usage
= "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP }] [-e time] [-f filename] [-i sec] [-s time]";
80 int dflag
= 0; /* drive statistics */
81 int gflag
= 0; /* page-out activity */
85 int nflag
= 0; /* network statistics */
87 char *sadc_mflagp
= "-m";
88 char *sadc_ppp_modep
= "PPP";
90 int pflag
= 0; /* page-in activity */
93 int uflag
= 0; /* cpu utilization - this is the only default */
97 int set_default_flag
= 1;
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
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)
110 /* end time delimiter -- converted from hh:mm:ss to seconds */
114 int iseconds
= 0; /* interval seconds, default = 0 implies all samples are
117 /* start time delimiter -- converted from hh:mm:ss to seconds */
118 time_t start_time
= 0;
123 /* stat records average and previous */
124 struct vm_statistics prev_vmstat
, avg_vmstat
, cur_vmstat
;
125 host_cpu_load_info_data_t prev_cpuload
, avg_cpuload
, cur_cpuload
;
126 struct drivestats_report
*dr_head
= NULL
;
128 /* internal table of drive path mappings */
129 struct drivepath
*dp_table
= NULL
;
132 /* internal table of network interface statistics */
133 struct netstats_report
*nr_table
= NULL
;
135 struct netstats
*netstat_readbuf
= NULL
;
136 size_t netstat_readbuf_size
= 0;
139 int avg_interval
= 0;
143 /* Forward function declarations */
144 static void exit_usage();
145 static void open_output_file(char *path
);
146 static void open_input_file(char *path
);
147 static void read_record_hdr(struct record_hdr
*hdr
, int writeflag
);
148 static void read_record_data(char *buf
, size_t size
, int writeflag
);
149 static void write_record_hdr(struct record_hdr
*hdr
);
150 static void write_record_data(char *buf
, size_t size
);
151 static time_t convert_hms(char *string
);
152 static char *get_hms_string(time_t, char *);
153 static int find_restart_header(struct record_hdr
*);
154 static void print_all_column_headings (time_t timestamp
);
155 static void print_column_heading (int type
, char *timebufptr
, int mode
);
156 static void read_sample_set(int, time_t, struct record_hdr
*);
157 static void do_main_workloop();
158 static int bypass_sample_set(struct record_hdr
*, time_t);
159 static void skip_data(int);
160 static int get_cpu_sample(int flag
, struct record_hdr
*hdr
);
161 static void print_cpu_sample(char *timebufptr
);
162 static int get_vmstat_sample(int flag
, struct record_hdr
*hdr
);
163 static void print_vmstat_sample(char *timebufptr
);
165 static int get_drivestats_sample(int flag
, struct record_hdr
*hdr
);
166 static void init_drivestats(struct drivestats_report
*dr
);
167 static void print_drivestats_sample(char *timebufptr
);
168 static int get_drivepath_sample(int flag
, struct record_hdr
*hdr
);
170 static void set_cur_netstats(struct netstats_report
*nr
, struct netstats
*ns
);
171 static void init_prev_netstats(struct netstats_report
*nr
);
172 static int get_netstats_sample(int flag
, struct record_hdr
*hdr
);
173 static void print_netstats_sample(char *timebufptr
);
175 static void exit_average();
185 time_t curr_time
; /* current time in seconds */
187 char filenamebuf
[20];
188 char *optstring
= NULL
;
193 * Detirmine which option string to use
199 while((ch
=getopt(argc
, argv
, "aAbcdgkmn:pqruvwyo:e:f:i:s:")) != EOF
) {
202 if (optstringval
== 2)
204 optstring
=optionstring1
;
211 if (optstringval
== 1)
213 optstring
=optionstring2
;
224 /* still trying to determine which option string to use */
225 if (argc
- optind
> 0)
227 optstring
=optionstring1
; /* we should have a t_second value */
232 optstring
=optionstring2
;
237 optreset
= optind
= 1;
238 while ((ch
=getopt(argc
, argv
, optstring
)) != EOF
) {
242 set_default_flag
= 0;
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 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
;
290 set_default_flag
= 0;
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;
329 /* open the output file */
332 (void)open_output_file(outfile
);
334 case 'e': /* eflag */
335 end_time
= convert_hms(optarg
);
343 iseconds
=atoi(optarg
);
346 start_time
= convert_hms(optarg
);
354 /* setup default uflag option */
357 dflag
= gflag
= pflag
= uflag
= 1;
361 * Add network stats to the load
362 * but avoid PPP data by default.
365 network_mode
= NET_DEV_MODE
| NET_EDEV_MODE
;;
367 flag_count
= 2; /* triggers column headings */
369 else if (set_default_flag
)
377 if (network_mode
& NET_PPP_MODE
)
379 if (!(network_mode
& NET_DEV_MODE
) &&
380 !(network_mode
& NET_EDEV_MODE
))
383 network_mode
|= NET_DEV_MODE
;
384 network_mode
|= NET_EDEV_MODE
;
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
);
399 if (optstringval
== 1)
401 /* expecting a time interval */
408 t_interval
= strtol(argv
[0], &p
, 0);
409 t_intervalp
= argv
[0];
410 if (errno
|| (*p
!= '\0') || t_interval
<= 0 )
415 n_samples
= strtol(argv
[1], &p
, 0);
416 n_samplesp
= argv
[1];
417 if (errno
|| (*p
!= '\0') || n_samples
<= 0)
423 /* where does the input come from */
426 (void)open_input_file(infile
);
428 else if (optstringval
== 2)
431 * Create a filename of the form /var/log/sa/sadd
432 * where "dd" is the date of the month
434 curr_time
= time((time_t *)0); /* returns time in seconds */
437 timebuf will be a 26-character string of the form:
438 Thu Nov 24 18:22:48 1986\n\0
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
);
450 else if (optstringval
== 1)
455 fprintf(stderr
, "sar: pipe(2) failed, errno = (%d)\n",errno
);
459 if ((pid
=fork()) == 0)
464 int fdlimit
= getdtablesize();
466 /* This is the child */
467 /* Close all file descriptors except the one we need */
469 for (i
=0; i
< fdlimit
; i
++) {
470 if ((i
!= fd
[0]) && (i
!= fd
[1]))
474 efd
= open("/tmp/errlog", O_CREAT
|O_APPEND
|O_RDWR
, 0666);
475 if (dup2(efd
,2) == -1) {
479 /* Dup the two file descriptors to stdin and stdout */
480 if (dup2(fd
[0],0) == -1) {
483 if (dup2(fd
[1],1) == -1) {
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
);
490 execl("/usr/lib/sa/sadc", "sadc", t_intervalp
, n_samplesp
, NULL
);
492 perror("execlp sadc");
493 exit(2); /* This call of exit(2) should never be reached... */
496 { /* This is the parent */
498 fprintf(stderr
, "sar: fork(2) failed, errno = (%d)\n",errno
);
501 close (fd
[1]); /* parent does not write to the pipe */
502 ifd
= fd
[0]; /* parent will read from the pipe */
507 /* we're confused about source of input data - bail out */
508 fprintf(stderr
, "sar: no input file recognized\n");
512 /* start reading input data and format the output */
513 (void)do_main_workloop();
514 (void)exit_average();
521 fprintf(stderr
, "\n%s\n\n", optionstring1_usage
);
522 fprintf(stderr
, "%s\n", optionstring2_usage
);
527 open_output_file(char *path
)
529 if ((ofd
= open(path
, O_CREAT
|O_APPEND
|O_TRUNC
|O_WRONLY
, 0664)) == -1 )
531 /* failed to open path */
532 fprintf(stderr
, "sar: failed to open output file [%s]\n", path
);
539 open_input_file(char *path
)
541 if ((ifd
= open(path
, O_RDONLY
, 0)) == -1)
543 /* failed to open path */
544 fprintf(stderr
, "sar: failed to open input file [%d][%s]\n", ifd
, path
);
550 read_record_hdr(hdr
, writeflag
)
551 struct record_hdr
*hdr
;
559 size
= sizeof(struct record_hdr
);
563 num
= read(ifd
, &hdr
[n
], size
);
573 fprintf(stderr
, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno
, (int)num
, (int)size
);
578 if (oflag
&& writeflag
)
579 write_record_hdr(hdr
);
585 read_record_data(buf
, size
, writeflag
)
596 num
= read(ifd
, &buf
[n
], size
);
602 else if (num
== 0) /* EOF */
606 fprintf(stderr
, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno
, (int)num
, (int)size
);
611 if (oflag
&& writeflag
)
612 write_record_data(buf
, n
);
618 write_record_hdr(hdr
)
619 struct record_hdr
*hdr
;
624 if ((num
= write(ofd
, hdr
, sizeof(struct record_hdr
))) == -1)
626 fprintf(stderr
, "sar: write_record_hdr failed, errno=%d\n", errno
);
633 write_record_data(char *buf
, size_t nbytes
)
637 if ((num
= write(ofd
, buf
, nbytes
)) == -1)
639 fprintf(stderr
, "sar: write_record_data failed, errno=%d\n", errno
);
646 * Convert a string of one of the forms
648 * into the number of seconds.
656 int hh
= 0; /* hours */
657 int mm
= 0; /* minutes */
658 int ss
= 0; /* seconds */
664 if (string
== NULL
|| *string
== '\0')
667 for (i
=0; string
[i
] != '\0'; i
++)
669 if ((!isdigit(string
[i
])) && (string
[i
] != ':'))
675 if (sscanf(string
, "%d:%d:%d", &hh
, &mm
, &ss
) != 3)
677 if (sscanf(string
, "%d:%d", &hh
, &mm
) != 2)
679 if (sscanf(string
, "%d", &hh
) != 1)
686 if (hh
< 0 || hh
>= HOURS_PER_DAY
||
687 mm
< 0 || mm
>= MINS_PER_HOUR
||
688 ss
< 0 || ss
> SECS_PER_MIN
)
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
;
701 fprintf(stderr
, "sar: time format usage is hh[:mm[:ss]]\n");
708 * Use ctime_r to convert a time value into
709 * a 26-character string of the form:
711 * Thu Nov 24 18:22:48 1986\n\0
715 get_hms_string(tdata
, tbuf
)
731 /* sample set flags */
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 */
743 if (!find_restart_header(&hdr
))
746 cur_timestamp
= hdr
.rec_timestamp
;
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
;
752 start_time
+= cur_timestamp
- (cur_timestamp
% SECS_PER_DAY
);
754 /* convert end_time, from 24 hour clock time to UTC seconds */
756 end_time
+= cur_timestamp
- (cur_timestamp
% SECS_PER_DAY
);
759 fprintf(stderr
, "start = %ld, end = %ld, cur=%ld, [24hour - %ld]\n",
760 start_time
, end_time
, cur_timestamp
,(cur_timestamp
% SECS_PER_DAY
));
763 while (cur_timestamp
< start_time
)
765 bypass_sample_set(&hdr
, cur_timestamp
);
766 cur_timestamp
= hdr
.rec_timestamp
;
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
;
774 while ((end_time
== 0) || (next_timestamp
< end_time
))
776 if (cur_timestamp
< next_timestamp
)
778 bypass_sample_set (&hdr
, cur_timestamp
);
779 cur_timestamp
= hdr
.rec_timestamp
;
783 /* need to know the seconds interval when printing averages */
784 if (avg_interval
== 0)
787 avg_interval
= iseconds
;
789 avg_interval
= cur_timestamp
- next_timestamp
;
791 next_timestamp
= cur_timestamp
+ iseconds
;
792 read_sample_set(PRINT_SET
, cur_timestamp
, &hdr
);
793 cur_timestamp
= hdr
.rec_timestamp
;
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
807 find_restart_header (ret_hdr
)
808 struct record_hdr
*ret_hdr
;
810 struct record_hdr hdr
;
817 read_record_hdr(&hdr
, FALSE
); /* exits on error */
819 if (hdr
.rec_type
== SAR_RESTART
)
823 write_record_hdr(&hdr
); /* writes the RESTART record */
830 * not the record we want...
831 * read past data and try again
836 { /* seek past data in the file */
837 if ((lseek(ifd
, (hdr
.rec_count
* hdr
.rec_size
), SEEK_CUR
)) == -1)
840 fprintf(stderr
, "sar: lseek failed, errno=%d\n", errno
);
845 /* compute data size - malloc a new buf if it's not big enough */
848 /* have to read from the pipe */
849 if (bufsize
< (hdr
.rec_count
* hdr
.rec_size
))
853 bufsize
= hdr
.rec_count
* hdr
.rec_size
;
854 if((buf
= (char *)malloc(bufsize
)) == NULL
)
856 fprintf(stderr
, "sar: malloc failed\n");
861 read_record_data(buf
, (hdr
.rec_count
* hdr
.rec_size
), FALSE
);
868 print_all_column_headings(timestamp
)
874 timebufp
= get_hms_string (timestamp
, timebuf
);
876 if (uflag
) /* print cpu headers */
877 print_column_heading(SAR_CPU
, timebufp
, 0);
879 if (gflag
) /* print page-out activity */
880 print_column_heading(SAR_VMSTAT
, timebufp
, 0);
882 if (pflag
) /* print page-in activity */
883 print_column_heading(SAR_VMSTAT
, timebufp
, 1);
885 if (dflag
) /* print drive stats */
886 print_column_heading(SAR_DRIVESTATS
, timebufp
, 0);
888 if (nflag
) /* print network stats */
890 if (network_mode
& NET_DEV_MODE
)
891 print_column_heading(SAR_NETSTATS
, timebufp
, NET_DEV_MODE
);
893 if (network_mode
& NET_EDEV_MODE
)
894 print_column_heading(SAR_NETSTATS
, timebufp
, NET_EDEV_MODE
);
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
907 bypass_sample_set (ret_hdr
, timestamp
)
908 struct record_hdr
*ret_hdr
;
911 struct record_hdr hdr
;
916 read_record_hdr(&hdr
, TRUE
); /* exits on error */
918 if (hdr
.rec_type
== SAR_TIMESTAMP
)
927 * not the record we want...
928 * read past data and try again
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
939 if ((lseek(ifd
, (hdr
.rec_count
* hdr
.rec_size
), SEEK_CUR
)) == -1)
942 fprintf(stderr
, "sar: lseek failed, errno=%d\n", errno
);
949 * We end up here when reading from pipe.
950 * malloc a new buffer if current is not big enough
952 if (bufsize
< (hdr
.rec_count
* hdr
.rec_size
))
956 bufsize
= hdr
.rec_count
* hdr
.rec_size
;
957 if((buf
= (char *)malloc(bufsize
)) == NULL
)
959 fprintf(stderr
, "sar: malloc failed\n");
965 read_record_data(buf
, (hdr
.rec_count
* hdr
.rec_size
), TRUE
);
967 } /* end if hdr.rec_count */
973 * INIT_SET: This initializes the first sample for each type.
974 * PRINT_SET: This read, compute and print out sample data.
977 read_sample_set(flag
, timestamp
, ret_hdr
)
980 struct record_hdr
*ret_hdr
;
982 struct record_hdr hdr
;
986 char *indent_string_wide
;
987 char *indent_string_narrow
;
990 int sar_drivestats
=0;
992 int sar_netstats
= 0;
994 indent_string_wide
= " ";
995 indent_string_narrow
= " ";
996 indent_string
= indent_string_narrow
;
998 read_record_hdr(&hdr
, TRUE
);
1000 while (hdr
.rec_type
!= SAR_TIMESTAMP
)
1002 switch (hdr
.rec_type
)
1005 sar_cpu
= get_cpu_sample(flag
, &hdr
);
1008 sar_vmstat
=get_vmstat_sample(flag
, &hdr
);
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
);
1015 case SAR_DRIVESTATS
:
1016 sar_drivestats
= get_drivestats_sample(flag
, &hdr
);
1019 sar_netstats
= get_netstats_sample(flag
, &hdr
);
1025 read_record_hdr(&hdr
, TRUE
);
1028 /* return the timestamp header */
1031 if (flag
== PRINT_SET
)
1034 timebufp
= get_hms_string(timestamp
, timebuf
);
1036 if (uflag
&& sar_cpu
)
1037 print_cpu_sample(timebufp
);
1039 if((gflag
|| pflag
) && sar_vmstat
)
1040 print_vmstat_sample(timebufp
);
1042 if (dflag
&& sar_drivestats
)
1043 print_drivestats_sample(timebufp
);
1045 if (nflag
&& sar_netstats
)
1046 print_netstats_sample(timebufp
);
1058 /* seek past data in the file */
1059 if ((lseek(ifd
, bufsize
, SEEK_CUR
) == -1))
1062 fprintf(stderr
, "sar: lseek failed, errno=%d\n", errno
);
1068 /* have to read from the pipe */
1069 if((buf
= (char *)malloc(bufsize
)) == NULL
)
1071 fprintf(stderr
, "sar: malloc failed\n");
1074 /* even though we skip this data, we still write it if necessary */
1075 read_record_data(buf
, bufsize
, TRUE
);
1084 get_cpu_sample(flag
, hdr
)
1086 struct record_hdr
*hdr
;
1090 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1092 if (datasize
!= sizeof(host_cpu_load_info_data_t
))
1094 /* read past the data but don't do anything with it */
1095 skip_data(datasize
);
1099 read_record_data ((char *)&cur_cpuload
, (int)sizeof(host_cpu_load_info_data_t
), TRUE
);
1101 if (flag
== INIT_SET
)
1103 prev_cpuload
= cur_cpuload
;
1104 bzero(&avg_cpuload
, sizeof(avg_cpuload
));
1110 print_cpu_sample(timebufptr
)
1117 cur_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1118 -= prev_cpuload
.cpu_ticks
[CPU_STATE_USER
];
1120 prev_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1121 += cur_cpuload
.cpu_ticks
[CPU_STATE_USER
];
1123 time
+= cur_cpuload
.cpu_ticks
[CPU_STATE_USER
];
1125 cur_cpuload
.cpu_ticks
[CPU_STATE_NICE
]
1126 -= prev_cpuload
.cpu_ticks
[CPU_STATE_NICE
];
1128 prev_cpuload
.cpu_ticks
[CPU_STATE_NICE
]
1129 += cur_cpuload
.cpu_ticks
[CPU_STATE_NICE
];
1131 time
+= cur_cpuload
.cpu_ticks
[CPU_STATE_NICE
];
1133 cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1134 -= prev_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
];
1136 prev_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1137 += cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
];
1139 time
+= cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
];
1141 cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1142 -= prev_cpuload
.cpu_ticks
[CPU_STATE_IDLE
];
1144 prev_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1145 += cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
];
1147 time
+= cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
];
1149 avg_cpuload
.cpu_ticks
[CPU_STATE_USER
] += rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1150 / (time
? time
: 1));
1152 avg_cpuload
.cpu_ticks
[CPU_STATE_NICE
] += rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_NICE
]
1153 / (time
? time
: 1));
1155 avg_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
] += rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1156 / (time
? time
: 1));
1158 avg_cpuload
.cpu_ticks
[CPU_STATE_IDLE
] += rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1159 / (time
? time
: 1));
1162 print_column_heading(SAR_CPU
, timebufptr
, 0);
1164 fprintf(stdout
, "%s%5.0f ", timebufptr
,
1165 rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1166 / (time
? time
: 1)));
1168 fprintf(stdout
, "%4.0f ",
1169 rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_NICE
]
1170 / (time
? time
: 1)));
1172 fprintf(stdout
, "%4.0f ",
1173 rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1174 / (time
? time
: 1)));
1176 fprintf(stdout
, "%4.0f\n",
1177 rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1178 / (time
? time
: 1)));
1182 get_vmstat_sample(flag
, hdr
)
1184 struct record_hdr
*hdr
;
1188 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1190 if (datasize
!= sizeof(struct vm_statistics
))
1192 /* read past the data but don't do anything with it */
1193 skip_data(datasize
);
1197 read_record_data ((char *)&cur_vmstat
, (int)sizeof(struct vm_statistics
), TRUE
);
1199 if (flag
== INIT_SET
)
1201 prev_vmstat
= cur_vmstat
;
1202 bzero(&avg_vmstat
, sizeof(avg_vmstat
));
1209 print_vmstat_sample(char *timebufptr
)
1212 cur_vmstat
.faults
-= prev_vmstat
.faults
;
1213 prev_vmstat
.faults
+= cur_vmstat
.faults
;
1214 avg_vmstat
.faults
+= cur_vmstat
.faults
;
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
;
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
;
1224 cur_vmstat
.reactivations
-= prev_vmstat
.reactivations
;
1225 prev_vmstat
.reactivations
+= cur_vmstat
.reactivations
;
1226 avg_vmstat
.reactivations
+= cur_vmstat
.reactivations
;
1228 cur_vmstat
.pageins
-= prev_vmstat
.pageins
;
1229 prev_vmstat
.pageins
+= cur_vmstat
.pageins
;
1230 avg_vmstat
.pageins
+= cur_vmstat
.pageins
;
1232 cur_vmstat
.pageouts
-= prev_vmstat
.pageouts
;
1233 prev_vmstat
.pageouts
+= cur_vmstat
.pageouts
;
1234 avg_vmstat
.pageouts
+= cur_vmstat
.pageouts
;
1240 print_column_heading(SAR_VMSTAT
, timebufptr
, 0);
1241 fprintf(stdout
, "%s %8.1f \n", timebufptr
, (float)((float)cur_vmstat
.pageouts
/avg_interval
));
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
));
1257 get_drivestats_sample(flag
, hdr
)
1259 struct record_hdr
*hdr
;
1261 struct drivestats
*databuf
;
1262 struct drivestats_report
*dr
;
1268 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1269 datacount
= hdr
->rec_count
;
1271 if (hdr
->rec_size
!= sizeof(struct drivestats
))
1273 /* something isn't right... read past the data but don't analyze it */
1274 skip_data(datasize
);
1278 /* malloc read buffer */
1279 if ((databuf
= (struct drivestats
*)malloc(datasize
)) == NULL
)
1281 fprintf(stderr
, "sar: malloc failed\n");
1282 exit (EXIT_FAILURE
);
1285 bzero(databuf
, datasize
);
1287 read_record_data ((char *)databuf
, datasize
, TRUE
);
1289 /* clear all global current fields */
1290 for(dr
= dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1294 dr
->cur_BytesRead
= 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;
1307 /* By this point, we have read in a complete set of diskstats from the sadc
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
1315 for (i
=0; i
< datacount
; i
++)
1317 struct drivestats_report
*dr_last
= NULL
;
1319 index
= databuf
[i
].drivepath_id
; /* use this as index into dp_table */
1321 /* find disk entry or allocate new one*/
1322 for(dr
= dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1325 if(index
== dr
->drivepath_id
)
1331 /* allocate new entry */
1332 if((dr
= (struct drivestats_report
*)malloc(sizeof(struct drivestats_report
))) == NULL
)
1334 fprintf(stderr
, "sar: malloc error\n");
1337 bzero((char *)dr
, sizeof(struct drivestats_report
));
1338 dr
->blocksize
= databuf
[i
].blocksize
;
1339 dr
->drivepath_id
= index
;
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);
1347 strcpy(dr
->name
, "disk??");
1349 if (dr_head
== NULL
)
1352 dr_head
->next
= NULL
;
1356 dr_last
->next
= (char *)dr
;
1358 } /* end if dr == NULL */
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 */
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
1380 for(dr
= dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1382 if (dr
->drivepath_id
>= dp_count
)
1384 /* something is amiss */
1389 index
= dr
->drivepath_id
; /* use this as index into dp_table */
1392 if ((flag
== INIT_SET
) ||
1393 (dp_table
[index
].state
== DPSTATE_NEW
) ||
1394 (dp_table
[index
].state
== DPSTATE_CHANGED
) ||
1398 * prev will be set to cur
1399 * activate the state in dp_table
1402 dp_table
[index
].state
= DPSTATE_ACTIVE
;
1404 init_drivestats(dr
);
1411 init_drivestats(struct drivestats_report
*dr
)
1414 dr
->prev_Reads
= dr
->cur_Reads
;
1416 dr
->prev_BytesRead
= dr
->cur_BytesRead
;
1417 dr
->avg_BytesRead
= 0;
1418 dr
->prev_Writes
= dr
->cur_Writes
;
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;
1442 print_drivestats_sample(char *timebufptr
)
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
;
1452 print_column_heading(SAR_DRIVESTATS
, timebufptr
, 0);
1454 for (dr
=dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
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.
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
))
1470 init_drivestats(dr
);
1476 dr
->cur_Reads
-= dr
->prev_Reads
;
1477 dr
->prev_Reads
+= dr
->cur_Reads
;
1478 dr
->avg_Reads
+= dr
->cur_Reads
;
1480 dr
->cur_BytesRead
-= dr
->prev_BytesRead
;
1481 dr
->prev_BytesRead
+= dr
->cur_BytesRead
;
1482 dr
->avg_BytesRead
+= dr
->cur_BytesRead
;
1484 dr
->cur_Writes
-= dr
->prev_Writes
;
1485 dr
->prev_Writes
+= dr
->cur_Writes
;
1486 dr
->avg_Writes
+= dr
->cur_Writes
;
1488 dr
->cur_BytesWritten
-= dr
->prev_BytesWritten
;
1489 dr
->prev_BytesWritten
+= dr
->cur_BytesWritten
;
1490 dr
->avg_BytesWritten
+= dr
->cur_BytesWritten
;
1492 dr
->cur_LatentReadTime
-= dr
->prev_LatentReadTime
;
1493 dr
->prev_LatentReadTime
+= dr
->cur_LatentReadTime
;
1494 dr
->avg_LatentReadTime
+= dr
->cur_LatentReadTime
;
1496 dr
->cur_LatentWriteTime
-= dr
->prev_LatentWriteTime
;
1497 dr
->prev_LatentWriteTime
+= dr
->cur_LatentWriteTime
;
1498 dr
->avg_LatentWriteTime
+= dr
->cur_LatentWriteTime
;
1500 dr
->cur_ReadErrors
-= dr
->prev_ReadErrors
;
1501 dr
->prev_ReadErrors
+= dr
->cur_ReadErrors
;
1502 dr
->avg_ReadErrors
+= dr
->cur_ReadErrors
;
1504 dr
->cur_WriteErrors
-= dr
->prev_WriteErrors
;
1505 dr
->prev_WriteErrors
+= dr
->cur_WriteErrors
;
1506 dr
->avg_WriteErrors
+= dr
->cur_WriteErrors
;
1508 dr
->cur_ReadRetries
-= dr
->prev_ReadRetries
;
1509 dr
->prev_ReadRetries
+= dr
->cur_ReadRetries
;
1510 dr
->avg_ReadRetries
+= dr
->cur_ReadRetries
;
1512 dr
->cur_WriteRetries
-= dr
->prev_WriteRetries
;
1513 dr
->prev_WriteRetries
+= dr
->cur_WriteRetries
;
1514 dr
->avg_WriteRetries
+= dr
->cur_WriteRetries
;
1516 dr
->cur_TotalReadTime
-= dr
->prev_TotalReadTime
;
1517 dr
->prev_TotalReadTime
+= dr
->cur_TotalReadTime
;
1518 dr
->avg_TotalReadTime
+= dr
->cur_TotalReadTime
;
1520 dr
->cur_TotalWriteTime
-= dr
->prev_TotalWriteTime
;
1521 dr
->prev_TotalWriteTime
+= dr
->cur_TotalWriteTime
;
1522 dr
->avg_TotalWriteTime
+= dr
->cur_TotalWriteTime
;
1525 interval_bytes
= dr
->cur_BytesRead
+ dr
->cur_BytesWritten
;
1528 interval_transfers
= dr
->cur_Reads
+ dr
->cur_Writes
;
1531 interval_time
= dr
->cur_LatentReadTime
+ dr
->cur_LatentWriteTime
;
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);
1538 kb_per_transfer
= (interval_transfers
> 0) ?
1539 ((long double)interval_bytes
/ interval_transfers
)
1542 /* times are in nanoseconds, convert to milliseconds */
1543 ms_per_transaction
= (interval_transfers
> 0) ?
1544 ((long double)interval_time
/ interval_transfers
)
1547 /* print device name */
1548 fprintf(stdout
, "%s %-10s", timebufptr
, dr
->name
);
1550 /* print transfers per second */
1551 fprintf(stdout
, "%4.0Lf ", transfers_per_second
);
1553 /* print blocks per second - in device blocksize */
1554 fprintf(stdout
, "%4.0Lf\n", blocks_per_second
);
1559 * Print averages before exiting.
1566 if (avg_counter
<= 0 )
1576 if (uflag
) /* print cpu averages */
1579 print_column_heading(SAR_CPU
, 0, 0);
1581 fprintf(stdout
, "Average: %5d ",
1582 (int)avg_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1583 / (avg_counter
? avg_counter
: 1));
1585 fprintf(stdout
, "%4d ",
1586 (int)avg_cpuload
.cpu_ticks
[CPU_STATE_NICE
]
1587 / (avg_counter
? avg_counter
: 1));
1589 fprintf(stdout
, "%4d ",
1590 (int)avg_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1591 / (avg_counter
? avg_counter
: 1));
1593 fprintf(stdout
, "%4d \n",
1594 (int)avg_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1595 / (avg_counter
? avg_counter
: 1));
1601 if (gflag
) /* print page-out averages */
1604 print_column_heading(SAR_VMSTAT
, 0, 0);
1606 fprintf(stdout
, "Average: %8.1f\n",
1607 (float)((avg_vmstat
.pageouts
/ (avg_counter
? avg_counter
: 1)) / avg_interval
));
1611 if (pflag
) /* print page-in averages */
1614 print_column_heading(SAR_VMSTAT
, 0, 1);
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
));
1623 if (dflag
) /* print drivestats averages */
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
;
1634 print_column_heading(SAR_DRIVESTATS
, 0, 0);
1636 for (dr
=dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1638 /* don't bother to print out averages for disks that were removed */
1642 fprintf(stdout
, " %s %s\n",
1643 dp_table
[dr
->drivepath_id
].BSDName
, dp_table
[dr
->drivepath_id
].ioreg_path
);
1646 total_bytes
= dr
->avg_BytesRead
+ dr
->avg_BytesWritten
;
1649 total_transfers
= dr
->avg_Reads
+ dr
->avg_Writes
;
1652 total_time
= dr
->avg_LatentReadTime
+ dr
->avg_LatentWriteTime
;
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);
1659 kb_per_transfer
= (total_transfers
> 0) ?
1660 ((long double)total_bytes
/ total_transfers
)
1663 /* times are in nanoseconds, convert to milliseconds */
1664 ms_per_transaction
= (total_transfers
> 0) ?
1665 ((long double)total_time
/ total_transfers
)
1667 msdig
= (ms_per_transaction
< 100.0) ? 1 : 0;
1668 fprintf(stdout
, "Average: %-10s %4.0Lf %4.0Lf\n",
1670 (transfers_per_second
/ dr
->avg_count
),
1671 (blocks_per_second
/ dr
->avg_count
));
1675 } /* end if dflag */
1681 if (network_mode
& NET_DEV_MODE
)
1684 print_column_heading(SAR_NETSTATS
, 0, NET_DEV_MODE
);
1685 for (i
= 0; i
< nr_count
; i
++)
1687 if (!nr_table
[i
].valid
)
1690 if(nr_table
[i
].avg_count
== 0)
1693 avg_count
= nr_table
[i
].avg_count
;
1695 fprintf(stdout
, "Average: %-8.8s", nr_table
[i
].tname_unit
);
1697 fprintf (stdout
, "%8llu ",
1698 ((nr_table
[i
].avg_ipackets
/ avg_count
) / avg_interval
));
1700 fprintf (stdout
, "%10llu ",
1701 ((nr_table
[i
].avg_ibytes
/ avg_count
) / avg_interval
));
1703 fprintf (stdout
, "%8llu ",
1704 ((nr_table
[i
].avg_opackets
/ avg_count
) / avg_interval
));
1706 fprintf (stdout
, "%10llu\n",
1707 ((nr_table
[i
].avg_obytes
/ avg_count
) / avg_interval
));
1713 if (network_mode
& NET_EDEV_MODE
)
1717 print_column_heading(SAR_NETSTATS
, 0, NET_EDEV_MODE
);
1719 for (i
= 0; i
< nr_count
; i
++)
1721 if (!nr_table
[i
].valid
)
1724 if(nr_table
[i
].avg_count
== 0)
1727 avg_count
= nr_table
[i
].avg_count
;
1729 fprintf(stdout
, "Average: %-8.8s ", nr_table
[i
].tname_unit
);
1731 fprintf (stdout
, "%7llu ",
1732 ((nr_table
[i
].avg_ierrors
/ avg_count
) / avg_interval
));
1734 fprintf (stdout
, "%7llu ",
1735 ((nr_table
[i
].avg_oerrors
/ avg_count
) / avg_interval
));
1737 fprintf (stdout
, "%5llu ",
1738 ((nr_table
[i
].avg_collisions
/ avg_count
) / avg_interval
));
1740 fprintf (stdout
, " %5llu\n",
1741 ((nr_table
[i
].avg_drops
/ avg_count
) / avg_interval
));
1747 } /* end if nflag */
1753 * Return < 0 failure, debugging purposes only
1754 * Return = 0 data skipped
1755 * Return > 0 success
1759 get_drivepath_sample(flag
, hdr
)
1761 struct record_hdr
*hdr
;
1764 struct drivepath dp
;
1765 struct drivestats_report
*dr
;
1768 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1770 if (datasize
!= sizeof(struct drivepath
))
1772 /* read past the data but don't do anything with it */
1773 skip_data(datasize
);
1777 read_record_data ((char *)&dp
, (int)sizeof(struct drivepath
), TRUE
);
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.
1784 if (dp
.state
== DPSTATE_NEW
)
1787 if (dp_table
== NULL
)
1789 if (dp
.drivepath_id
!= 0)
1791 /* First setup of internal drivepath table */
1792 dp_table
= (struct drivepath
*)malloc(sizeof(struct drivepath
));
1793 if (dp_table
== NULL
)
1799 fprintf(stdout
, "New Disk: [%s] %s\n", dp
.BSDName
, dp
.ioreg_path
);
1801 /* traverse table and find next uninitialized entry */
1802 for (i
= 0; i
< dp_count
; i
++)
1804 if (dp_table
[i
].state
== DPSTATE_UNINITIALIZED
)
1806 if (dp
.drivepath_id
!= i
)
1808 /* the table is out of sync - this should not happen */
1816 * If we get here, we've run out of table entries.
1817 * Double the size of the table, then assign the next entry.
1819 if (dp
.drivepath_id
!= i
)
1821 /* the table is out of sync - this should not happen */
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
;
1832 else if (dp
.state
== DPSTATE_CHANGED
)
1835 /* Update the name in the table */
1836 if ((dp
.drivepath_id
< dp_count
) && (dp_table
[dp
.drivepath_id
].state
!= DPSTATE_UNINITIALIZED
))
1838 if (strcmp(dp_table
[dp
.drivepath_id
].ioreg_path
, dp
.ioreg_path
) != 0)
1840 /* something is amiss */
1847 fprintf(stdout
, "Change: [%s] %s\n", dp
.BSDName
,
1848 dp_table
[dp
.drivepath_id
].ioreg_path
);
1850 strcpy(dp_table
[dp
.drivepath_id
].BSDName
, dp
.BSDName
);
1852 for(dr
= dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1854 if (dr
->drivepath_id
== dp
.drivepath_id
)
1855 strcpy(dr
->name
, dp
.BSDName
);
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.
1873 set_cur_netstats(struct netstats_report
*nr
, struct netstats
*ns
)
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
;
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
;
1886 nr
->cur_imcasts
= ns
->net_imcasts
;
1887 nr
->cur_omcasts
= ns
->net_omcasts
;
1892 init_prev_netstats(struct netstats_report
*nr
)
1898 nr
->prev_ipackets
= nr
->cur_ipackets
;
1899 nr
->avg_ipackets
= 0;
1900 nr
->prev_ibytes
= nr
->cur_ibytes
;
1902 nr
->prev_opackets
= nr
->cur_opackets
;
1903 nr
->avg_opackets
= 0;
1904 nr
->prev_obytes
= nr
->cur_obytes
;
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
;
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;
1928 get_netstats_sample(flag
, hdr
)
1930 struct record_hdr
*hdr
;
1932 struct netstats
*databuf
= NULL
;
1937 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1938 datacount
= hdr
->rec_count
;
1940 if (hdr
->rec_size
!= sizeof(struct netstats
))
1942 /* something isn't right... read past the data but don't analyze it */
1943 skip_data(datasize
);
1947 /* malloc new or bigger read buffer */
1948 if((netstat_readbuf
== NULL
) || (netstat_readbuf_size
< datasize
))
1950 if (netstat_readbuf
)
1951 free (netstat_readbuf
);
1953 if ((netstat_readbuf
= (struct netstats
*)malloc(datasize
)) == NULL
)
1955 fprintf(stderr
, "sar: malloc failed\n");
1956 exit (EXIT_FAILURE
);
1958 netstat_readbuf_size
= datasize
;
1961 bzero(netstat_readbuf
, netstat_readbuf_size
);
1962 databuf
= netstat_readbuf
;
1964 read_record_data ((char *)databuf
, datasize
, TRUE
);
1966 if (nr_table
== NULL
)
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
)));
1973 /* on first init, this is faster than finding our way to NEW_ENTRY */
1974 for (i
= 0; i
< datacount
; i
++)
1976 if (!(network_mode
& NET_PPP_MODE
))
1978 if (!strncmp(databuf
[i
].tname_unit
, "ppp", 3))
1980 * Skip ppp interfaces.
1981 * ie don't even put them in this internal table.
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
]);
1993 * clear all the present flags.
1994 * As we traverse the current sample set
1995 * and update the internal table, the flag
1998 for (i
= 0; i
< nr_count
; i
++)
2000 nr_table
[i
].present
= 0;
2004 * Find and update table entries.
2007 for (i
=0; i
<datacount
; i
++)
2014 name
= databuf
[i
].tname_unit
;
2017 if (!(network_mode
& NET_PPP_MODE
))
2019 if (!strncmp(name
, "ppp", 3))
2020 continue; /* skip ppp interfaces */
2023 /* Find the matching entry using the interface name */
2024 for (j
=0; j
< nr_count
&& !found
; j
++)
2026 if (nr_table
[j
].valid
)
2028 if(!strcmp(nr_table
[j
].tname_unit
, name
))
2031 nr_table
[j
].present
= 1;
2032 set_cur_netstats(&nr_table
[j
], &databuf
[i
]);
2037 if (!found
) /* this is a new entry */
2039 /* Find an invalid entry in the table and init it */
2040 for (j
=0; j
< nr_count
; j
++)
2042 if (!nr_table
[j
].valid
)
2049 /* we ran out of entries... grow the table */
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
;
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
]);
2066 * Traverse the internal table. Any valid entry that wasn't
2067 * present in this sample is cleared for reuse.
2069 for (i
= 0; i
< nr_count
; i
++)
2071 if (nr_table
[i
].valid
)
2073 if (nr_table
[i
].present
== 0)
2074 bzero(&nr_table
[i
], sizeof(struct netstats_report
));
2081 print_netstats_sample(char *timebufptr
)
2085 for (i
=0; i
< nr_count
; i
++)
2087 if (!nr_table
[i
].valid
)
2091 * This is where we attempt to handle counters that
2092 * might wrap ... the kernel netstats are only 32 bits.
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.
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.
2108 if (network_mode
& NET_PPP_MODE
)
2111 * ppp interfaces won't even make it into this table
2112 * when NET_PPP_MODE isn't set
2114 if (!strncmp(nr_table
[i
].tname_unit
, "ppp", 3))
2117 * Both ipackets and opackets have to be less
2118 * than the previous counter to cause us to reinit.
2121 if ((nr_table
[i
].cur_ipackets
< nr_table
[i
].prev_ipackets
)
2122 && (nr_table
[i
].cur_opackets
< nr_table
[i
].prev_opackets
))
2124 init_prev_netstats(&nr_table
[i
]);
2130 nr_table
[i
].avg_count
++;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
2218 if (!(flag_count
> 1))
2219 fprintf(stdout
, "\n");
2221 if (network_mode
& NET_DEV_MODE
)
2224 print_column_heading(SAR_NETSTATS
, timebufptr
, NET_DEV_MODE
);
2226 for (i
=0; i
< nr_count
; i
++)
2228 if (!nr_table
[i
].valid
)
2231 if (!(network_mode
& NET_PPP_MODE
))
2233 if (!strncmp(nr_table
[i
].tname_unit
, "ppp", 3))
2235 continue; /* skip any ppp interfaces */
2239 /* print the interface name */
2240 fprintf(stdout
, "%s %-8.8s", timebufptr
, nr_table
[i
].tname_unit
);
2242 fprintf (stdout
, "%8llu ",
2243 (nr_table
[i
].cur_ipackets
/ avg_interval
));
2245 fprintf (stdout
, "%10llu ",
2246 (nr_table
[i
].cur_ibytes
/ avg_interval
));
2248 fprintf (stdout
, "%8llu ",
2249 (nr_table
[i
].cur_opackets
/ avg_interval
));
2251 fprintf (stdout
, "%10llu\n",
2252 (nr_table
[i
].cur_obytes
/ avg_interval
));
2257 if (network_mode
& NET_EDEV_MODE
)
2261 print_column_heading(SAR_NETSTATS
, timebufptr
, NET_EDEV_MODE
);
2264 for (i
=0; i
< nr_count
; i
++)
2266 if (!nr_table
[i
].valid
)
2269 if (!(network_mode
& NET_PPP_MODE
))
2271 if (!strncmp(nr_table
[i
].tname_unit
, "ppp", 3))
2273 continue; /* skip any ppp interfaces */
2277 /* print the interface name */
2278 fprintf(stdout
, "%s %-8.8s ", timebufptr
, nr_table
[i
].tname_unit
);
2280 fprintf (stdout
, "%7llu ",
2281 (nr_table
[i
].cur_ierrors
/ avg_interval
));
2283 fprintf (stdout
, "%7llu ",
2284 (nr_table
[i
].cur_oerrors
/ avg_interval
));
2286 fprintf (stdout
, "%5llu ",
2287 (nr_table
[i
].cur_collisions
/ avg_interval
));
2289 fprintf (stdout
, " %5llu\n",
2290 (nr_table
[i
].cur_drops
/ avg_interval
));
2297 print_column_heading(int type
, char *timebufptr
, int mode
)
2306 if (!(flag_count
> 1))
2307 fprintf(stdout
, "\n");
2312 fprintf (stdout
, "\n%s %%usr %%nice %%sys %%idle\n", p
);
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
);
2321 case SAR_DRIVESTATS
:
2322 fprintf(stdout
, "\n%s device r+w/s blks/s\n", p
);
2325 if (mode
== NET_DEV_MODE
)
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");
2330 else if (mode
== NET_EDEV_MODE
)
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");