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