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