]> git.saurik.com Git - apple/system_cmds.git/blame - sar.tproj/sar.c
system_cmds-336.17.tar.gz
[apple/system_cmds.git] / sar.tproj / sar.c
CommitLineData
c3a08f59 1/*
83f6dbe8
A
2 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
3 * Reserved.
c3a08f59 4 *
83f6dbe8
A
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.
c3a08f59
A
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,
83f6dbe8
A
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*/
c3a08f59
A
20
21/*
22 cc -Wall -Wno-long-double -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 long 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
465 /* This is the child */
466 /* Close all file descriptors except the one we need */
467
468 for (i=0; i <= KERN_MAXFILESPERPROC; i++) {
469 if ((i != fd[0]) && (i != fd[1]))
470 (void)close(i);
471 }
472#if 0
473 efd = open("/tmp/errlog", O_CREAT|O_APPEND|O_RDWR, 0666);
474 if (dup2(efd,2) == -1) {
475 exit(1);
476 }
477#endif
478 /* Dup the two file descriptors to stdin and stdout */
479 if (dup2(fd[0],0) == -1) {
480 exit(1);
481 }
482 if (dup2(fd[1],1) == -1) {
483 exit(1);
484 }
485 /* Exec the child process */
486 if (network_mode & NET_PPP_MODE)
487 execl("/usr/lib/sa/sadc", "sadc", sadc_mflagp, sadc_ppp_modep, t_intervalp, n_samplesp, NULL);
488 else
489 execl("/usr/lib/sa/sadc", "sadc", t_intervalp, n_samplesp, NULL);
490
491 perror("execlp sadc");
492 exit(2); /* This call of exit(2) should never be reached... */
493 }
494 else
495 { /* This is the parent */
496 if (pid == -1) {
497 fprintf(stderr, "sar: fork(2) failed, errno = (%d)\n",errno);
498 exit(1);
499 }
500 close (fd[1]); /* parent does not write to the pipe */
501 ifd = fd[0]; /* parent will read from the pipe */
502 }
503 }
504 else
505 {
506 /* we're confused about source of input data - bail out */
507 fprintf(stderr, "sar: no input file recognized\n");
508 exit_usage();
509 }
510
511 /* start reading input data and format the output */
512 (void)do_main_workloop();
513 (void)exit_average();
514 exit(0);
515}
516
517static void
518exit_usage()
519{
520 fprintf(stderr, "\n%s\n\n", optionstring1_usage);
521 fprintf(stderr, "%s\n", optionstring2_usage);
522 exit(EXIT_FAILURE);
523}
524
525static void
526open_output_file(char *path)
527{
528 if ((ofd = open(path, O_CREAT|O_APPEND|O_TRUNC|O_WRONLY, 0664)) == -1 )
529 {
530 /* failed to open path */
531 fprintf(stderr, "sar: failed to open output file [%s]\n", path);
532 exit_usage();
533 }
534}
535
536
537static void
538open_input_file(char *path)
539{
540 if ((ifd = open(path, O_RDONLY, 0)) == -1)
541 {
542 /* failed to open path */
543 fprintf(stderr, "sar: failed to open input file [%d][%s]\n", ifd, path);
544 exit_usage();
545 }
546}
547
548static void
549read_record_hdr(hdr, writeflag)
550 struct record_hdr *hdr;
551 int writeflag;
552{
553 errno = 0;
554 int num = 0;
555 int n = 0;
556 size_t size = 0;
557
558 size = sizeof(struct record_hdr);
559
560 while (size)
561 {
562 num = read(ifd, &hdr[n], size);
563 if (num > 0)
564 {
565 n += num;
566 size -= num;
567 }
568 else if (num == 0)
569 exit_average();
570 else
571 {
572 fprintf(stderr, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno, (int)num, (int)size);
573 exit(EXIT_FAILURE);
574 }
575 }
576
577 if (oflag && writeflag)
578 write_record_hdr(hdr);
579
580 return;
581}
582
583static void
584read_record_data(buf, size, writeflag)
585 char * buf;
586 size_t size;
587 int writeflag;
588{
589 errno = 0;
590 size_t num = 0;
591 size_t n = 0;
592
593 while (size)
594 {
595 num = read(ifd, &buf[n], size);
596 if (num > 0)
597 {
598 n += num;
599 size -= num;
600 }
601 else if (num == 0) /* EOF */
602 exit_average();
603 else
604 {
605 fprintf(stderr, "sar: read_record_data failed, errno=%d num=%d, size=%d\n", (int)errno, (int)num, (int)size);
606 exit(EXIT_FAILURE);
607 }
608 }
609
610 if (oflag && writeflag)
611 write_record_data(buf, n);
612
613 return;
614}
615
616static void
617write_record_hdr(hdr)
618 struct record_hdr *hdr;
619{
620 errno = 0;
621 int num;
622
623 if ((num = write(ofd, hdr, sizeof(struct record_hdr))) == -1)
624 {
625 fprintf(stderr, "sar: write_record_hdr failed, errno=%d\n", errno);
626 exit(EXIT_FAILURE);
627 }
628 return;
629}
630
631static void
632write_record_data(char *buf, size_t nbytes)
633{
634 errno = 0;
635 int num;
636 if ((num = write(ofd, buf, nbytes)) == -1)
637 {
638 fprintf(stderr, "sar: write_record_data failed, errno=%d\n", errno);
639 exit(EXIT_FAILURE);
640 }
641 return;
642}
643
644/*
645 * Convert a string of one of the forms
646 * hh hh:mm hh:mm:ss
647 * into the number of seconds.
648 * exit on error
649*/
650
651static time_t
652convert_hms(string)
653 char *string;
654{
655 int hh = 0; /* hours */
656 int mm = 0; /* minutes */
657 int ss = 0; /* seconds */
658 time_t seconds;
659 time_t timestamp;
660 struct tm *tm;
661 int i;
662
663 if (string == NULL || *string == '\0')
664 goto convert_err;
665
666 for (i=0; string[i] != '\0'; i++)
667 {
668 if ((!isdigit(string[i])) && (string[i] != ':'))
669 {
670 goto convert_err;
671 }
672 }
673
674 if (sscanf(string, "%d:%d:%d", &hh, &mm, &ss) != 3)
675 {
676 if (sscanf(string, "%d:%d", &hh, &mm) != 2)
677 {
678 if (sscanf(string, "%d", &hh) != 1)
679 {
680 goto convert_err;
681 }
682 }
683 }
684
685 if (hh < 0 || hh >= HOURS_PER_DAY ||
686 mm < 0 || mm >= MINS_PER_HOUR ||
687 ss < 0 || ss > SECS_PER_MIN)
688 {
689 goto convert_err;
690 }
691
692 seconds = ((((hh * MINS_PER_HOUR) + mm) * SECS_PER_MIN) + ss);
693 timestamp = time((time_t *)0);
694 tm=localtime(&timestamp);
695 seconds -= tm->tm_gmtoff;
696
697 return(seconds);
698
699 convert_err:
700 fprintf(stderr, "sar: time format usage is hh[:mm[:ss]]\n");
701 exit_usage();
702 return(0);
703}
704
705
706/*
707 * Use ctime_r to convert a time value into
708 * a 26-character string of the form:
709 *
710 * Thu Nov 24 18:22:48 1986\n\0
711 */
712
713static char *
714get_hms_string(tdata, tbuf)
715 time_t tdata;
716 char *tbuf;
717{
718 time_t t;
719 char *p;
720
721 t = tdata;
722 ctime_r(&t, tbuf);
723 p=&tbuf[11];
724 tbuf[19] = 0;
725
726 return(p);
727}
728
729
730/* sample set flags */
731#define INIT_SET 0
732#define PRINT_SET 1
733#define PRINT_AVG 2
734
735static void
736do_main_workloop()
737{
738 struct record_hdr hdr;
739 time_t cur_timestamp = 0; /* seconds - Coordinated Universal Time */
740 time_t next_timestamp = 0; /* seconds - Coordinated Universal Time */
741
742 if (!find_restart_header(&hdr))
743 exit(1);
744
745 cur_timestamp = hdr.rec_timestamp;
746
747 /* convert sflag's start_time from 24 hour clock time to UTC seconds */
748 if (start_time < (cur_timestamp % SECS_PER_DAY))
749 start_time = cur_timestamp;
750 else
751 start_time += cur_timestamp - (cur_timestamp % SECS_PER_DAY);
752
753 /* convert end_time, from 24 hour clock time to UTC seconds */
754 if (end_time != 0)
755 end_time += cur_timestamp - (cur_timestamp % SECS_PER_DAY);
756
757#if 0
758 fprintf(stderr, "start = %ld, end = %ld, cur=%ld, [24hour - %ld]\n",
759 start_time, end_time, cur_timestamp,(cur_timestamp % SECS_PER_DAY));
760#endif
761
762 while (cur_timestamp < start_time)
763 {
764 bypass_sample_set(&hdr, cur_timestamp);
765 cur_timestamp = hdr.rec_timestamp;
766 }
767
768 next_timestamp = cur_timestamp + iseconds;
769 print_all_column_headings(cur_timestamp);
770 read_sample_set(INIT_SET, cur_timestamp, &hdr);
771 cur_timestamp = hdr.rec_timestamp;
772
773 while ((end_time == 0) || (next_timestamp < end_time))
774 {
775 if (cur_timestamp < next_timestamp)
776 {
777 bypass_sample_set (&hdr, cur_timestamp);
778 cur_timestamp = hdr.rec_timestamp;
779 }
780 else
781 {
782 /* need to know the seconds interval when printing averages */
783 if (avg_interval == 0)
784 {
785 if (iseconds)
786 avg_interval = iseconds;
787 else
788 avg_interval = cur_timestamp - next_timestamp;
789 }
790 next_timestamp = cur_timestamp + iseconds;
791 read_sample_set(PRINT_SET, cur_timestamp, &hdr);
792 cur_timestamp = hdr.rec_timestamp;
793 }
794 }
795 exit_average();
796}
797
798
799/*
800 * Find and fill in a restart header. We don't write
801 * the binary data when looking for SAR_RESTART.
802 * Return: 1 on success
803 * 0 on failure
804 */
805static int
806find_restart_header (ret_hdr)
807 struct record_hdr *ret_hdr;
808{
809 struct record_hdr hdr;
810 int bufsize = 0;
811 char *buf = NULL;
812
813 errno = 0;
814
815 restart_loop:
816 read_record_hdr(&hdr, FALSE); /* exits on error */
817
818 if (hdr.rec_type == SAR_RESTART)
819 {
820 *ret_hdr = hdr;
821 if (oflag)
822 write_record_hdr(&hdr); /* writes the RESTART record */
823 if (buf)
824 free(buf);
825 return(1);
826 }
827
828 /*
829 * not the record we want...
830 * read past data and try again
831 */
832 if (hdr.rec_count)
833 {
834 if (fflag)
835 { /* seek past data in the file */
836 if ((lseek(ifd, (hdr.rec_count * hdr.rec_size), SEEK_CUR)) == -1)
837 {
838 /*exit on error */
839 fprintf(stderr, "sar: lseek failed, errno=%d\n", errno);
840 exit(EXIT_FAILURE);
841 }
842
843 }
844 /* compute data size - malloc a new buf if it's not big enough */
845 else
846 {
847 /* have to read from the pipe */
848 if (bufsize < (hdr.rec_count * hdr.rec_size))
849 {
850 if (buf)
851 free(buf);
852 bufsize = hdr.rec_count * hdr.rec_size;
853 if((buf = (char *)malloc(bufsize)) == NULL)
854 {
855 fprintf(stderr, "sar: malloc failed\n");
856 return(0);
857 }
858 }
859 /* exits on error */
860 read_record_data(buf, (hdr.rec_count * hdr.rec_size), FALSE);
861 }
862 }
863 goto restart_loop;
864}
865
866static void
867print_all_column_headings(timestamp)
868 time_t timestamp;
869{
870 char timebuf[26];
871 char *timebufp;
872
873 timebufp = get_hms_string (timestamp, timebuf);
874
875 if (uflag) /* print cpu headers */
876 print_column_heading(SAR_CPU, timebufp, 0);
877
878 if (gflag) /* print page-out activity */
879 print_column_heading(SAR_VMSTAT, timebufp, 0);
880
881 if (pflag ) /* print page-in activity */
882 print_column_heading(SAR_VMSTAT, timebufp, 1);
883
884 if (dflag) /* print drive stats */
885 print_column_heading(SAR_DRIVESTATS, timebufp, 0);
886
887 if (nflag) /* print network stats */
888 {
889 if (network_mode & NET_DEV_MODE)
890 print_column_heading(SAR_NETSTATS, timebufp, NET_DEV_MODE);
891
892 if (network_mode & NET_EDEV_MODE)
893 print_column_heading(SAR_NETSTATS, timebufp, NET_EDEV_MODE);
894 }
895}
896
897
898/*
899 * Find and fill in a timestamp header.
900 * Write the binary data when looking for SAR_TIMESTAMP
901 * Don't do anything with the data, just read past it.
902 * Return: 1 on success
903 * 0 on failure
904 */
905static int
906bypass_sample_set (ret_hdr, timestamp)
907 struct record_hdr *ret_hdr;
908 time_t timestamp;
909{
910 struct record_hdr hdr;
911 int bufsize = 0;
912 char *buf = NULL;
913
914 bypass_loop:
915 read_record_hdr(&hdr, TRUE); /* exits on error */
916
917 if (hdr.rec_type == SAR_TIMESTAMP)
918 {
919 *ret_hdr = hdr;
920 if (buf)
921 free(buf);
922 return(1);
923 }
924
925 /*
926 * not the record we want...
927 * read past data and try again
928 */
929 if (hdr.rec_count)
930 {
931 if (fflag && !oflag)
932 {
933 /*
934 * we're reading from a file and we don't have to write the
935 * binary data so seek past data in the file
936 */
937 errno = 0;
938 if ((lseek(ifd, (hdr.rec_count * hdr.rec_size), SEEK_CUR)) == -1)
939 {
940 /*exit on error */
941 fprintf(stderr, "sar: lseek failed, errno=%d\n", errno);
942 exit(EXIT_FAILURE);
943 }
944 }
945 else
946 {
947 /*
948 * We end up here when reading from pipe.
949 * malloc a new buffer if current is not big enough
950 */
951 if (bufsize < (hdr.rec_count * hdr.rec_size))
952 {
953 if (buf)
954 free(buf);
955 bufsize = hdr.rec_count * hdr.rec_size;
956 if((buf = (char *)malloc(bufsize)) == NULL)
957 {
958 fprintf(stderr, "sar: malloc failed\n");
959 exit(EXIT_FAILURE);
960 }
961 }
962
963 /* exits on error */
964 read_record_data(buf, (hdr.rec_count * hdr.rec_size), TRUE);
965 }
966 } /* end if hdr.rec_count */
967 goto bypass_loop;
968}
969
970
971/*
972 * INIT_SET: This initializes the first sample for each type.
973 * PRINT_SET: This read, compute and print out sample data.
974 */
975static void
976read_sample_set(flag, timestamp, ret_hdr)
977 int flag;
978 time_t timestamp;
979 struct record_hdr *ret_hdr;
980{
981 struct record_hdr hdr;
982 char timebuf[26];
983 char *timebufp;
984 char *indent_string;
985 char *indent_string_wide;
986 char *indent_string_narrow;
987 int sar_cpu = 0;
988 int sar_vmstat=0;
989 int sar_drivestats=0;
990 int sar_drivepath=0;
991 int sar_netstats = 0;
992
993 indent_string_wide = " ";
994 indent_string_narrow = " ";
995 indent_string = indent_string_narrow;
996
997 read_record_hdr(&hdr, TRUE);
998
999 while (hdr.rec_type != SAR_TIMESTAMP)
1000 {
1001 switch (hdr.rec_type)
1002 {
1003 case SAR_CPU:
1004 sar_cpu = get_cpu_sample(flag, &hdr);
1005 break;
1006 case SAR_VMSTAT:
1007 sar_vmstat=get_vmstat_sample(flag, &hdr);
1008 break;
1009 case SAR_DRIVEPATH:
1010 sar_drivepath = get_drivepath_sample(flag, &hdr);
1011 if (sar_drivepath < 0)
1012 fprintf(stderr, "sar: drivepath sync code error %d\n", sar_drivepath);
1013 break;
1014 case SAR_DRIVESTATS:
1015 sar_drivestats = get_drivestats_sample(flag, &hdr);
1016 break;
1017 case SAR_NETSTATS:
1018 sar_netstats = get_netstats_sample(flag, &hdr);
1019 break;
1020 default:
1021 break;
1022 }
1023
1024 read_record_hdr(&hdr, TRUE);
1025 }
1026
1027 /* return the timestamp header */
1028 *ret_hdr = hdr;
1029
1030 if (flag == PRINT_SET)
1031 {
1032 avg_counter++;
1033 timebufp = get_hms_string(timestamp, timebuf);
1034
1035 if (uflag && sar_cpu)
1036 print_cpu_sample(timebufp);
1037
1038 if((gflag || pflag) && sar_vmstat)
1039 print_vmstat_sample(timebufp);
1040
1041 if (dflag && sar_drivestats)
1042 print_drivestats_sample(timebufp);
1043
1044 if (nflag && sar_netstats)
1045 print_netstats_sample(timebufp);
1046 }
1047}
1048
1049static void
1050skip_data(bufsize)
1051 int bufsize;
1052{
1053 char *buf = NULL;
1054
1055 if (fflag)
1056 {
1057 /* seek past data in the file */
1058 if ((lseek(ifd, bufsize, SEEK_CUR) == -1))
1059 {
1060 /*exit on error */
1061 fprintf(stderr, "sar: lseek failed, errno=%d\n", errno);
1062 exit(EXIT_FAILURE);
1063 }
1064 }
1065 else
1066 {
1067 /* have to read from the pipe */
1068 if((buf = (char *)malloc(bufsize)) == NULL)
1069 {
1070 fprintf(stderr, "sar: malloc failed\n");
1071 exit(EXIT_FAILURE);
1072 }
1073 /* even though we skip this data, we still write it if necessary */
1074 read_record_data(buf, bufsize, TRUE);
1075 }
1076 if (buf)
1077 free(buf);
1078
1079 return;
1080}
1081
1082static int
1083get_cpu_sample(flag, hdr)
1084 int flag;
1085 struct record_hdr *hdr;
1086{
1087 int datasize;
1088
1089 datasize = hdr->rec_count * hdr->rec_size;
1090
1091 if (datasize != sizeof(host_cpu_load_info_data_t))
1092 {
1093 /* read past the data but don't do anything with it */
1094 skip_data(datasize);
1095 return(0);
1096 }
1097
1098 read_record_data ((char *)&cur_cpuload, (int)sizeof(host_cpu_load_info_data_t), TRUE );
1099
1100 if (flag == INIT_SET)
1101 {
1102 prev_cpuload = cur_cpuload;
1103 bzero(&avg_cpuload, sizeof(avg_cpuload));
1104 }
1105 return(1);
1106}
1107
1108static void
1109print_cpu_sample(timebufptr)
1110 char * timebufptr;
1111{
1112
1113 double time;
1114
1115 time = 0.0;
1116 cur_cpuload.cpu_ticks[CPU_STATE_USER]
1117 -= prev_cpuload.cpu_ticks[CPU_STATE_USER];
1118
1119 prev_cpuload.cpu_ticks[CPU_STATE_USER]
1120 += cur_cpuload.cpu_ticks[CPU_STATE_USER];
1121
1122 time += cur_cpuload.cpu_ticks[CPU_STATE_USER];
1123
1124 cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
1125 -= prev_cpuload.cpu_ticks[CPU_STATE_SYSTEM];
1126
1127 prev_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
1128 += cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM];
1129
1130 time += cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM];
1131
1132 cur_cpuload.cpu_ticks[CPU_STATE_IDLE]
1133 -= prev_cpuload.cpu_ticks[CPU_STATE_IDLE];
1134
1135 prev_cpuload.cpu_ticks[CPU_STATE_IDLE]
1136 += cur_cpuload.cpu_ticks[CPU_STATE_IDLE];
1137
1138 time += cur_cpuload.cpu_ticks[CPU_STATE_IDLE];
1139
1140 avg_cpuload.cpu_ticks[CPU_STATE_USER] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_USER]
1141 / (time ? time : 1));
1142
1143 avg_cpuload.cpu_ticks[CPU_STATE_SYSTEM] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
1144 / (time ? time : 1));
1145
1146 avg_cpuload.cpu_ticks[CPU_STATE_IDLE] += rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_IDLE]
1147 / (time ? time : 1));
1148
1149 if(flag_count > 1)
1150 print_column_heading(SAR_CPU, timebufptr, 0);
1151
1152 fprintf(stdout, "%s%5.0f ", timebufptr,
1153 rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_USER]
1154 / (time ? time : 1)));
1155
1156 fprintf(stdout, "%4.0f ",
1157 rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
1158 / (time ? time : 1)));
1159
1160 fprintf(stdout, "%4.0f\n",
1161 rint(100. * cur_cpuload.cpu_ticks[CPU_STATE_IDLE]
1162 / (time ? time : 1)));
1163}
1164
1165static int
1166get_vmstat_sample(flag, hdr)
1167 int flag;
1168 struct record_hdr *hdr;
1169{
1170 int datasize;
1171
1172 datasize = hdr->rec_count * hdr->rec_size;
1173
1174 if (datasize != sizeof(struct vm_statistics))
1175 {
1176 /* read past the data but don't do anything with it */
1177 skip_data(datasize);
1178 return(0);
1179 }
1180
1181 read_record_data ((char *)&cur_vmstat, (int)sizeof(struct vm_statistics), TRUE );
1182
1183 if (flag == INIT_SET)
1184 {
1185 prev_vmstat = cur_vmstat;
1186 bzero(&avg_vmstat, sizeof(avg_vmstat));
1187 }
1188 return(1);
1189}
1190
1191
1192static void
1193print_vmstat_sample(char *timebufptr)
1194{
1195
1196 cur_vmstat.faults -= prev_vmstat.faults;
1197 prev_vmstat.faults += cur_vmstat.faults;
1198 avg_vmstat.faults += cur_vmstat.faults;
1199
1200 cur_vmstat.cow_faults -= prev_vmstat.cow_faults;
1201 prev_vmstat.cow_faults += cur_vmstat.cow_faults;
1202 avg_vmstat.cow_faults += cur_vmstat.cow_faults;
1203
1204 cur_vmstat.zero_fill_count -= prev_vmstat.zero_fill_count;
1205 prev_vmstat.zero_fill_count += cur_vmstat.zero_fill_count;
1206 avg_vmstat.zero_fill_count += cur_vmstat.zero_fill_count;
1207
1208 cur_vmstat.reactivations -= prev_vmstat.reactivations;
1209 prev_vmstat.reactivations += cur_vmstat.reactivations;
1210 avg_vmstat.reactivations += cur_vmstat.reactivations;
1211
1212 cur_vmstat.pageins -= prev_vmstat.pageins;
1213 prev_vmstat.pageins += cur_vmstat.pageins;
1214 avg_vmstat.pageins += cur_vmstat.pageins;
1215
1216 cur_vmstat.pageouts -= prev_vmstat.pageouts;
1217 prev_vmstat.pageouts += cur_vmstat.pageouts;
1218 avg_vmstat.pageouts += cur_vmstat.pageouts;
1219
1220
1221 if (gflag)
1222 {
1223 if (flag_count > 1)
1224 print_column_heading(SAR_VMSTAT, timebufptr, 0);
1225 fprintf(stdout, "%s %8.1f \n", timebufptr, (float)((float)cur_vmstat.pageouts/avg_interval));
1226 }
1227
1228 if (pflag)
1229 {
1230 if (flag_count > 1)
1231 print_column_heading(SAR_VMSTAT, timebufptr, 1);
1232 fprintf(stdout, "%s %8.1f %8.1f %8.1f\n", timebufptr,
1233 (float)((float)cur_vmstat.pageins / avg_interval),
1234 (float)((float)cur_vmstat.cow_faults/avg_interval),
1235 (float)((float)cur_vmstat.faults/avg_interval));
1236 }
1237 fflush(stdout);
1238}
1239
1240static int
1241get_drivestats_sample(flag, hdr)
1242 int flag;
1243 struct record_hdr *hdr;
1244{
1245 struct drivestats *databuf;
1246 struct drivestats_report *dr;
1247 size_t datasize;
1248 int datacount;
1249 int index;
1250 int i;
1251
1252 datasize = hdr->rec_count * hdr->rec_size;
1253 datacount = hdr->rec_count;
1254
1255 if (hdr->rec_size != sizeof(struct drivestats))
1256 {
1257 /* something isn't right... read past the data but don't analyze it */
1258 skip_data(datasize);
1259 return(0);
1260 }
1261
1262 /* malloc read buffer */
1263 if ((databuf = (struct drivestats *)malloc(datasize)) == NULL)
1264 {
1265 fprintf(stderr, "sar: malloc failed\n");
1266 exit (EXIT_FAILURE);
1267 }
1268
1269 bzero(databuf, datasize);
1270
1271 read_record_data ((char *)databuf, datasize, TRUE );
1272
1273 /* clear all global current fields */
1274 for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
1275 {
1276 dr->present = 0;
1277 dr->cur_Reads = 0;
1278 dr->cur_BytesRead = 0;
1279 dr->cur_Writes = 0;
1280 dr->cur_BytesWritten = 0;
1281 dr->cur_LatentReadTime = 0;
1282 dr->cur_LatentWriteTime = 0;
1283 dr->cur_ReadErrors = 0;
1284 dr->cur_WriteErrors = 0;
1285 dr->cur_ReadRetries = 0;
1286 dr->cur_WriteRetries = 0;
1287 dr->cur_TotalReadTime = 0;
1288 dr->cur_TotalWriteTime=0;
1289 }
1290
1291 /* By this point, we have read in a complete set of diskstats from the sadc
1292 * data collector.
1293 * The order of the drives in not guaranteed.
1294 * The global report structure is a linked list, but may need initialization
1295 * We need to traverse this list and transfer the current
1296 * read data. If a disk entry isn't found, then we need to allocate one
1297 * initilize it.
1298 */
1299 for (i=0; i< datacount; i++)
1300 {
1301 struct drivestats_report *dr_last = NULL;
1302
1303 index = databuf[i].drivepath_id; /* use this as index into dp_table */
1304
1305 /* find disk entry or allocate new one*/
1306 for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
1307 {
1308 dr_last = dr;
1309 if(index == dr->drivepath_id)
1310 break;
1311 }
1312
1313 if (dr == NULL)
1314 {
1315 /* allocate new entry */
1316 if((dr = (struct drivestats_report *)malloc(sizeof(struct drivestats_report))) == NULL)
1317 {
1318 fprintf(stderr, "sar: malloc error\n");
1319 exit(EXIT_FAILURE);
1320 }
1321 bzero((char *)dr, sizeof(struct drivestats_report));
1322 dr->blocksize = databuf[i].blocksize;
1323 dr->drivepath_id = index;
1324 dr->next = NULL;
1325 dr->avg_count = 0;
1326
1327 /* get the BSDName which should be in the table by now */
1328 if ((index < dp_count) && (dp_table[index].state != DPSTATE_UNINITIALIZED))
1329 strncpy(dr->name, dp_table[index].BSDName, MAXDRIVENAME+1);
1330 else
1331 strcpy(dr->name, "disk??");
1332
1333 if (dr_head == NULL)
1334 {
1335 dr_head = dr;
1336 dr_head->next = NULL;
1337 }
1338 else
1339 {
1340 dr_last->next = (char *)dr;
1341 }
1342 } /* end if dr == NULL */
1343
1344 dr->present = TRUE;
1345 dr->cur_Reads = databuf[i].Reads;
1346 dr->cur_BytesRead = databuf[i].BytesRead;
1347 dr->cur_Writes = databuf[i].Writes;
1348 dr->cur_BytesWritten = databuf[i].BytesWritten;
1349 dr->cur_LatentReadTime = databuf[i].LatentReadTime;
1350 dr->cur_LatentWriteTime = databuf[i].LatentWriteTime;
1351 dr->cur_ReadErrors = databuf[i].ReadErrors;
1352 dr->cur_WriteErrors = databuf[i].WriteErrors;
1353 dr->cur_ReadRetries = databuf[i].ReadRetries;
1354 dr->cur_WriteRetries = databuf[i].WriteRetries;
1355 dr->cur_TotalReadTime = databuf[i].TotalReadTime;
1356 dr->cur_TotalWriteTime=databuf[i].TotalWriteTime;
1357 } /* end for loop */
1358
1359 /* Reinitialize the prev and avg fields when
1360 * This is a new disk
1361 * This is a changed disk - name change implies disk swapping
1362 * This disk is not present in this sample
1363 */
1364 for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
1365 {
1366 if (dr->drivepath_id >= dp_count)
1367 {
1368 /* something is amiss */
1369 continue;
1370 }
1371 else
1372 {
1373 index = dr->drivepath_id; /* use this as index into dp_table */
1374 }
1375
1376 if ((flag == INIT_SET) ||
1377 (dp_table[index].state == DPSTATE_NEW) ||
1378 (dp_table[index].state == DPSTATE_CHANGED) ||
1379 (!dr->present))
1380 {
1381 /*
1382 * prev will be set to cur
1383 * activate the state in dp_table
1384 */
1385 if (dr->present)
1386 dp_table[index].state = DPSTATE_ACTIVE;
1387
1388 init_drivestats(dr);
1389 }
1390 }
1391 return(1);
1392}
1393
1394static void
1395init_drivestats(struct drivestats_report *dr)
1396{
1397 dr->avg_count = 0;
1398 dr->prev_Reads = dr->cur_Reads;
1399 dr->avg_Reads = 0;
1400 dr->prev_BytesRead = dr->cur_BytesRead;
1401 dr->avg_BytesRead = 0;
1402 dr->prev_Writes = dr->cur_Writes;
1403 dr->avg_Writes = 0;
1404 dr->prev_BytesWritten = dr->cur_BytesWritten;
1405 dr->avg_BytesWritten = 0;
1406 dr->prev_LatentReadTime = dr->cur_LatentReadTime;
1407 dr->avg_LatentReadTime = 0;
1408 dr->prev_LatentWriteTime = dr->cur_LatentWriteTime ;
1409 dr->avg_LatentWriteTime = 0;
1410 dr->prev_ReadErrors = dr->cur_ReadErrors ;
1411 dr->avg_ReadErrors = 0;
1412 dr->prev_WriteErrors = dr->cur_WriteErrors ;
1413 dr->avg_WriteErrors = 0;
1414 dr->prev_ReadRetries = dr->cur_ReadRetries ;
1415 dr->avg_ReadRetries = 0;
1416 dr->prev_WriteRetries = dr->cur_WriteRetries ;
1417 dr->avg_WriteRetries = 0;
1418 dr->prev_TotalReadTime = dr->cur_TotalReadTime ;
1419 dr->avg_TotalReadTime = 0;
1420 dr->prev_TotalWriteTime = dr->cur_TotalWriteTime ;
1421 dr->avg_TotalWriteTime = 0;
1422}
1423
1424
1425static void
1426print_drivestats_sample(char *timebufptr)
1427{
1428 struct drivestats_report *dr;
1429 long double transfers_per_second;
1430 long double kb_per_transfer, mb_per_second;
1431 u_int64_t interval_bytes, interval_transfers, interval_blocks;
1432 u_int64_t interval_time;
1433 long double blocks_per_second, ms_per_transaction;
1434
1435 if (flag_count > 1)
1436 print_column_heading(SAR_DRIVESTATS, timebufptr, 0);
1437
1438 for (dr=dr_head; dr; dr=(struct drivestats_report *)dr->next)
1439 {
1440 if(!dr->present)
1441 continue;
1442
1443 /*
1444 * This sanity check is for drives that get removed and then
1445 * returned during the sampling sleep interval. If anything
1446 * looks out of sync, reinit and skip this entry. There is
1447 * no way to guard against this entirely.
1448 */
1449 if ((dr->cur_Reads < dr->prev_Reads) ||
1450 (dr->cur_BytesRead < dr->prev_BytesRead) ||
1451 (dr->cur_Writes < dr->prev_Writes) ||
1452 (dr->cur_BytesWritten < dr->prev_BytesWritten))
1453 {
1454 init_drivestats(dr);
1455 continue;
1456 }
1457
1458 dr->avg_count++;
1459
1460 dr->cur_Reads -= dr->prev_Reads;
1461 dr->prev_Reads += dr->cur_Reads;
1462 dr->avg_Reads += dr->cur_Reads;
1463
1464 dr->cur_BytesRead -= dr->prev_BytesRead;
1465 dr->prev_BytesRead += dr->cur_BytesRead;
1466 dr->avg_BytesRead += dr->cur_BytesRead;
1467
1468 dr->cur_Writes -= dr->prev_Writes ;
1469 dr->prev_Writes += dr->cur_Writes ;
1470 dr->avg_Writes += dr->cur_Writes ;
1471
1472 dr->cur_BytesWritten -= dr->prev_BytesWritten ;
1473 dr->prev_BytesWritten += dr->cur_BytesWritten ;
1474 dr->avg_BytesWritten += dr->cur_BytesWritten ;
1475
1476 dr->cur_LatentReadTime -= dr->prev_LatentReadTime ;
1477 dr->prev_LatentReadTime += dr->cur_LatentReadTime ;
1478 dr->avg_LatentReadTime += dr->cur_LatentReadTime ;
1479
1480 dr->cur_LatentWriteTime -= dr->prev_LatentWriteTime ;
1481 dr->prev_LatentWriteTime += dr->cur_LatentWriteTime ;
1482 dr->avg_LatentWriteTime += dr->cur_LatentWriteTime ;
1483
1484 dr->cur_ReadErrors -= dr->prev_ReadErrors ;
1485 dr->prev_ReadErrors += dr->cur_ReadErrors ;
1486 dr->avg_ReadErrors += dr->cur_ReadErrors ;
1487
1488 dr->cur_WriteErrors -= dr->prev_WriteErrors ;
1489 dr->prev_WriteErrors += dr->cur_WriteErrors ;
1490 dr->avg_WriteErrors += dr->cur_WriteErrors ;
1491
1492 dr->cur_ReadRetries -= dr->prev_ReadRetries ;
1493 dr->prev_ReadRetries += dr->cur_ReadRetries ;
1494 dr->avg_ReadRetries += dr->cur_ReadRetries ;
1495
1496 dr->cur_WriteRetries -= dr->prev_WriteRetries ;
1497 dr->prev_WriteRetries += dr->cur_WriteRetries;
1498 dr->avg_WriteRetries += dr->cur_WriteRetries;
1499
1500 dr->cur_TotalReadTime -= dr->prev_TotalReadTime ;
1501 dr->prev_TotalReadTime += dr->cur_TotalReadTime ;
1502 dr->avg_TotalReadTime += dr->cur_TotalReadTime ;
1503
1504 dr->cur_TotalWriteTime -= dr->prev_TotalWriteTime ;
1505 dr->prev_TotalWriteTime += dr->cur_TotalWriteTime ;
1506 dr->avg_TotalWriteTime += dr->cur_TotalWriteTime ;
1507
1508 /* I/O volume */
1509 interval_bytes = dr->cur_BytesRead + dr->cur_BytesWritten;
1510
1511 /* I/O counts */
1512 interval_transfers = dr->cur_Reads + dr->cur_Writes;
1513
1514 /* I/O time */
1515 interval_time = dr->cur_LatentReadTime + dr->cur_LatentWriteTime;
1516
1517 interval_blocks = interval_bytes / dr->blocksize;
1518 blocks_per_second = interval_blocks / avg_interval;
1519 transfers_per_second = interval_transfers / avg_interval;
1520 mb_per_second = (interval_bytes / avg_interval) / (1024 *1024);
1521
1522 kb_per_transfer = (interval_transfers > 0) ?
1523 ((long double)interval_bytes / interval_transfers)
1524 / 1024 : 0;
1525
1526 /* times are in nanoseconds, convert to milliseconds */
1527 ms_per_transaction = (interval_transfers > 0) ?
1528 ((long double)interval_time / interval_transfers)
1529 / 1000 : 0;
1530
1531 /* print device name */
1532 fprintf(stdout, "%s %-10s", timebufptr, dr->name);
1533
1534 /* print transfers per second */
1535 fprintf(stdout, "%4.0Lf ", transfers_per_second);
1536
1537 /* print blocks per second - in device blocksize */
1538 fprintf(stdout, "%4.0Lf\n", blocks_per_second);
1539 }
1540}
1541
1542/*
1543 * Print averages before exiting.
1544 */
1545static void
1546exit_average()
1547{
1548 int i;
1549
1550 if (avg_counter <= 0 )
1551 exit(0);
1552
1553 if (oflag)
1554 {
1555 if (ofd)
1556 close (ofd);
1557 ofd = 0;
1558 }
1559
1560 if (uflag) /* print cpu averages */
1561 {
1562 if(flag_count > 1)
1563 print_column_heading(SAR_CPU, 0, 0);
1564
1565 fprintf(stdout, "Average: %5d ",
1566 (int)avg_cpuload.cpu_ticks[CPU_STATE_USER]
1567 / (avg_counter ? avg_counter : 1));
1568
1569 fprintf(stdout, "%4d ",
1570 (int)avg_cpuload.cpu_ticks[CPU_STATE_SYSTEM]
1571 / (avg_counter ? avg_counter : 1));
1572
1573 fprintf(stdout, "%4d \n",
1574 (int)avg_cpuload.cpu_ticks[CPU_STATE_IDLE]
1575 / (avg_counter ? avg_counter : 1));
1576
1577 fflush(stdout);
1578 }
1579
1580
1581 if (gflag) /* print page-out averages */
1582 {
1583 if (flag_count > 1)
1584 print_column_heading(SAR_VMSTAT, 0, 0);
1585
1586 fprintf(stdout, "Average: %8.1f\n",
1587 (float)((avg_vmstat.pageouts / (avg_counter ? avg_counter : 1)) / avg_interval));
1588 fflush(stdout);
1589 }
1590
1591 if (pflag) /* print page-in averages */
1592 {
1593 if (flag_count > 1)
1594 print_column_heading(SAR_VMSTAT, 0, 1);
1595
1596 fprintf(stdout, "Average: %8.1f %8.1f %8.1f\n",
1597 (float)(((float)avg_vmstat.pageins / (avg_counter ? avg_counter : 1)) / avg_interval),
1598 (float)(((float)avg_vmstat.cow_faults / (avg_counter ? avg_counter : 1)) / avg_interval),
1599 (float)(((float)avg_vmstat.faults / (avg_counter ? avg_counter : 1)) / avg_interval));
1600 fflush(stdout);
1601 }
1602
1603 if (dflag) /* print drivestats averages */
1604 {
1605 struct drivestats_report *dr;
1606 long double transfers_per_second;
1607 long double kb_per_transfer, mb_per_second;
1608 u_int64_t total_bytes, total_transfers, total_blocks;
1609 u_int64_t total_time;
1610 long double blocks_per_second, ms_per_transaction;
1611 int msdig;
1612
1613 if (flag_count > 1)
1614 print_column_heading(SAR_DRIVESTATS, 0, 0);
1615
1616 for (dr=dr_head; dr; dr=(struct drivestats_report *)dr->next)
1617 {
1618 /* don't bother to print out averages for disks that were removed */
1619 if (!dr->present)
1620 continue;
1621
1622 fprintf(stdout, " %s %s\n",
1623 dp_table[dr->drivepath_id].BSDName, dp_table[dr->drivepath_id].ioreg_path);
1624
1625 /* I/O volume */
1626 total_bytes = dr->avg_BytesRead + dr->avg_BytesWritten;
1627
1628 /* I/O counts */
1629 total_transfers = dr->avg_Reads + dr->avg_Writes;
1630
1631 /* I/O time */
1632 total_time = dr->avg_LatentReadTime + dr->avg_LatentWriteTime;
1633
1634 total_blocks = total_bytes / dr->blocksize;
1635 blocks_per_second = total_blocks / avg_interval;
1636 transfers_per_second = total_transfers / avg_interval;
1637 mb_per_second = (total_bytes / avg_interval) / (1024 *1024);
1638
1639 kb_per_transfer = (total_transfers > 0) ?
1640 ((long double)total_bytes / total_transfers)
1641 / 1024 : 0;
1642
1643 /* times are in nanoseconds, convert to milliseconds */
1644 ms_per_transaction = (total_transfers > 0) ?
1645 ((long double)total_time / total_transfers)
1646 / 1000 : 0;
1647 msdig = (ms_per_transaction < 100.0) ? 1 : 0;
1648 fprintf(stdout, "Average: %-10s %4.0Lf %4.0Lf\n",
1649 dr->name,
1650 (transfers_per_second / dr->avg_count),
1651 (blocks_per_second / dr->avg_count));
1652
1653 fflush(stdout);
1654 }
1655 } /* end if dflag */
1656
1657 if (nflag)
1658 {
1659 int avg_count;
1660
1661 if (network_mode & NET_DEV_MODE)
1662 {
1663 if (flag_count > 1)
1664 print_column_heading(SAR_NETSTATS, 0, NET_DEV_MODE);
1665 for (i = 0; i < nr_count; i++)
1666 {
1667 if (!nr_table[i].valid)
1668 continue;
1669
1670 if(nr_table[i].avg_count == 0)
1671 avg_count = 1;
1672 else
1673 avg_count = nr_table[i].avg_count;
1674
1675 fprintf(stdout, "Average: %-8.8s", nr_table[i].tname_unit);
1676
1677 fprintf (stdout, "%8llu ",
1678 ((nr_table[i].avg_ipackets / avg_count) / avg_interval));
1679
1680 fprintf (stdout, "%10llu ",
1681 ((nr_table[i].avg_ibytes / avg_count) / avg_interval));
1682
1683 fprintf (stdout, "%8llu ",
1684 ((nr_table[i].avg_opackets / avg_count) / avg_interval));
1685
1686 fprintf (stdout, "%10llu\n",
1687 ((nr_table[i].avg_obytes / avg_count) / avg_interval));
1688
1689 fflush(stdout);
1690 }
1691 }
1692
1693 if (network_mode & NET_EDEV_MODE)
1694 {
1695
1696 if(flag_count > 1)
1697 print_column_heading(SAR_NETSTATS, 0, NET_EDEV_MODE);
1698
1699 for (i = 0; i < nr_count; i++)
1700 {
1701 if (!nr_table[i].valid)
1702 continue;
1703
1704 if(nr_table[i].avg_count == 0)
1705 avg_count = 1;
1706 else
1707 avg_count = nr_table[i].avg_count;
1708
1709 fprintf(stdout, "Average: %-8.8s ", nr_table[i].tname_unit);
1710
1711 fprintf (stdout, "%7llu ",
1712 ((nr_table[i].avg_ierrors / avg_count) / avg_interval));
1713
1714 fprintf (stdout, "%7llu ",
1715 ((nr_table[i].avg_oerrors / avg_count) / avg_interval));
1716
1717 fprintf (stdout, "%5llu ",
1718 ((nr_table[i].avg_collisions / avg_count) / avg_interval));
1719
1720 fprintf (stdout, " %5llu\n",
1721 ((nr_table[i].avg_drops / avg_count) / avg_interval));
1722
1723 fflush(stdout);
1724 }
1725 }
1726
1727 } /* end if nflag */
1728 exit(0);
1729}
1730
1731
1732/*
1733 * Return < 0 failure, debugging purposes only
1734 * Return = 0 data skipped
1735 * Return > 0 success
1736 */
1737
1738static int
1739get_drivepath_sample(flag, hdr)
1740 int flag;
1741 struct record_hdr *hdr;
1742{
1743 size_t datasize;
1744 struct drivepath dp;
1745 struct drivestats_report *dr;
1746 int i, n;
1747
1748 datasize = hdr->rec_count * hdr->rec_size;
1749
1750 if (datasize != sizeof(struct drivepath))
1751 {
1752 /* read past the data but don't do anything with it */
1753 skip_data(datasize);
1754 return(0);
1755 }
1756
1757 read_record_data ((char *)&dp, (int)sizeof(struct drivepath), TRUE );
1758
1759 /*
1760 * If state is new -- put a new entry in the dp_table.
1761 * If state is changed -- traverse the drivestats_report table
1762 * and copy new name.
1763 */
1764 if (dp.state == DPSTATE_NEW)
1765 {
1766
1767 if (dp_table == NULL)
1768 {
1769 if (dp.drivepath_id != 0)
1770 return(-1);
1771 /* First setup of internal drivepath table */
1772 dp_table = (struct drivepath *)malloc(sizeof(struct drivepath));
1773 if (dp_table == NULL)
1774 return(-2);
1775 dp_count = 1;
1776 }
1777
1778 if (dflag)
1779 fprintf(stdout, "New Disk: [%s] %s\n", dp.BSDName, dp.ioreg_path);
1780
1781 /* traverse table and find next uninitialized entry */
1782 for (i = 0; i< dp_count; i++)
1783 {
1784 if (dp_table[i].state == DPSTATE_UNINITIALIZED)
1785 {
1786 if (dp.drivepath_id != i)
1787 {
1788 /* the table is out of sync - this should not happen */
1789 return (-3);
1790 }
1791 dp_table[i] = dp;
1792 return(1);
1793 }
1794 }
1795 /*
1796 * If we get here, we've run out of table entries.
1797 * Double the size of the table, then assign the next entry.
1798 */
1799 if (dp.drivepath_id != i)
1800 {
1801 /* the table is out of sync - this should not happen */
1802 return (-4);
1803 }
1804 n = dp_count * 2;
1805 dp_table = (struct drivepath *)realloc(dp_table, n * sizeof(struct drivepath));
1806 bzero(&dp_table[dp_count], dp_count * sizeof(struct drivepath));
1807 dp_table[dp_count] = dp;
1808 dp_count = n;
1809 return(1);
1810
1811 }
1812 else if (dp.state == DPSTATE_CHANGED)
1813 {
1814
1815 /* Update the name in the table */
1816 if ((dp.drivepath_id < dp_count) && (dp_table[dp.drivepath_id].state != DPSTATE_UNINITIALIZED))
1817 {
1818 if (strcmp(dp_table[dp.drivepath_id].ioreg_path, dp.ioreg_path) != 0)
1819 {
1820 /* something is amiss */
1821 return (-5);
1822 }
1823 else
1824 {
1825 if (dflag)
1826 {
1827 fprintf(stdout, "Change: [%s] %s\n", dp.BSDName,
1828 dp_table[dp.drivepath_id].ioreg_path);
1829 }
1830 strcpy(dp_table[dp.drivepath_id].BSDName, dp.BSDName);
1831
1832 for(dr = dr_head; dr; dr=(struct drivestats_report *)dr->next)
1833 {
1834 if (dr->drivepath_id == dp.drivepath_id)
1835 strcpy(dr->name, dp.BSDName);
1836 }
1837 return(1);
1838 }
1839 }
1840 else
1841 return(-6);
1842 }
1843 return(-7);
1844}
1845
1846/*
1847 * Bytes and packet counts are used to track
1848 * counter wraps. So, don't enforce the
1849 * NET_DEV_MODE or NET_EDEV_MODE in here.
1850 * Maintain all the stats.
1851 */
1852static void
1853set_cur_netstats(struct netstats_report *nr, struct netstats *ns)
1854{
1855
1856 nr->cur_ipackets = ns->net_ipackets;
1857 nr->cur_ibytes = ns->net_ibytes;
1858 nr->cur_opackets = ns->net_opackets;
1859 nr->cur_obytes = ns->net_obytes;
1860
1861 nr->cur_ierrors = ns->net_ierrors;
1862 nr->cur_oerrors = ns->net_oerrors;
1863 nr->cur_collisions = ns->net_collisions;
1864 nr->cur_drops = ns->net_drops;
1865
1866 nr->cur_imcasts = ns->net_imcasts;
1867 nr->cur_omcasts = ns->net_omcasts;
1868
1869}
1870
1871static void
1872init_prev_netstats(struct netstats_report *nr)
1873{
1874 nr->avg_count = 0;
1875 nr->valid = 1;
1876 nr->present = 1;
1877
1878 nr->prev_ipackets = nr->cur_ipackets;
1879 nr->avg_ipackets = 0;
1880 nr->prev_ibytes = nr->cur_ibytes;
1881 nr->avg_ibytes = 0;
1882 nr->prev_opackets = nr->cur_opackets;
1883 nr->avg_opackets = 0;
1884 nr->prev_obytes = nr->cur_obytes;
1885 nr->avg_obytes = 0;
1886
1887 nr->prev_ierrors = nr->cur_ierrors;
1888 nr->avg_ierrors = 0;
1889 nr->prev_oerrors = nr->cur_oerrors ;
1890 nr->avg_oerrors = 0;
1891 nr->prev_collisions = nr->cur_collisions ;
1892 nr->avg_collisions = 0;
1893 nr->prev_drops = nr->cur_drops ;
1894 nr->avg_drops = 0;
1895
1896 /* track these, but never displayed */
1897 nr->prev_imcasts = nr->cur_imcasts;
1898 nr->avg_imcasts = 0;
1899 nr->prev_omcasts = nr->cur_omcasts;
1900 nr->avg_omcasts = 0;
1901}
1902
1903/*
1904 * Success : 1
1905 * Failure : 0
1906 */
1907static int
1908get_netstats_sample(flag, hdr)
1909 int flag;
1910 struct record_hdr *hdr;
1911{
1912 struct netstats *databuf = NULL;
1913 size_t datasize;
1914 int datacount;
1915 int i, j;
1916
1917 datasize = hdr->rec_count * hdr->rec_size;
1918 datacount = hdr->rec_count;
1919
1920 if (hdr->rec_size != sizeof(struct netstats))
1921 {
1922 /* something isn't right... read past the data but don't analyze it */
1923 skip_data(datasize);
1924 return(0);
1925 }
1926
1927 /* malloc new or bigger read buffer */
1928 if((netstat_readbuf == NULL) || (netstat_readbuf_size < datasize))
1929 {
1930 if (netstat_readbuf)
1931 free (netstat_readbuf);
1932
1933 if ((netstat_readbuf = (struct netstats *)malloc(datasize)) == NULL)
1934 {
1935 fprintf(stderr, "sar: malloc failed\n");
1936 exit (EXIT_FAILURE);
1937 }
1938 netstat_readbuf_size = datasize;
1939 }
1940
1941 bzero(netstat_readbuf, netstat_readbuf_size);
1942 databuf = netstat_readbuf;
1943
1944 read_record_data ((char *)databuf, datasize, TRUE );
1945
1946 if (nr_table == NULL)
1947 {
1948 /* initial internal table setup */
1949 nr_table = (struct netstats_report *)malloc(datacount * sizeof(struct netstats_report));
1950 nr_count = datacount;
1951 bzero(nr_table, (datacount * sizeof(struct netstats_report)));
1952
1953 /* on first init, this is faster than finding our way to NEW_ENTRY */
1954 for (i = 0; i < datacount; i++)
1955 {
1956 if (!(network_mode & NET_PPP_MODE))
1957 {
1958 if (!strncmp(databuf[i].tname_unit, "ppp", 3))
1959 continue; /*
1960 * Skip ppp interfaces.
1961 * ie don't even put them in this internal table.
1962 */
1963 }
1964 strncpy(nr_table[i].tname_unit, databuf[i].tname_unit, MAX_TNAME_UNIT_SIZE);
1965 nr_table[i].tname_unit[MAX_TNAME_UNIT_SIZE] = '\0';
1966 set_cur_netstats(&nr_table[i], &databuf[i]);
1967 init_prev_netstats(&nr_table[i]);
1968 }
1969 return(1);
1970 }
1971
1972 /*
1973 * clear all the present flags.
1974 * As we traverse the current sample set
1975 * and update the internal table, the flag
1976 * is reset.
1977 */
1978 for (i = 0; i < nr_count; i++)
1979 {
1980 nr_table[i].present = 0;
1981 }
1982
1983 /*
1984 * Find and update table entries.
1985 * Init new entries.
1986 */
1987 for (i=0; i<datacount; i++)
1988 {
1989 int found;
1990 char *name;
1991 int nr_index;
1992 int n;
1993
1994 name = databuf[i].tname_unit;
1995 found = 0;
1996
1997 if (!(network_mode & NET_PPP_MODE))
1998 {
1999 if (!strncmp(name, "ppp", 3))
2000 continue; /* skip ppp interfaces */
2001 }
2002
2003 /* Find the matching entry using the interface name */
2004 for (j=0; j < nr_count && !found; j++)
2005 {
2006 if (nr_table[j].valid)
2007 {
2008 if(!strcmp(nr_table[j].tname_unit, name))
2009 {
2010 found = 1;
2011 nr_table[j].present = 1;
2012 set_cur_netstats(&nr_table[j], &databuf[i]);
2013 }
2014 }
2015 } /* end for */
2016
2017 if (!found) /* this is a new entry */
2018 {
2019 /* Find an invalid entry in the table and init it */
2020 for (j=0; j < nr_count; j++)
2021 {
2022 if (!nr_table[j].valid)
2023 {
2024 nr_index = j;
2025 goto NEW_ENTRY;
2026 }
2027 }
2028
2029 /* we ran out of entries... grow the table */
2030 n = nr_count * 2;
2031 nr_table = (struct netstats_report *)realloc(nr_table, n * sizeof(struct netstats_report));
2032 bzero(&nr_table[nr_count], nr_count * sizeof (struct netstats_report));
2033 nr_index = nr_count;
2034 nr_count = n;
2035
2036 NEW_ENTRY:
2037 strncpy(nr_table[nr_index].tname_unit, databuf[i].tname_unit, MAX_TNAME_UNIT_SIZE);
2038 nr_table[nr_index].tname_unit[MAX_TNAME_UNIT_SIZE] = '\0';
2039 set_cur_netstats(&nr_table[nr_index], &databuf[i]);
2040 init_prev_netstats(&nr_table[nr_index]);
2041 }
2042
2043 } /* end for */
2044
2045 /*
2046 * Traverse the internal table. Any valid entry that wasn't
2047 * present in this sample is cleared for reuse.
2048 */
2049 for (i = 0; i < nr_count; i++)
2050 {
2051 if (nr_table[i].valid)
2052 {
2053 if (nr_table[i].present == 0)
2054 bzero(&nr_table[i], sizeof(struct netstats_report));
2055 }
2056 }
2057 return (1);
2058}
2059
2060static void
2061print_netstats_sample(char *timebufptr)
2062{
2063 int i;
2064
2065 for (i=0; i < nr_count; i++)
2066 {
2067 if (!nr_table[i].valid)
2068 continue;
2069
2070 /*
2071 * This is where we attempt to handle counters that
2072 * might wrap ... the kernel netstats are only 32 bits.
2073 *
2074 * Interfaces may go away and then return within the
2075 * sampling period. This can't be detected and it
2076 * may look like a counter wrap. An interface generation
2077 * counter will help... but isn't implemented at this time.
2078 */
2079
2080 /*
2081 * The ppp interfaces are very likely to come and go during
2082 * a sampling period. During the normal life of a ppp interface,
2083 * it's less likely that the packet counter will wrap, so if
2084 * it appears to have done so, is probably because the
2085 * interface unit number has been reused.
2086 * We reinitialize that interface in that case.
2087 */
2088 if (network_mode & NET_PPP_MODE)
2089 {
2090 /*
2091 * ppp interfaces won't even make it into this table
2092 * when NET_PPP_MODE isn't set
2093 */
2094 if (!strncmp(nr_table[i].tname_unit, "ppp", 3))
2095 {
2096 /*
2097 * Both ipackets and opackets have to be less
2098 * than the previous counter to cause us to reinit.
2099 */
2100
2101 if ((nr_table[i].cur_ipackets < nr_table[i].prev_ipackets)
2102 && (nr_table[i].cur_opackets < nr_table[i].prev_opackets))
2103 {
2104 init_prev_netstats(&nr_table[i]);
2105 continue;
2106 }
2107 }
2108 }
2109
2110 nr_table[i].avg_count ++;
2111
2112#ifdef IFNET_32_BIT_COUNTERS
2113 while (nr_table[i].cur_ipackets < nr_table[i].prev_ipackets)
2114 nr_table[i].cur_ipackets += 0x100000000LL;
2115#endif /* IFNET_32_BIT_COUNTERS */
2116 nr_table[i].cur_ipackets -= nr_table[i].prev_ipackets;
2117 nr_table[i].prev_ipackets += nr_table[i].cur_ipackets;
2118 nr_table[i].avg_ipackets += nr_table[i].cur_ipackets;
2119
2120
2121#ifdef IFNET_32_BIT_COUNTERS
2122 while (nr_table[i].cur_ibytes < nr_table[i].prev_ibytes)
2123 nr_table[i].cur_ibytes += 0x100000000LL;
2124#endif /* IFNET_32_BIT_COUNTERS */
2125 nr_table[i].cur_ibytes -= nr_table[i].prev_ibytes;
2126 nr_table[i].prev_ibytes += nr_table[i].cur_ibytes;
2127 nr_table[i].avg_ibytes += nr_table[i].cur_ibytes;
2128
2129
2130#ifdef IFNET_32_BIT_COUNTERS
2131 while (nr_table[i].cur_opackets < nr_table[i].prev_opackets)
2132 nr_table[i].cur_opackets += 0x100000000LL;
2133#endif /* IFNET_32_BIT_COUNTERS */
2134 nr_table[i].cur_opackets -= nr_table[i].prev_opackets;
2135 nr_table[i].prev_opackets += nr_table[i].cur_opackets;
2136 nr_table[i].avg_opackets += nr_table[i].cur_opackets;
2137
2138#ifdef IFNET_32_BIT_COUNTERS
2139 while (nr_table[i].cur_obytes < nr_table[i].prev_obytes)
2140 nr_table[i].cur_obytes += 0x100000000LL;
2141#endif /* IFNET_32_BIT_COUNTERS */
2142 nr_table[i].cur_obytes -= nr_table[i].prev_obytes;
2143 nr_table[i].prev_obytes += nr_table[i].cur_obytes;
2144 nr_table[i].avg_obytes += nr_table[i].cur_obytes;
2145
2146
2147#ifdef IFNET_32_BIT_COUNTERS
2148 while (nr_table[i].cur_ierrors < nr_table[i].prev_ierrors)
2149 nr_table[i].cur_ierrors += 0x100000000LL;
2150#endif /* IFNET_32_BIT_COUNTERS */
2151 nr_table[i].cur_ierrors -= nr_table[i].prev_ierrors;
2152 nr_table[i].prev_ierrors += nr_table[i].cur_ierrors;
2153 nr_table[i].avg_ierrors += nr_table[i].cur_ierrors;
2154
2155#ifdef IFNET_32_BIT_COUNTERS
2156 while (nr_table[i].cur_oerrors < nr_table[i].prev_oerrors)
2157 nr_table[i].cur_oerrors += 0x100000000LL;
2158#endif /* IFNET_32_BIT_COUNTERS */
2159 nr_table[i].cur_oerrors -= nr_table[i].prev_oerrors;
2160 nr_table[i].prev_oerrors += nr_table[i].cur_oerrors;
2161 nr_table[i].avg_oerrors += nr_table[i].cur_oerrors;
2162
2163#ifdef IFNET_32_BIT_COUNTERS
2164 while (nr_table[i].cur_collisions < nr_table[i].prev_collisions)
2165 nr_table[i].cur_collisions += 0x100000000LL;
2166#endif /* IFNET_32_BIT_COUNTERS */
2167 nr_table[i].cur_collisions -= nr_table[i].prev_collisions;
2168 nr_table[i].prev_collisions += nr_table[i].cur_collisions;
2169 nr_table[i].avg_collisions += nr_table[i].cur_collisions;
2170
2171#ifdef IFNET_32_BIT_COUNTERS
2172 while (nr_table[i].cur_drops < nr_table[i].prev_drops)
2173 nr_table[i].cur_drops += 0x100000000LL;
2174#endif /* IFNET_32_BIT_COUNTERS */
2175 nr_table[i].cur_drops -= nr_table[i].prev_drops;
2176 nr_table[i].prev_drops += nr_table[i].cur_drops;
2177 nr_table[i].avg_drops += nr_table[i].cur_drops;
2178
2179
2180#ifdef IFNET_32_BIT_COUNTERS
2181 while (nr_table[i].cur_imcasts < nr_table[i].prev_imcasts)
2182 nr_table[i].cur_imcasts += 0x100000000LL;
2183#endif /* IFNET_32_BIT_COUNTERS */
2184 nr_table[i].cur_imcasts -= nr_table[i].prev_imcasts;
2185 nr_table[i].prev_imcasts += nr_table[i].cur_imcasts;
2186 nr_table[i].avg_imcasts += nr_table[i].cur_imcasts;
2187
2188#ifdef IFNET_32_BIT_COUNTERS
2189 while (nr_table[i].cur_omcasts < nr_table[i].prev_omcasts)
2190 nr_table[i].cur_omcasts += 0x100000000LL;
2191#endif /* IFNET_32_BIT_COUNTERS */
2192 nr_table[i].cur_omcasts -= nr_table[i].prev_omcasts;
2193 nr_table[i].prev_omcasts += nr_table[i].cur_omcasts;
2194 nr_table[i].avg_omcasts += nr_table[i].cur_omcasts;
2195 }
2196
2197
2198 if (!(flag_count > 1))
2199 fprintf(stdout, "\n");
2200
2201 if (network_mode & NET_DEV_MODE)
2202 {
2203 if (flag_count > 1)
2204 print_column_heading(SAR_NETSTATS, timebufptr, NET_DEV_MODE);
2205
2206 for (i=0; i < nr_count; i++)
2207 {
2208 if (!nr_table[i].valid)
2209 continue;
2210
2211 if (!(network_mode & NET_PPP_MODE))
2212 {
2213 if (!strncmp(nr_table[i].tname_unit, "ppp", 3))
2214 {
2215 continue; /* skip any ppp interfaces */
2216 }
2217 }
2218
2219 /* print the interface name */
2220 fprintf(stdout, "%s %-8.8s", timebufptr, nr_table[i].tname_unit);
2221
2222 fprintf (stdout, "%8llu ",
2223 (nr_table[i].cur_ipackets / avg_interval));
2224
2225 fprintf (stdout, "%10llu ",
2226 (nr_table[i].cur_ibytes / avg_interval));
2227
2228 fprintf (stdout, "%8llu ",
2229 (nr_table[i].cur_opackets / avg_interval));
2230
2231 fprintf (stdout, "%10llu\n",
2232 (nr_table[i].cur_obytes / avg_interval));
2233 }
2234 }
2235
2236
2237 if (network_mode & NET_EDEV_MODE)
2238 {
2239 if(flag_count > 1)
2240 {
2241 print_column_heading(SAR_NETSTATS, timebufptr, NET_EDEV_MODE);
2242 }
2243
2244 for (i=0; i < nr_count; i++)
2245 {
2246 if (!nr_table[i].valid)
2247 continue;
2248
2249 if (!(network_mode & NET_PPP_MODE))
2250 {
2251 if (!strncmp(nr_table[i].tname_unit, "ppp", 3))
2252 {
2253 continue; /* skip any ppp interfaces */
2254 }
2255 }
2256
2257 /* print the interface name */
2258 fprintf(stdout, "%s %-8.8s ", timebufptr, nr_table[i].tname_unit);
2259
2260 fprintf (stdout, "%7llu ",
2261 (nr_table[i].cur_ierrors / avg_interval));
2262
2263 fprintf (stdout, "%7llu ",
2264 (nr_table[i].cur_oerrors / avg_interval));
2265
2266 fprintf (stdout, "%5llu ",
2267 (nr_table[i].cur_collisions / avg_interval));
2268
2269 fprintf (stdout, " %5llu\n",
2270 (nr_table[i].cur_drops / avg_interval));
2271 }
2272 fflush(stdout);
2273 }
2274}
2275
2276static void
2277print_column_heading(int type, char *timebufptr, int mode)
2278{
2279 char *p;
2280
2281 p = timebufptr;
2282
2283 if (p == NULL)
2284 p = "Average:";
2285
2286 if (!(flag_count > 1))
2287 fprintf(stdout, "\n");
2288
2289 switch (type)
2290 {
2291 case SAR_CPU:
2292 fprintf (stdout, "\n%s %%usr %%sys %%idle\n", p);
2293 break;
2294
2295 case SAR_VMSTAT:
2296 if (mode == 0) /* gflag */
2297 fprintf(stdout, "\n%s pgout/s\n", p);
2298 else if (mode == 1) /* pflag */
2299 fprintf(stdout, "\n%s pgin/s pflt/s vflt/s\n", p);
2300 break;
2301 case SAR_DRIVESTATS:
2302 fprintf(stdout, "\n%s device r+w/s blks/s\n", p);
2303 break;
2304 case SAR_NETSTATS:
2305 if (mode == NET_DEV_MODE)
2306 {
2307 fprintf(stdout, "\n%s %-8.8s %8.8s %10.10s %8.8s %10.10s\n", p,
2308 " IFACE", "Ipkts/s", "Ibytes/s", "Opkts/s", "Obytes/s");
2309 }
2310 else if (mode == NET_EDEV_MODE)
2311 {
2312 fprintf(stdout, "\n%s %-8.8s %7.7s %7.7s %5s %s\n", p,
2313 " IFACE", "Ierrs/s", "Oerrs/s", "Coll/s", "Drop/s");
2314 }
2315 break;
2316 default:
2317 break;
2318 }
2319}
2320