2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
26 cc -Wall -Wno-long-double -I. -I ../sadc.tproj -O -o sar sar.c
37 #include <mach/mach.h>
38 #include <sys/param.h>
39 #include <sys/sysctl.h>
45 #define IFNET_32_BIT_COUNTERS 1
47 /* Options used only for launching sadc */
48 int t_interval
= 5; /* in seconds */
49 char * t_intervalp
= "5";
50 int n_samples
= 1; /* number of sample loops */
51 char * n_samplesp
= "1";
53 /* Used only for storing the binary output after launching sadc */
54 char *outfile
= NULL
; /* output file */
55 int ofd
= 0; /* output file descriptor */
58 * When launching sadc, this file descriptor reads sadc's stdout
60 * When not launching sadc, this file descriptor will be either
61 * the input file passed in with the -f flag
62 * or the standard input file /var/log/sa/saXX
64 int ifd
= 0; /* input file descriptor */
65 char *infile
= NULL
; /* input file */
69 /* Used when we have to luanch sadc */
71 int fd
[2]; /* read from fd[0], write to fd[1] */
73 char *optionstring1
= "Adgn:puo:";
74 char *optionstring1_usage
= "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP } ] [-o filename] t [n]";
75 char *optionstring2
= "Adgn:pue:f:i:s:";
76 char *optionstring2_usage
= "/usr/bin/sar [-Adgpu] [-n { DEV | EDEV | PPP }] [-e time] [-f filename] [-i sec] [-s time]";
84 int dflag
= 0; /* drive statistics */
85 int gflag
= 0; /* page-out activity */
89 int nflag
= 0; /* network statistics */
91 char *sadc_mflagp
= "-m";
92 char *sadc_ppp_modep
= "PPP";
94 int pflag
= 0; /* page-in activity */
97 int uflag
= 0; /* cpu utilization - this is the only default */
101 int set_default_flag
= 1;
105 * To get the current time of day in seconds
106 * based on a 24 hour clock, pass in the time_t from time()
107 * the remainder is the current time in seconds
109 #define HOURS_PER_DAY 24
110 #define MINS_PER_HOUR 60
111 #define SECS_PER_MIN 60
112 #define SECS_PER_DAY (SECS_PER_MIN * MINS_PER_HOUR * HOURS_PER_DAY)
114 /* end time delimiter -- converted from hh:mm:ss to seconds */
118 int iseconds
= 0; /* interval seconds, default = 0 implies all samples are
121 /* start time delimiter -- converted from hh:mm:ss to seconds */
122 time_t start_time
= 0;
127 /* stat records average and previous */
128 struct vm_statistics prev_vmstat
, avg_vmstat
, cur_vmstat
;
129 host_cpu_load_info_data_t prev_cpuload
, avg_cpuload
, cur_cpuload
;
130 struct drivestats_report
*dr_head
= NULL
;
132 /* internal table of drive path mappings */
133 struct drivepath
*dp_table
= NULL
;
136 /* internal table of network interface statistics */
137 struct netstats_report
*nr_table
= NULL
;
139 struct netstats
*netstat_readbuf
= NULL
;
140 size_t netstat_readbuf_size
= 0;
143 int avg_interval
= 0;
147 /* Forward function declarations */
148 static void exit_usage();
149 static void open_output_file(char *path
);
150 static void open_input_file(char *path
);
151 static void read_record_hdr(struct record_hdr
*hdr
, int writeflag
);
152 static void read_record_data(char *buf
, size_t size
, int writeflag
);
153 static void write_record_hdr(struct record_hdr
*hdr
);
154 static void write_record_data(char *buf
, size_t size
);
155 static long convert_hms(char *string
);
156 static char *get_hms_string(time_t, char *);
157 static int find_restart_header(struct record_hdr
*);
158 static void print_all_column_headings (time_t timestamp
);
159 static void print_column_heading (int type
, char *timebufptr
, int mode
);
160 static void read_sample_set(int, time_t, struct record_hdr
*);
161 static void do_main_workloop();
162 static int bypass_sample_set(struct record_hdr
*, time_t);
163 static void skip_data(int);
164 static int get_cpu_sample(int flag
, struct record_hdr
*hdr
);
165 static void print_cpu_sample(char *timebufptr
);
166 static int get_vmstat_sample(int flag
, struct record_hdr
*hdr
);
167 static void print_vmstat_sample(char *timebufptr
);
169 static int get_drivestats_sample(int flag
, struct record_hdr
*hdr
);
170 static void init_drivestats(struct drivestats_report
*dr
);
171 static void print_drivestats_sample(char *timebufptr
);
172 static int get_drivepath_sample(int flag
, struct record_hdr
*hdr
);
174 static void set_cur_netstats(struct netstats_report
*nr
, struct netstats
*ns
);
175 static void init_prev_netstats(struct netstats_report
*nr
);
176 static int get_netstats_sample(int flag
, struct record_hdr
*hdr
);
177 static void print_netstats_sample(char *timebufptr
);
179 static void exit_average();
189 time_t curr_time
; /* current time in seconds */
191 char filenamebuf
[20];
192 char *optstring
= NULL
;
197 * Detirmine which option string to use
203 while((ch
=getopt(argc
, argv
, "aAbcdgkmn:pqruvwyo:e:f:i:s:")) != EOF
) {
206 if (optstringval
== 2)
208 optstring
=optionstring1
;
215 if (optstringval
== 1)
217 optstring
=optionstring2
;
228 /* still trying to determine which option string to use */
229 if (argc
- optind
> 0)
231 optstring
=optionstring1
; /* we should have a t_second value */
236 optstring
=optionstring2
;
241 optreset
= optind
= 1;
242 while ((ch
=getopt(argc
, argv
, optstring
)) != EOF
) {
246 set_default_flag
= 0;
251 set_default_flag
= 0;
256 set_default_flag
= 0;
261 set_default_flag
= 0;
266 set_default_flag
= 0;
271 set_default_flag
= 0;
276 set_default_flag
= 0;
281 set_default_flag
= 0;
286 if (!strncmp(optarg
, "PPP", 3))
287 network_mode
|= NET_PPP_MODE
;
288 else if (!strncmp(optarg
, "DEV", 3))
289 network_mode
|= NET_DEV_MODE
;
290 else if (!strncmp(optarg
, "EDEV", 4))
291 network_mode
|= NET_EDEV_MODE
;
294 set_default_flag
= 0;
299 set_default_flag
= 0;
304 set_default_flag
= 0;
309 set_default_flag
= 0;
314 set_default_flag
= 0;
319 set_default_flag
= 0;
324 set_default_flag
= 0;
329 set_default_flag
= 0;
333 /* open the output file */
336 (void)open_output_file(outfile
);
338 case 'e': /* eflag */
339 end_time
= convert_hms(optarg
);
347 iseconds
=atoi(optarg
);
350 start_time
= convert_hms(optarg
);
358 /* setup default uflag option */
361 dflag
= gflag
= pflag
= uflag
= 1;
365 * Add network stats to the load
366 * but avoid PPP data by default.
369 network_mode
= NET_DEV_MODE
| NET_EDEV_MODE
;;
371 flag_count
= 2; /* triggers column headings */
373 else if (set_default_flag
)
381 if (network_mode
& NET_PPP_MODE
)
383 if (!(network_mode
& NET_DEV_MODE
) &&
384 !(network_mode
& NET_EDEV_MODE
))
387 network_mode
|= NET_DEV_MODE
;
388 network_mode
|= NET_EDEV_MODE
;
397 /* set up signal handlers */
398 signal(SIGINT
, exit_average
);
399 signal(SIGQUIT
, exit_average
);
400 signal(SIGHUP
, exit_average
);
401 signal(SIGTERM
, exit_average
);
403 if (optstringval
== 1)
405 /* expecting a time interval */
412 t_interval
= strtol(argv
[0], &p
, 0);
413 t_intervalp
= argv
[0];
414 if (errno
|| (*p
!= '\0') || t_interval
<= 0 )
419 n_samples
= strtol(argv
[1], &p
, 0);
420 n_samplesp
= argv
[1];
421 if (errno
|| (*p
!= '\0') || n_samples
<= 0)
427 /* where does the input come from */
430 (void)open_input_file(infile
);
432 else if (optstringval
== 2)
435 * Create a filename of the form /var/log/sa/sadd
436 * where "dd" is the date of the month
438 curr_time
= time((time_t *)0); /* returns time in seconds */
441 timebuf will be a 26-character string of the form:
442 Thu Nov 24 18:22:48 1986\n\0
445 ctime_r(&curr_time
, timebuf
);
446 strncpy(filenamebuf
, "/var/log/sa/sa", 14);
447 strncpy(&filenamebuf
[14], &timebuf
[8], 2);
448 if (filenamebuf
[14] == ' ')
449 filenamebuf
[14] = '0';
450 filenamebuf
[16]='\0';
451 infile
= filenamebuf
;
452 (void)open_input_file(infile
);
454 else if (optstringval
== 1)
459 fprintf(stderr
, "sar: pipe(2) failed, errno = (%d)\n",errno
);
463 if ((pid
=fork()) == 0)
469 /* This is the child */
470 /* Close all file descriptors except the one we need */
472 for (i
=0; i
<= KERN_MAXFILESPERPROC
; i
++) {
473 if ((i
!= fd
[0]) && (i
!= fd
[1]))
477 efd
= open("/tmp/errlog", O_CREAT
|O_APPEND
|O_RDWR
, 0666);
478 if (dup2(efd
,2) == -1) {
482 /* Dup the two file descriptors to stdin and stdout */
483 if (dup2(fd
[0],0) == -1) {
486 if (dup2(fd
[1],1) == -1) {
489 /* Exec the child process */
490 if (network_mode
& NET_PPP_MODE
)
491 execl("/usr/lib/sa/sadc", "sadc", sadc_mflagp
, sadc_ppp_modep
, t_intervalp
, n_samplesp
, NULL
);
493 execl("/usr/lib/sa/sadc", "sadc", t_intervalp
, n_samplesp
, NULL
);
495 perror("execlp sadc");
496 exit(2); /* This call of exit(2) should never be reached... */
499 { /* This is the parent */
501 fprintf(stderr
, "sar: fork(2) failed, errno = (%d)\n",errno
);
504 close (fd
[1]); /* parent does not write to the pipe */
505 ifd
= fd
[0]; /* parent will read from the pipe */
510 /* we're confused about source of input data - bail out */
511 fprintf(stderr
, "sar: no input file recognized\n");
515 /* start reading input data and format the output */
516 (void)do_main_workloop();
517 (void)exit_average();
524 fprintf(stderr
, "\n%s\n\n", optionstring1_usage
);
525 fprintf(stderr
, "%s\n", optionstring2_usage
);
530 open_output_file(char *path
)
532 if ((ofd
= open(path
, O_CREAT
|O_APPEND
|O_TRUNC
|O_WRONLY
, 0664)) == -1 )
534 /* failed to open path */
535 fprintf(stderr
, "sar: failed to open output file [%s]\n", path
);
542 open_input_file(char *path
)
544 if ((ifd
= open(path
, O_RDONLY
, 0)) == -1)
546 /* failed to open path */
547 fprintf(stderr
, "sar: failed to open input file [%d][%s]\n", ifd
, path
);
553 read_record_hdr(hdr
, writeflag
)
554 struct record_hdr
*hdr
;
562 size
= sizeof(struct record_hdr
);
566 num
= read(ifd
, &hdr
[n
], size
);
576 fprintf(stderr
, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno
, (int)num
, (int)size
);
581 if (oflag
&& writeflag
)
582 write_record_hdr(hdr
);
588 read_record_data(buf
, size
, writeflag
)
599 num
= read(ifd
, &buf
[n
], size
);
605 else if (num
== 0) /* EOF */
609 fprintf(stderr
, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno
, (int)num
, (int)size
);
614 if (oflag
&& writeflag
)
615 write_record_data(buf
, n
);
621 write_record_hdr(hdr
)
622 struct record_hdr
*hdr
;
627 if ((num
= write(ofd
, hdr
, sizeof(struct record_hdr
))) == -1)
629 fprintf(stderr
, "sar: write_record_hdr failed, errno=%d\n", errno
);
636 write_record_data(char *buf
, size_t nbytes
)
640 if ((num
= write(ofd
, buf
, nbytes
)) == -1)
642 fprintf(stderr
, "sar: write_record_data failed, errno=%d\n", errno
);
649 * Convert a string of one of the forms
651 * into the number of seconds.
659 int hh
= 0; /* hours */
660 int mm
= 0; /* minutes */
661 int ss
= 0; /* seconds */
667 if (string
== NULL
|| *string
== '\0')
670 for (i
=0; string
[i
] != '\0'; i
++)
672 if ((!isdigit(string
[i
])) && (string
[i
] != ':'))
678 if (sscanf(string
, "%d:%d:%d", &hh
, &mm
, &ss
) != 3)
680 if (sscanf(string
, "%d:%d", &hh
, &mm
) != 2)
682 if (sscanf(string
, "%d", &hh
) != 1)
689 if (hh
< 0 || hh
>= HOURS_PER_DAY
||
690 mm
< 0 || mm
>= MINS_PER_HOUR
||
691 ss
< 0 || ss
> SECS_PER_MIN
)
696 seconds
= ((((hh
* MINS_PER_HOUR
) + mm
) * SECS_PER_MIN
) + ss
);
697 timestamp
= time((time_t *)0);
698 tm
=localtime(×tamp
);
699 seconds
-= tm
->tm_gmtoff
;
704 fprintf(stderr
, "sar: time format usage is hh[:mm[:ss]]\n");
711 * Use ctime_r to convert a time value into
712 * a 26-character string of the form:
714 * Thu Nov 24 18:22:48 1986\n\0
718 get_hms_string(tdata
, tbuf
)
734 /* sample set flags */
742 struct record_hdr hdr
;
743 time_t cur_timestamp
= 0; /* seconds - Coordinated Universal Time */
744 time_t next_timestamp
= 0; /* seconds - Coordinated Universal Time */
746 if (!find_restart_header(&hdr
))
749 cur_timestamp
= hdr
.rec_timestamp
;
751 /* convert sflag's start_time from 24 hour clock time to UTC seconds */
752 if (start_time
< (cur_timestamp
% SECS_PER_DAY
))
753 start_time
= cur_timestamp
;
755 start_time
+= cur_timestamp
- (cur_timestamp
% SECS_PER_DAY
);
757 /* convert end_time, from 24 hour clock time to UTC seconds */
759 end_time
+= cur_timestamp
- (cur_timestamp
% SECS_PER_DAY
);
762 fprintf(stderr
, "start = %ld, end = %ld, cur=%ld, [24hour - %ld]\n",
763 start_time
, end_time
, cur_timestamp
,(cur_timestamp
% SECS_PER_DAY
));
766 while (cur_timestamp
< start_time
)
768 bypass_sample_set(&hdr
, cur_timestamp
);
769 cur_timestamp
= hdr
.rec_timestamp
;
772 next_timestamp
= cur_timestamp
+ iseconds
;
773 print_all_column_headings(cur_timestamp
);
774 read_sample_set(INIT_SET
, cur_timestamp
, &hdr
);
775 cur_timestamp
= hdr
.rec_timestamp
;
777 while ((end_time
== 0) || (next_timestamp
< end_time
))
779 if (cur_timestamp
< next_timestamp
)
781 bypass_sample_set (&hdr
, cur_timestamp
);
782 cur_timestamp
= hdr
.rec_timestamp
;
786 /* need to know the seconds interval when printing averages */
787 if (avg_interval
== 0)
790 avg_interval
= iseconds
;
792 avg_interval
= cur_timestamp
- next_timestamp
;
794 next_timestamp
= cur_timestamp
+ iseconds
;
795 read_sample_set(PRINT_SET
, cur_timestamp
, &hdr
);
796 cur_timestamp
= hdr
.rec_timestamp
;
804 * Find and fill in a restart header. We don't write
805 * the binary data when looking for SAR_RESTART.
806 * Return: 1 on success
810 find_restart_header (ret_hdr
)
811 struct record_hdr
*ret_hdr
;
813 struct record_hdr hdr
;
820 read_record_hdr(&hdr
, FALSE
); /* exits on error */
822 if (hdr
.rec_type
== SAR_RESTART
)
826 write_record_hdr(&hdr
); /* writes the RESTART record */
833 * not the record we want...
834 * read past data and try again
839 { /* seek past data in the file */
840 if ((lseek(ifd
, (hdr
.rec_count
* hdr
.rec_size
), SEEK_CUR
)) == -1)
843 fprintf(stderr
, "sar: lseek failed, errno=%d\n", errno
);
848 /* compute data size - malloc a new buf if it's not big enough */
851 /* have to read from the pipe */
852 if (bufsize
< (hdr
.rec_count
* hdr
.rec_size
))
856 bufsize
= hdr
.rec_count
* hdr
.rec_size
;
857 if((buf
= (char *)malloc(bufsize
)) == NULL
)
859 fprintf(stderr
, "sar: malloc failed\n");
864 read_record_data(buf
, (hdr
.rec_count
* hdr
.rec_size
), FALSE
);
871 print_all_column_headings(timestamp
)
877 timebufp
= get_hms_string (timestamp
, timebuf
);
879 if (uflag
) /* print cpu headers */
880 print_column_heading(SAR_CPU
, timebufp
, 0);
882 if (gflag
) /* print page-out activity */
883 print_column_heading(SAR_VMSTAT
, timebufp
, 0);
885 if (pflag
) /* print page-in activity */
886 print_column_heading(SAR_VMSTAT
, timebufp
, 1);
888 if (dflag
) /* print drive stats */
889 print_column_heading(SAR_DRIVESTATS
, timebufp
, 0);
891 if (nflag
) /* print network stats */
893 if (network_mode
& NET_DEV_MODE
)
894 print_column_heading(SAR_NETSTATS
, timebufp
, NET_DEV_MODE
);
896 if (network_mode
& NET_EDEV_MODE
)
897 print_column_heading(SAR_NETSTATS
, timebufp
, NET_EDEV_MODE
);
903 * Find and fill in a timestamp header.
904 * Write the binary data when looking for SAR_TIMESTAMP
905 * Don't do anything with the data, just read past it.
906 * Return: 1 on success
910 bypass_sample_set (ret_hdr
, timestamp
)
911 struct record_hdr
*ret_hdr
;
914 struct record_hdr hdr
;
919 read_record_hdr(&hdr
, TRUE
); /* exits on error */
921 if (hdr
.rec_type
== SAR_TIMESTAMP
)
930 * not the record we want...
931 * read past data and try again
938 * we're reading from a file and we don't have to write the
939 * binary data so seek past data in the file
942 if ((lseek(ifd
, (hdr
.rec_count
* hdr
.rec_size
), SEEK_CUR
)) == -1)
945 fprintf(stderr
, "sar: lseek failed, errno=%d\n", errno
);
952 * We end up here when reading from pipe.
953 * malloc a new buffer if current is not big enough
955 if (bufsize
< (hdr
.rec_count
* hdr
.rec_size
))
959 bufsize
= hdr
.rec_count
* hdr
.rec_size
;
960 if((buf
= (char *)malloc(bufsize
)) == NULL
)
962 fprintf(stderr
, "sar: malloc failed\n");
968 read_record_data(buf
, (hdr
.rec_count
* hdr
.rec_size
), TRUE
);
970 } /* end if hdr.rec_count */
976 * INIT_SET: This initializes the first sample for each type.
977 * PRINT_SET: This read, compute and print out sample data.
980 read_sample_set(flag
, timestamp
, ret_hdr
)
983 struct record_hdr
*ret_hdr
;
985 struct record_hdr hdr
;
989 char *indent_string_wide
;
990 char *indent_string_narrow
;
993 int sar_drivestats
=0;
995 int sar_netstats
= 0;
997 indent_string_wide
= " ";
998 indent_string_narrow
= " ";
999 indent_string
= indent_string_narrow
;
1001 read_record_hdr(&hdr
, TRUE
);
1003 while (hdr
.rec_type
!= SAR_TIMESTAMP
)
1005 switch (hdr
.rec_type
)
1008 sar_cpu
= get_cpu_sample(flag
, &hdr
);
1011 sar_vmstat
=get_vmstat_sample(flag
, &hdr
);
1014 sar_drivepath
= get_drivepath_sample(flag
, &hdr
);
1015 if (sar_drivepath
< 0)
1016 fprintf(stderr
, "sar: drivepath sync code error %d\n", sar_drivepath
);
1018 case SAR_DRIVESTATS
:
1019 sar_drivestats
= get_drivestats_sample(flag
, &hdr
);
1022 sar_netstats
= get_netstats_sample(flag
, &hdr
);
1028 read_record_hdr(&hdr
, TRUE
);
1031 /* return the timestamp header */
1034 if (flag
== PRINT_SET
)
1037 timebufp
= get_hms_string(timestamp
, timebuf
);
1039 if (uflag
&& sar_cpu
)
1040 print_cpu_sample(timebufp
);
1042 if((gflag
|| pflag
) && sar_vmstat
)
1043 print_vmstat_sample(timebufp
);
1045 if (dflag
&& sar_drivestats
)
1046 print_drivestats_sample(timebufp
);
1048 if (nflag
&& sar_netstats
)
1049 print_netstats_sample(timebufp
);
1061 /* seek past data in the file */
1062 if ((lseek(ifd
, bufsize
, SEEK_CUR
) == -1))
1065 fprintf(stderr
, "sar: lseek failed, errno=%d\n", errno
);
1071 /* have to read from the pipe */
1072 if((buf
= (char *)malloc(bufsize
)) == NULL
)
1074 fprintf(stderr
, "sar: malloc failed\n");
1077 /* even though we skip this data, we still write it if necessary */
1078 read_record_data(buf
, bufsize
, TRUE
);
1087 get_cpu_sample(flag
, hdr
)
1089 struct record_hdr
*hdr
;
1093 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1095 if (datasize
!= sizeof(host_cpu_load_info_data_t
))
1097 /* read past the data but don't do anything with it */
1098 skip_data(datasize
);
1102 read_record_data ((char *)&cur_cpuload
, (int)sizeof(host_cpu_load_info_data_t
), TRUE
);
1104 if (flag
== INIT_SET
)
1106 prev_cpuload
= cur_cpuload
;
1107 bzero(&avg_cpuload
, sizeof(avg_cpuload
));
1113 print_cpu_sample(timebufptr
)
1120 cur_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1121 -= prev_cpuload
.cpu_ticks
[CPU_STATE_USER
];
1123 prev_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1124 += cur_cpuload
.cpu_ticks
[CPU_STATE_USER
];
1126 time
+= cur_cpuload
.cpu_ticks
[CPU_STATE_USER
];
1128 cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1129 -= prev_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
];
1131 prev_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1132 += cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
];
1134 time
+= cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
];
1136 cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1137 -= prev_cpuload
.cpu_ticks
[CPU_STATE_IDLE
];
1139 prev_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1140 += cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
];
1142 time
+= cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
];
1144 avg_cpuload
.cpu_ticks
[CPU_STATE_USER
] += rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1145 / (time
? time
: 1));
1147 avg_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
] += rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1148 / (time
? time
: 1));
1150 avg_cpuload
.cpu_ticks
[CPU_STATE_IDLE
] += rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1151 / (time
? time
: 1));
1154 print_column_heading(SAR_CPU
, timebufptr
, 0);
1156 fprintf(stdout
, "%s%5.0f ", timebufptr
,
1157 rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1158 / (time
? time
: 1)));
1160 fprintf(stdout
, "%4.0f ",
1161 rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1162 / (time
? time
: 1)));
1164 fprintf(stdout
, "%4.0f\n",
1165 rint(100. * cur_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1166 / (time
? time
: 1)));
1170 get_vmstat_sample(flag
, hdr
)
1172 struct record_hdr
*hdr
;
1176 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1178 if (datasize
!= sizeof(struct vm_statistics
))
1180 /* read past the data but don't do anything with it */
1181 skip_data(datasize
);
1185 read_record_data ((char *)&cur_vmstat
, (int)sizeof(struct vm_statistics
), TRUE
);
1187 if (flag
== INIT_SET
)
1189 prev_vmstat
= cur_vmstat
;
1190 bzero(&avg_vmstat
, sizeof(avg_vmstat
));
1197 print_vmstat_sample(char *timebufptr
)
1200 cur_vmstat
.faults
-= prev_vmstat
.faults
;
1201 prev_vmstat
.faults
+= cur_vmstat
.faults
;
1202 avg_vmstat
.faults
+= cur_vmstat
.faults
;
1204 cur_vmstat
.cow_faults
-= prev_vmstat
.cow_faults
;
1205 prev_vmstat
.cow_faults
+= cur_vmstat
.cow_faults
;
1206 avg_vmstat
.cow_faults
+= cur_vmstat
.cow_faults
;
1208 cur_vmstat
.zero_fill_count
-= prev_vmstat
.zero_fill_count
;
1209 prev_vmstat
.zero_fill_count
+= cur_vmstat
.zero_fill_count
;
1210 avg_vmstat
.zero_fill_count
+= cur_vmstat
.zero_fill_count
;
1212 cur_vmstat
.reactivations
-= prev_vmstat
.reactivations
;
1213 prev_vmstat
.reactivations
+= cur_vmstat
.reactivations
;
1214 avg_vmstat
.reactivations
+= cur_vmstat
.reactivations
;
1216 cur_vmstat
.pageins
-= prev_vmstat
.pageins
;
1217 prev_vmstat
.pageins
+= cur_vmstat
.pageins
;
1218 avg_vmstat
.pageins
+= cur_vmstat
.pageins
;
1220 cur_vmstat
.pageouts
-= prev_vmstat
.pageouts
;
1221 prev_vmstat
.pageouts
+= cur_vmstat
.pageouts
;
1222 avg_vmstat
.pageouts
+= cur_vmstat
.pageouts
;
1228 print_column_heading(SAR_VMSTAT
, timebufptr
, 0);
1229 fprintf(stdout
, "%s %8.1f \n", timebufptr
, (float)((float)cur_vmstat
.pageouts
/avg_interval
));
1235 print_column_heading(SAR_VMSTAT
, timebufptr
, 1);
1236 fprintf(stdout
, "%s %8.1f %8.1f %8.1f\n", timebufptr
,
1237 (float)((float)cur_vmstat
.pageins
/ avg_interval
),
1238 (float)((float)cur_vmstat
.cow_faults
/avg_interval
),
1239 (float)((float)cur_vmstat
.faults
/avg_interval
));
1245 get_drivestats_sample(flag
, hdr
)
1247 struct record_hdr
*hdr
;
1249 struct drivestats
*databuf
;
1250 struct drivestats_report
*dr
;
1256 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1257 datacount
= hdr
->rec_count
;
1259 if (hdr
->rec_size
!= sizeof(struct drivestats
))
1261 /* something isn't right... read past the data but don't analyze it */
1262 skip_data(datasize
);
1266 /* malloc read buffer */
1267 if ((databuf
= (struct drivestats
*)malloc(datasize
)) == NULL
)
1269 fprintf(stderr
, "sar: malloc failed\n");
1270 exit (EXIT_FAILURE
);
1273 bzero(databuf
, datasize
);
1275 read_record_data ((char *)databuf
, datasize
, TRUE
);
1277 /* clear all global current fields */
1278 for(dr
= dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1282 dr
->cur_BytesRead
= 0;
1284 dr
->cur_BytesWritten
= 0;
1285 dr
->cur_LatentReadTime
= 0;
1286 dr
->cur_LatentWriteTime
= 0;
1287 dr
->cur_ReadErrors
= 0;
1288 dr
->cur_WriteErrors
= 0;
1289 dr
->cur_ReadRetries
= 0;
1290 dr
->cur_WriteRetries
= 0;
1291 dr
->cur_TotalReadTime
= 0;
1292 dr
->cur_TotalWriteTime
=0;
1295 /* By this point, we have read in a complete set of diskstats from the sadc
1297 * The order of the drives in not guaranteed.
1298 * The global report structure is a linked list, but may need initialization
1299 * We need to traverse this list and transfer the current
1300 * read data. If a disk entry isn't found, then we need to allocate one
1303 for (i
=0; i
< datacount
; i
++)
1305 struct drivestats_report
*dr_last
= NULL
;
1307 index
= databuf
[i
].drivepath_id
; /* use this as index into dp_table */
1309 /* find disk entry or allocate new one*/
1310 for(dr
= dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1313 if(index
== dr
->drivepath_id
)
1319 /* allocate new entry */
1320 if((dr
= (struct drivestats_report
*)malloc(sizeof(struct drivestats_report
))) == NULL
)
1322 fprintf(stderr
, "sar: malloc error\n");
1325 bzero((char *)dr
, sizeof(struct drivestats_report
));
1326 dr
->blocksize
= databuf
[i
].blocksize
;
1327 dr
->drivepath_id
= index
;
1331 /* get the BSDName which should be in the table by now */
1332 if ((index
< dp_count
) && (dp_table
[index
].state
!= DPSTATE_UNINITIALIZED
))
1333 strncpy(dr
->name
, dp_table
[index
].BSDName
, MAXDRIVENAME
+1);
1335 strcpy(dr
->name
, "disk??");
1337 if (dr_head
== NULL
)
1340 dr_head
->next
= NULL
;
1344 dr_last
->next
= (char *)dr
;
1346 } /* end if dr == NULL */
1349 dr
->cur_Reads
= databuf
[i
].Reads
;
1350 dr
->cur_BytesRead
= databuf
[i
].BytesRead
;
1351 dr
->cur_Writes
= databuf
[i
].Writes
;
1352 dr
->cur_BytesWritten
= databuf
[i
].BytesWritten
;
1353 dr
->cur_LatentReadTime
= databuf
[i
].LatentReadTime
;
1354 dr
->cur_LatentWriteTime
= databuf
[i
].LatentWriteTime
;
1355 dr
->cur_ReadErrors
= databuf
[i
].ReadErrors
;
1356 dr
->cur_WriteErrors
= databuf
[i
].WriteErrors
;
1357 dr
->cur_ReadRetries
= databuf
[i
].ReadRetries
;
1358 dr
->cur_WriteRetries
= databuf
[i
].WriteRetries
;
1359 dr
->cur_TotalReadTime
= databuf
[i
].TotalReadTime
;
1360 dr
->cur_TotalWriteTime
=databuf
[i
].TotalWriteTime
;
1361 } /* end for loop */
1363 /* Reinitialize the prev and avg fields when
1364 * This is a new disk
1365 * This is a changed disk - name change implies disk swapping
1366 * This disk is not present in this sample
1368 for(dr
= dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1370 if (dr
->drivepath_id
>= dp_count
)
1372 /* something is amiss */
1377 index
= dr
->drivepath_id
; /* use this as index into dp_table */
1380 if ((flag
== INIT_SET
) ||
1381 (dp_table
[index
].state
== DPSTATE_NEW
) ||
1382 (dp_table
[index
].state
== DPSTATE_CHANGED
) ||
1386 * prev will be set to cur
1387 * activate the state in dp_table
1390 dp_table
[index
].state
= DPSTATE_ACTIVE
;
1392 init_drivestats(dr
);
1399 init_drivestats(struct drivestats_report
*dr
)
1402 dr
->prev_Reads
= dr
->cur_Reads
;
1404 dr
->prev_BytesRead
= dr
->cur_BytesRead
;
1405 dr
->avg_BytesRead
= 0;
1406 dr
->prev_Writes
= dr
->cur_Writes
;
1408 dr
->prev_BytesWritten
= dr
->cur_BytesWritten
;
1409 dr
->avg_BytesWritten
= 0;
1410 dr
->prev_LatentReadTime
= dr
->cur_LatentReadTime
;
1411 dr
->avg_LatentReadTime
= 0;
1412 dr
->prev_LatentWriteTime
= dr
->cur_LatentWriteTime
;
1413 dr
->avg_LatentWriteTime
= 0;
1414 dr
->prev_ReadErrors
= dr
->cur_ReadErrors
;
1415 dr
->avg_ReadErrors
= 0;
1416 dr
->prev_WriteErrors
= dr
->cur_WriteErrors
;
1417 dr
->avg_WriteErrors
= 0;
1418 dr
->prev_ReadRetries
= dr
->cur_ReadRetries
;
1419 dr
->avg_ReadRetries
= 0;
1420 dr
->prev_WriteRetries
= dr
->cur_WriteRetries
;
1421 dr
->avg_WriteRetries
= 0;
1422 dr
->prev_TotalReadTime
= dr
->cur_TotalReadTime
;
1423 dr
->avg_TotalReadTime
= 0;
1424 dr
->prev_TotalWriteTime
= dr
->cur_TotalWriteTime
;
1425 dr
->avg_TotalWriteTime
= 0;
1430 print_drivestats_sample(char *timebufptr
)
1432 struct drivestats_report
*dr
;
1433 long double transfers_per_second
;
1434 long double kb_per_transfer
, mb_per_second
;
1435 u_int64_t interval_bytes
, interval_transfers
, interval_blocks
;
1436 u_int64_t interval_time
;
1437 long double blocks_per_second
, ms_per_transaction
;
1440 print_column_heading(SAR_DRIVESTATS
, timebufptr
, 0);
1442 for (dr
=dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1448 * This sanity check is for drives that get removed and then
1449 * returned during the sampling sleep interval. If anything
1450 * looks out of sync, reinit and skip this entry. There is
1451 * no way to guard against this entirely.
1453 if ((dr
->cur_Reads
< dr
->prev_Reads
) ||
1454 (dr
->cur_BytesRead
< dr
->prev_BytesRead
) ||
1455 (dr
->cur_Writes
< dr
->prev_Writes
) ||
1456 (dr
->cur_BytesWritten
< dr
->prev_BytesWritten
))
1458 init_drivestats(dr
);
1464 dr
->cur_Reads
-= dr
->prev_Reads
;
1465 dr
->prev_Reads
+= dr
->cur_Reads
;
1466 dr
->avg_Reads
+= dr
->cur_Reads
;
1468 dr
->cur_BytesRead
-= dr
->prev_BytesRead
;
1469 dr
->prev_BytesRead
+= dr
->cur_BytesRead
;
1470 dr
->avg_BytesRead
+= dr
->cur_BytesRead
;
1472 dr
->cur_Writes
-= dr
->prev_Writes
;
1473 dr
->prev_Writes
+= dr
->cur_Writes
;
1474 dr
->avg_Writes
+= dr
->cur_Writes
;
1476 dr
->cur_BytesWritten
-= dr
->prev_BytesWritten
;
1477 dr
->prev_BytesWritten
+= dr
->cur_BytesWritten
;
1478 dr
->avg_BytesWritten
+= dr
->cur_BytesWritten
;
1480 dr
->cur_LatentReadTime
-= dr
->prev_LatentReadTime
;
1481 dr
->prev_LatentReadTime
+= dr
->cur_LatentReadTime
;
1482 dr
->avg_LatentReadTime
+= dr
->cur_LatentReadTime
;
1484 dr
->cur_LatentWriteTime
-= dr
->prev_LatentWriteTime
;
1485 dr
->prev_LatentWriteTime
+= dr
->cur_LatentWriteTime
;
1486 dr
->avg_LatentWriteTime
+= dr
->cur_LatentWriteTime
;
1488 dr
->cur_ReadErrors
-= dr
->prev_ReadErrors
;
1489 dr
->prev_ReadErrors
+= dr
->cur_ReadErrors
;
1490 dr
->avg_ReadErrors
+= dr
->cur_ReadErrors
;
1492 dr
->cur_WriteErrors
-= dr
->prev_WriteErrors
;
1493 dr
->prev_WriteErrors
+= dr
->cur_WriteErrors
;
1494 dr
->avg_WriteErrors
+= dr
->cur_WriteErrors
;
1496 dr
->cur_ReadRetries
-= dr
->prev_ReadRetries
;
1497 dr
->prev_ReadRetries
+= dr
->cur_ReadRetries
;
1498 dr
->avg_ReadRetries
+= dr
->cur_ReadRetries
;
1500 dr
->cur_WriteRetries
-= dr
->prev_WriteRetries
;
1501 dr
->prev_WriteRetries
+= dr
->cur_WriteRetries
;
1502 dr
->avg_WriteRetries
+= dr
->cur_WriteRetries
;
1504 dr
->cur_TotalReadTime
-= dr
->prev_TotalReadTime
;
1505 dr
->prev_TotalReadTime
+= dr
->cur_TotalReadTime
;
1506 dr
->avg_TotalReadTime
+= dr
->cur_TotalReadTime
;
1508 dr
->cur_TotalWriteTime
-= dr
->prev_TotalWriteTime
;
1509 dr
->prev_TotalWriteTime
+= dr
->cur_TotalWriteTime
;
1510 dr
->avg_TotalWriteTime
+= dr
->cur_TotalWriteTime
;
1513 interval_bytes
= dr
->cur_BytesRead
+ dr
->cur_BytesWritten
;
1516 interval_transfers
= dr
->cur_Reads
+ dr
->cur_Writes
;
1519 interval_time
= dr
->cur_LatentReadTime
+ dr
->cur_LatentWriteTime
;
1521 interval_blocks
= interval_bytes
/ dr
->blocksize
;
1522 blocks_per_second
= interval_blocks
/ avg_interval
;
1523 transfers_per_second
= interval_transfers
/ avg_interval
;
1524 mb_per_second
= (interval_bytes
/ avg_interval
) / (1024 *1024);
1526 kb_per_transfer
= (interval_transfers
> 0) ?
1527 ((long double)interval_bytes
/ interval_transfers
)
1530 /* times are in nanoseconds, convert to milliseconds */
1531 ms_per_transaction
= (interval_transfers
> 0) ?
1532 ((long double)interval_time
/ interval_transfers
)
1535 /* print device name */
1536 fprintf(stdout
, "%s %-10s", timebufptr
, dr
->name
);
1538 /* print transfers per second */
1539 fprintf(stdout
, "%4.0Lf ", transfers_per_second
);
1541 /* print blocks per second - in device blocksize */
1542 fprintf(stdout
, "%4.0Lf\n", blocks_per_second
);
1547 * Print averages before exiting.
1554 if (avg_counter
<= 0 )
1564 if (uflag
) /* print cpu averages */
1567 print_column_heading(SAR_CPU
, 0, 0);
1569 fprintf(stdout
, "Average: %5d ",
1570 (int)avg_cpuload
.cpu_ticks
[CPU_STATE_USER
]
1571 / (avg_counter
? avg_counter
: 1));
1573 fprintf(stdout
, "%4d ",
1574 (int)avg_cpuload
.cpu_ticks
[CPU_STATE_SYSTEM
]
1575 / (avg_counter
? avg_counter
: 1));
1577 fprintf(stdout
, "%4d \n",
1578 (int)avg_cpuload
.cpu_ticks
[CPU_STATE_IDLE
]
1579 / (avg_counter
? avg_counter
: 1));
1585 if (gflag
) /* print page-out averages */
1588 print_column_heading(SAR_VMSTAT
, 0, 0);
1590 fprintf(stdout
, "Average: %8.1f\n",
1591 (float)((avg_vmstat
.pageouts
/ (avg_counter
? avg_counter
: 1)) / avg_interval
));
1595 if (pflag
) /* print page-in averages */
1598 print_column_heading(SAR_VMSTAT
, 0, 1);
1600 fprintf(stdout
, "Average: %8.1f %8.1f %8.1f\n",
1601 (float)(((float)avg_vmstat
.pageins
/ (avg_counter
? avg_counter
: 1)) / avg_interval
),
1602 (float)(((float)avg_vmstat
.cow_faults
/ (avg_counter
? avg_counter
: 1)) / avg_interval
),
1603 (float)(((float)avg_vmstat
.faults
/ (avg_counter
? avg_counter
: 1)) / avg_interval
));
1607 if (dflag
) /* print drivestats averages */
1609 struct drivestats_report
*dr
;
1610 long double transfers_per_second
;
1611 long double kb_per_transfer
, mb_per_second
;
1612 u_int64_t total_bytes
, total_transfers
, total_blocks
;
1613 u_int64_t total_time
;
1614 long double blocks_per_second
, ms_per_transaction
;
1618 print_column_heading(SAR_DRIVESTATS
, 0, 0);
1620 for (dr
=dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1622 /* don't bother to print out averages for disks that were removed */
1626 fprintf(stdout
, " %s %s\n",
1627 dp_table
[dr
->drivepath_id
].BSDName
, dp_table
[dr
->drivepath_id
].ioreg_path
);
1630 total_bytes
= dr
->avg_BytesRead
+ dr
->avg_BytesWritten
;
1633 total_transfers
= dr
->avg_Reads
+ dr
->avg_Writes
;
1636 total_time
= dr
->avg_LatentReadTime
+ dr
->avg_LatentWriteTime
;
1638 total_blocks
= total_bytes
/ dr
->blocksize
;
1639 blocks_per_second
= total_blocks
/ avg_interval
;
1640 transfers_per_second
= total_transfers
/ avg_interval
;
1641 mb_per_second
= (total_bytes
/ avg_interval
) / (1024 *1024);
1643 kb_per_transfer
= (total_transfers
> 0) ?
1644 ((long double)total_bytes
/ total_transfers
)
1647 /* times are in nanoseconds, convert to milliseconds */
1648 ms_per_transaction
= (total_transfers
> 0) ?
1649 ((long double)total_time
/ total_transfers
)
1651 msdig
= (ms_per_transaction
< 100.0) ? 1 : 0;
1652 fprintf(stdout
, "Average: %-10s %4.0Lf %4.0Lf\n",
1654 (transfers_per_second
/ dr
->avg_count
),
1655 (blocks_per_second
/ dr
->avg_count
));
1659 } /* end if dflag */
1665 if (network_mode
& NET_DEV_MODE
)
1668 print_column_heading(SAR_NETSTATS
, 0, NET_DEV_MODE
);
1669 for (i
= 0; i
< nr_count
; i
++)
1671 if (!nr_table
[i
].valid
)
1674 if(nr_table
[i
].avg_count
== 0)
1677 avg_count
= nr_table
[i
].avg_count
;
1679 fprintf(stdout
, "Average: %-8.8s", nr_table
[i
].tname_unit
);
1681 fprintf (stdout
, "%8llu ",
1682 ((nr_table
[i
].avg_ipackets
/ avg_count
) / avg_interval
));
1684 fprintf (stdout
, "%10llu ",
1685 ((nr_table
[i
].avg_ibytes
/ avg_count
) / avg_interval
));
1687 fprintf (stdout
, "%8llu ",
1688 ((nr_table
[i
].avg_opackets
/ avg_count
) / avg_interval
));
1690 fprintf (stdout
, "%10llu\n",
1691 ((nr_table
[i
].avg_obytes
/ avg_count
) / avg_interval
));
1697 if (network_mode
& NET_EDEV_MODE
)
1701 print_column_heading(SAR_NETSTATS
, 0, NET_EDEV_MODE
);
1703 for (i
= 0; i
< nr_count
; i
++)
1705 if (!nr_table
[i
].valid
)
1708 if(nr_table
[i
].avg_count
== 0)
1711 avg_count
= nr_table
[i
].avg_count
;
1713 fprintf(stdout
, "Average: %-8.8s ", nr_table
[i
].tname_unit
);
1715 fprintf (stdout
, "%7llu ",
1716 ((nr_table
[i
].avg_ierrors
/ avg_count
) / avg_interval
));
1718 fprintf (stdout
, "%7llu ",
1719 ((nr_table
[i
].avg_oerrors
/ avg_count
) / avg_interval
));
1721 fprintf (stdout
, "%5llu ",
1722 ((nr_table
[i
].avg_collisions
/ avg_count
) / avg_interval
));
1724 fprintf (stdout
, " %5llu\n",
1725 ((nr_table
[i
].avg_drops
/ avg_count
) / avg_interval
));
1731 } /* end if nflag */
1737 * Return < 0 failure, debugging purposes only
1738 * Return = 0 data skipped
1739 * Return > 0 success
1743 get_drivepath_sample(flag
, hdr
)
1745 struct record_hdr
*hdr
;
1748 struct drivepath dp
;
1749 struct drivestats_report
*dr
;
1752 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1754 if (datasize
!= sizeof(struct drivepath
))
1756 /* read past the data but don't do anything with it */
1757 skip_data(datasize
);
1761 read_record_data ((char *)&dp
, (int)sizeof(struct drivepath
), TRUE
);
1764 * If state is new -- put a new entry in the dp_table.
1765 * If state is changed -- traverse the drivestats_report table
1766 * and copy new name.
1768 if (dp
.state
== DPSTATE_NEW
)
1771 if (dp_table
== NULL
)
1773 if (dp
.drivepath_id
!= 0)
1775 /* First setup of internal drivepath table */
1776 dp_table
= (struct drivepath
*)malloc(sizeof(struct drivepath
));
1777 if (dp_table
== NULL
)
1783 fprintf(stdout
, "New Disk: [%s] %s\n", dp
.BSDName
, dp
.ioreg_path
);
1785 /* traverse table and find next uninitialized entry */
1786 for (i
= 0; i
< dp_count
; i
++)
1788 if (dp_table
[i
].state
== DPSTATE_UNINITIALIZED
)
1790 if (dp
.drivepath_id
!= i
)
1792 /* the table is out of sync - this should not happen */
1800 * If we get here, we've run out of table entries.
1801 * Double the size of the table, then assign the next entry.
1803 if (dp
.drivepath_id
!= i
)
1805 /* the table is out of sync - this should not happen */
1809 dp_table
= (struct drivepath
*)realloc(dp_table
, n
* sizeof(struct drivepath
));
1810 bzero(&dp_table
[dp_count
], dp_count
* sizeof(struct drivepath
));
1811 dp_table
[dp_count
] = dp
;
1816 else if (dp
.state
== DPSTATE_CHANGED
)
1819 /* Update the name in the table */
1820 if ((dp
.drivepath_id
< dp_count
) && (dp_table
[dp
.drivepath_id
].state
!= DPSTATE_UNINITIALIZED
))
1822 if (strcmp(dp_table
[dp
.drivepath_id
].ioreg_path
, dp
.ioreg_path
) != 0)
1824 /* something is amiss */
1831 fprintf(stdout
, "Change: [%s] %s\n", dp
.BSDName
,
1832 dp_table
[dp
.drivepath_id
].ioreg_path
);
1834 strcpy(dp_table
[dp
.drivepath_id
].BSDName
, dp
.BSDName
);
1836 for(dr
= dr_head
; dr
; dr
=(struct drivestats_report
*)dr
->next
)
1838 if (dr
->drivepath_id
== dp
.drivepath_id
)
1839 strcpy(dr
->name
, dp
.BSDName
);
1851 * Bytes and packet counts are used to track
1852 * counter wraps. So, don't enforce the
1853 * NET_DEV_MODE or NET_EDEV_MODE in here.
1854 * Maintain all the stats.
1857 set_cur_netstats(struct netstats_report
*nr
, struct netstats
*ns
)
1860 nr
->cur_ipackets
= ns
->net_ipackets
;
1861 nr
->cur_ibytes
= ns
->net_ibytes
;
1862 nr
->cur_opackets
= ns
->net_opackets
;
1863 nr
->cur_obytes
= ns
->net_obytes
;
1865 nr
->cur_ierrors
= ns
->net_ierrors
;
1866 nr
->cur_oerrors
= ns
->net_oerrors
;
1867 nr
->cur_collisions
= ns
->net_collisions
;
1868 nr
->cur_drops
= ns
->net_drops
;
1870 nr
->cur_imcasts
= ns
->net_imcasts
;
1871 nr
->cur_omcasts
= ns
->net_omcasts
;
1876 init_prev_netstats(struct netstats_report
*nr
)
1882 nr
->prev_ipackets
= nr
->cur_ipackets
;
1883 nr
->avg_ipackets
= 0;
1884 nr
->prev_ibytes
= nr
->cur_ibytes
;
1886 nr
->prev_opackets
= nr
->cur_opackets
;
1887 nr
->avg_opackets
= 0;
1888 nr
->prev_obytes
= nr
->cur_obytes
;
1891 nr
->prev_ierrors
= nr
->cur_ierrors
;
1892 nr
->avg_ierrors
= 0;
1893 nr
->prev_oerrors
= nr
->cur_oerrors
;
1894 nr
->avg_oerrors
= 0;
1895 nr
->prev_collisions
= nr
->cur_collisions
;
1896 nr
->avg_collisions
= 0;
1897 nr
->prev_drops
= nr
->cur_drops
;
1900 /* track these, but never displayed */
1901 nr
->prev_imcasts
= nr
->cur_imcasts
;
1902 nr
->avg_imcasts
= 0;
1903 nr
->prev_omcasts
= nr
->cur_omcasts
;
1904 nr
->avg_omcasts
= 0;
1912 get_netstats_sample(flag
, hdr
)
1914 struct record_hdr
*hdr
;
1916 struct netstats
*databuf
= NULL
;
1921 datasize
= hdr
->rec_count
* hdr
->rec_size
;
1922 datacount
= hdr
->rec_count
;
1924 if (hdr
->rec_size
!= sizeof(struct netstats
))
1926 /* something isn't right... read past the data but don't analyze it */
1927 skip_data(datasize
);
1931 /* malloc new or bigger read buffer */
1932 if((netstat_readbuf
== NULL
) || (netstat_readbuf_size
< datasize
))
1934 if (netstat_readbuf
)
1935 free (netstat_readbuf
);
1937 if ((netstat_readbuf
= (struct netstats
*)malloc(datasize
)) == NULL
)
1939 fprintf(stderr
, "sar: malloc failed\n");
1940 exit (EXIT_FAILURE
);
1942 netstat_readbuf_size
= datasize
;
1945 bzero(netstat_readbuf
, netstat_readbuf_size
);
1946 databuf
= netstat_readbuf
;
1948 read_record_data ((char *)databuf
, datasize
, TRUE
);
1950 if (nr_table
== NULL
)
1952 /* initial internal table setup */
1953 nr_table
= (struct netstats_report
*)malloc(datacount
* sizeof(struct netstats_report
));
1954 nr_count
= datacount
;
1955 bzero(nr_table
, (datacount
* sizeof(struct netstats_report
)));
1957 /* on first init, this is faster than finding our way to NEW_ENTRY */
1958 for (i
= 0; i
< datacount
; i
++)
1960 if (!(network_mode
& NET_PPP_MODE
))
1962 if (!strncmp(databuf
[i
].tname_unit
, "ppp", 3))
1964 * Skip ppp interfaces.
1965 * ie don't even put them in this internal table.
1968 strncpy(nr_table
[i
].tname_unit
, databuf
[i
].tname_unit
, MAX_TNAME_UNIT_SIZE
);
1969 nr_table
[i
].tname_unit
[MAX_TNAME_UNIT_SIZE
] = '\0';
1970 set_cur_netstats(&nr_table
[i
], &databuf
[i
]);
1971 init_prev_netstats(&nr_table
[i
]);
1977 * clear all the present flags.
1978 * As we traverse the current sample set
1979 * and update the internal table, the flag
1982 for (i
= 0; i
< nr_count
; i
++)
1984 nr_table
[i
].present
= 0;
1988 * Find and update table entries.
1991 for (i
=0; i
<datacount
; i
++)
1998 name
= databuf
[i
].tname_unit
;
2001 if (!(network_mode
& NET_PPP_MODE
))
2003 if (!strncmp(name
, "ppp", 3))
2004 continue; /* skip ppp interfaces */
2007 /* Find the matching entry using the interface name */
2008 for (j
=0; j
< nr_count
&& !found
; j
++)
2010 if (nr_table
[j
].valid
)
2012 if(!strcmp(nr_table
[j
].tname_unit
, name
))
2015 nr_table
[j
].present
= 1;
2016 set_cur_netstats(&nr_table
[j
], &databuf
[i
]);
2021 if (!found
) /* this is a new entry */
2023 /* Find an invalid entry in the table and init it */
2024 for (j
=0; j
< nr_count
; j
++)
2026 if (!nr_table
[j
].valid
)
2033 /* we ran out of entries... grow the table */
2035 nr_table
= (struct netstats_report
*)realloc(nr_table
, n
* sizeof(struct netstats_report
));
2036 bzero(&nr_table
[nr_count
], nr_count
* sizeof (struct netstats_report
));
2037 nr_index
= nr_count
;
2041 strncpy(nr_table
[nr_index
].tname_unit
, databuf
[i
].tname_unit
, MAX_TNAME_UNIT_SIZE
);
2042 nr_table
[nr_index
].tname_unit
[MAX_TNAME_UNIT_SIZE
] = '\0';
2043 set_cur_netstats(&nr_table
[nr_index
], &databuf
[i
]);
2044 init_prev_netstats(&nr_table
[nr_index
]);
2050 * Traverse the internal table. Any valid entry that wasn't
2051 * present in this sample is cleared for reuse.
2053 for (i
= 0; i
< nr_count
; i
++)
2055 if (nr_table
[i
].valid
)
2057 if (nr_table
[i
].present
== 0)
2058 bzero(&nr_table
[i
], sizeof(struct netstats_report
));
2065 print_netstats_sample(char *timebufptr
)
2069 for (i
=0; i
< nr_count
; i
++)
2071 if (!nr_table
[i
].valid
)
2075 * This is where we attempt to handle counters that
2076 * might wrap ... the kernel netstats are only 32 bits.
2078 * Interfaces may go away and then return within the
2079 * sampling period. This can't be detected and it
2080 * may look like a counter wrap. An interface generation
2081 * counter will help... but isn't implemented at this time.
2085 * The ppp interfaces are very likely to come and go during
2086 * a sampling period. During the normal life of a ppp interface,
2087 * it's less likely that the packet counter will wrap, so if
2088 * it appears to have done so, is probably because the
2089 * interface unit number has been reused.
2090 * We reinitialize that interface in that case.
2092 if (network_mode
& NET_PPP_MODE
)
2095 * ppp interfaces won't even make it into this table
2096 * when NET_PPP_MODE isn't set
2098 if (!strncmp(nr_table
[i
].tname_unit
, "ppp", 3))
2101 * Both ipackets and opackets have to be less
2102 * than the previous counter to cause us to reinit.
2105 if ((nr_table
[i
].cur_ipackets
< nr_table
[i
].prev_ipackets
)
2106 && (nr_table
[i
].cur_opackets
< nr_table
[i
].prev_opackets
))
2108 init_prev_netstats(&nr_table
[i
]);
2114 nr_table
[i
].avg_count
++;
2116 #ifdef IFNET_32_BIT_COUNTERS
2117 while (nr_table
[i
].cur_ipackets
< nr_table
[i
].prev_ipackets
)
2118 nr_table
[i
].cur_ipackets
+= 0x100000000LL
;
2119 #endif /* IFNET_32_BIT_COUNTERS */
2120 nr_table
[i
].cur_ipackets
-= nr_table
[i
].prev_ipackets
;
2121 nr_table
[i
].prev_ipackets
+= nr_table
[i
].cur_ipackets
;
2122 nr_table
[i
].avg_ipackets
+= nr_table
[i
].cur_ipackets
;
2125 #ifdef IFNET_32_BIT_COUNTERS
2126 while (nr_table
[i
].cur_ibytes
< nr_table
[i
].prev_ibytes
)
2127 nr_table
[i
].cur_ibytes
+= 0x100000000LL
;
2128 #endif /* IFNET_32_BIT_COUNTERS */
2129 nr_table
[i
].cur_ibytes
-= nr_table
[i
].prev_ibytes
;
2130 nr_table
[i
].prev_ibytes
+= nr_table
[i
].cur_ibytes
;
2131 nr_table
[i
].avg_ibytes
+= nr_table
[i
].cur_ibytes
;
2134 #ifdef IFNET_32_BIT_COUNTERS
2135 while (nr_table
[i
].cur_opackets
< nr_table
[i
].prev_opackets
)
2136 nr_table
[i
].cur_opackets
+= 0x100000000LL
;
2137 #endif /* IFNET_32_BIT_COUNTERS */
2138 nr_table
[i
].cur_opackets
-= nr_table
[i
].prev_opackets
;
2139 nr_table
[i
].prev_opackets
+= nr_table
[i
].cur_opackets
;
2140 nr_table
[i
].avg_opackets
+= nr_table
[i
].cur_opackets
;
2142 #ifdef IFNET_32_BIT_COUNTERS
2143 while (nr_table
[i
].cur_obytes
< nr_table
[i
].prev_obytes
)
2144 nr_table
[i
].cur_obytes
+= 0x100000000LL
;
2145 #endif /* IFNET_32_BIT_COUNTERS */
2146 nr_table
[i
].cur_obytes
-= nr_table
[i
].prev_obytes
;
2147 nr_table
[i
].prev_obytes
+= nr_table
[i
].cur_obytes
;
2148 nr_table
[i
].avg_obytes
+= nr_table
[i
].cur_obytes
;
2151 #ifdef IFNET_32_BIT_COUNTERS
2152 while (nr_table
[i
].cur_ierrors
< nr_table
[i
].prev_ierrors
)
2153 nr_table
[i
].cur_ierrors
+= 0x100000000LL
;
2154 #endif /* IFNET_32_BIT_COUNTERS */
2155 nr_table
[i
].cur_ierrors
-= nr_table
[i
].prev_ierrors
;
2156 nr_table
[i
].prev_ierrors
+= nr_table
[i
].cur_ierrors
;
2157 nr_table
[i
].avg_ierrors
+= nr_table
[i
].cur_ierrors
;
2159 #ifdef IFNET_32_BIT_COUNTERS
2160 while (nr_table
[i
].cur_oerrors
< nr_table
[i
].prev_oerrors
)
2161 nr_table
[i
].cur_oerrors
+= 0x100000000LL
;
2162 #endif /* IFNET_32_BIT_COUNTERS */
2163 nr_table
[i
].cur_oerrors
-= nr_table
[i
].prev_oerrors
;
2164 nr_table
[i
].prev_oerrors
+= nr_table
[i
].cur_oerrors
;
2165 nr_table
[i
].avg_oerrors
+= nr_table
[i
].cur_oerrors
;
2167 #ifdef IFNET_32_BIT_COUNTERS
2168 while (nr_table
[i
].cur_collisions
< nr_table
[i
].prev_collisions
)
2169 nr_table
[i
].cur_collisions
+= 0x100000000LL
;
2170 #endif /* IFNET_32_BIT_COUNTERS */
2171 nr_table
[i
].cur_collisions
-= nr_table
[i
].prev_collisions
;
2172 nr_table
[i
].prev_collisions
+= nr_table
[i
].cur_collisions
;
2173 nr_table
[i
].avg_collisions
+= nr_table
[i
].cur_collisions
;
2175 #ifdef IFNET_32_BIT_COUNTERS
2176 while (nr_table
[i
].cur_drops
< nr_table
[i
].prev_drops
)
2177 nr_table
[i
].cur_drops
+= 0x100000000LL
;
2178 #endif /* IFNET_32_BIT_COUNTERS */
2179 nr_table
[i
].cur_drops
-= nr_table
[i
].prev_drops
;
2180 nr_table
[i
].prev_drops
+= nr_table
[i
].cur_drops
;
2181 nr_table
[i
].avg_drops
+= nr_table
[i
].cur_drops
;
2184 #ifdef IFNET_32_BIT_COUNTERS
2185 while (nr_table
[i
].cur_imcasts
< nr_table
[i
].prev_imcasts
)
2186 nr_table
[i
].cur_imcasts
+= 0x100000000LL
;
2187 #endif /* IFNET_32_BIT_COUNTERS */
2188 nr_table
[i
].cur_imcasts
-= nr_table
[i
].prev_imcasts
;
2189 nr_table
[i
].prev_imcasts
+= nr_table
[i
].cur_imcasts
;
2190 nr_table
[i
].avg_imcasts
+= nr_table
[i
].cur_imcasts
;
2192 #ifdef IFNET_32_BIT_COUNTERS
2193 while (nr_table
[i
].cur_omcasts
< nr_table
[i
].prev_omcasts
)
2194 nr_table
[i
].cur_omcasts
+= 0x100000000LL
;
2195 #endif /* IFNET_32_BIT_COUNTERS */
2196 nr_table
[i
].cur_omcasts
-= nr_table
[i
].prev_omcasts
;
2197 nr_table
[i
].prev_omcasts
+= nr_table
[i
].cur_omcasts
;
2198 nr_table
[i
].avg_omcasts
+= nr_table
[i
].cur_omcasts
;
2202 if (!(flag_count
> 1))
2203 fprintf(stdout
, "\n");
2205 if (network_mode
& NET_DEV_MODE
)
2208 print_column_heading(SAR_NETSTATS
, timebufptr
, NET_DEV_MODE
);
2210 for (i
=0; i
< nr_count
; i
++)
2212 if (!nr_table
[i
].valid
)
2215 if (!(network_mode
& NET_PPP_MODE
))
2217 if (!strncmp(nr_table
[i
].tname_unit
, "ppp", 3))
2219 continue; /* skip any ppp interfaces */
2223 /* print the interface name */
2224 fprintf(stdout
, "%s %-8.8s", timebufptr
, nr_table
[i
].tname_unit
);
2226 fprintf (stdout
, "%8llu ",
2227 (nr_table
[i
].cur_ipackets
/ avg_interval
));
2229 fprintf (stdout
, "%10llu ",
2230 (nr_table
[i
].cur_ibytes
/ avg_interval
));
2232 fprintf (stdout
, "%8llu ",
2233 (nr_table
[i
].cur_opackets
/ avg_interval
));
2235 fprintf (stdout
, "%10llu\n",
2236 (nr_table
[i
].cur_obytes
/ avg_interval
));
2241 if (network_mode
& NET_EDEV_MODE
)
2245 print_column_heading(SAR_NETSTATS
, timebufptr
, NET_EDEV_MODE
);
2248 for (i
=0; i
< nr_count
; i
++)
2250 if (!nr_table
[i
].valid
)
2253 if (!(network_mode
& NET_PPP_MODE
))
2255 if (!strncmp(nr_table
[i
].tname_unit
, "ppp", 3))
2257 continue; /* skip any ppp interfaces */
2261 /* print the interface name */
2262 fprintf(stdout
, "%s %-8.8s ", timebufptr
, nr_table
[i
].tname_unit
);
2264 fprintf (stdout
, "%7llu ",
2265 (nr_table
[i
].cur_ierrors
/ avg_interval
));
2267 fprintf (stdout
, "%7llu ",
2268 (nr_table
[i
].cur_oerrors
/ avg_interval
));
2270 fprintf (stdout
, "%5llu ",
2271 (nr_table
[i
].cur_collisions
/ avg_interval
));
2273 fprintf (stdout
, " %5llu\n",
2274 (nr_table
[i
].cur_drops
/ avg_interval
));
2281 print_column_heading(int type
, char *timebufptr
, int mode
)
2290 if (!(flag_count
> 1))
2291 fprintf(stdout
, "\n");
2296 fprintf (stdout
, "\n%s %%usr %%sys %%idle\n", p
);
2300 if (mode
== 0) /* gflag */
2301 fprintf(stdout
, "\n%s pgout/s\n", p
);
2302 else if (mode
== 1) /* pflag */
2303 fprintf(stdout
, "\n%s pgin/s pflt/s vflt/s\n", p
);
2305 case SAR_DRIVESTATS
:
2306 fprintf(stdout
, "\n%s device r+w/s blks/s\n", p
);
2309 if (mode
== NET_DEV_MODE
)
2311 fprintf(stdout
, "\n%s %-8.8s %8.8s %10.10s %8.8s %10.10s\n", p
,
2312 " IFACE", "Ipkts/s", "Ibytes/s", "Opkts/s", "Obytes/s");
2314 else if (mode
== NET_EDEV_MODE
)
2316 fprintf(stdout
, "\n%s %-8.8s %7.7s %7.7s %5s %s\n", p
,
2317 " IFACE", "Ierrs/s", "Oerrs/s", "Coll/s", "Drop/s");