2 * sar: report system activity
3 * (C) 1999-2015 by Sebastien GODARD (sysstat <at> orange.fr)
5 ***************************************************************************
6 * This program is free software; you can redistribute it and/or modify it *
7 * under the terms of the GNU General Public License as published by the *
8 * Free Software Foundation; either version 2 of the License, or (at your *
9 * option) any later version. *
11 * This program is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY *
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
16 * You should have received a copy of the GNU General Public License along *
17 * with this program; if not, write to the Free Software Foundation, Inc., *
18 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
19 ***************************************************************************
40 #define _(string) gettext(string)
42 #define _(string) (string)
45 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
46 char *sccsid(void) { return (SCCSID); }
48 /* Interval and count parameters */
49 long interval = -1, count = 0;
51 /* TRUE if a header line must be printed */
54 unsigned int flags = 0;
55 unsigned int dm_major; /* Device-mapper major number */
57 char timestamp[2][TIMESTAMP_LEN];
59 unsigned long avg_count = 0;
62 struct file_header file_hdr;
64 /* Current record header */
65 struct record_header record_hdr[3];
69 * This array must always be entirely filled (even with trailing zeros).
71 unsigned int id_seq[NR_ACT];
75 /* Contain the date specified by -s and -e options */
76 struct tstamp tm_start, tm_end;
78 char *args[MAX_ARGV_NR];
80 extern struct activity *act[];
82 struct sigaction int_act;
83 int sigint_caught = 0;
86 ***************************************************************************
87 * Print usage title message.
90 * @progname Name of sysstat command
91 ***************************************************************************
93 void print_usage_title(FILE *fp, char *progname)
95 fprintf(fp, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
100 ***************************************************************************
101 * Print usage and exit.
104 * @progname Name of sysstat command
105 ***************************************************************************
107 void usage(char *progname)
109 print_usage_title(stderr, progname);
110 fprintf(stderr, _("Options are:\n"
111 "[ -A ] [ -B ] [ -b ] [ -C ] [ -D ] [ -d ] [ -F [ MOUNT ] ] [ -H ] [ -h ]\n"
112 "[ -p ] [ -q ] [ -R ] [ -r [ ALL ] ] [ -S ] [ -t ] [ -u [ ALL ] ] [ -V ]\n"
113 "[ -v ] [ -W ] [ -w ] [ -y ] [ --sadc ]\n"
114 "[ -I { <int> [,...] | SUM | ALL | XALL } ] [ -P { <cpu> [,...] | ALL } ]\n"
115 "[ -m { <keyword> [,...] | ALL } ] [ -n { <keyword> [,...] | ALL } ]\n"
116 "[ -j { ID | LABEL | PATH | UUID | ... } ]\n"
117 "[ -f [ <filename> ] | -o [ <filename> ] | -[0-9]+ ]\n"
118 "[ -i <interval> ] [ -s [ <hh:mm[:ss]> ] ] [ -e [ <hh:mm[:ss]> ] ]\n"));
123 ***************************************************************************
124 * Display a short help message and exit.
127 * @progname Name of sysstat command
128 ***************************************************************************
130 void display_help(char *progname)
132 print_usage_title(stdout, progname);
133 printf(_("Main options and reports:\n"));
134 printf(_("\t-B\tPaging statistics\n"));
135 printf(_("\t-b\tI/O and transfer rate statistics\n"));
136 printf(_("\t-d\tBlock devices statistics\n"));
137 printf(_("\t-F [ MOUNT ]\n"));
138 printf(_("\t\tFilesystems statistics\n"));
139 printf(_("\t-H\tHugepages utilization statistics\n"));
140 printf(_("\t-I { <int> | SUM | ALL | XALL }\n"
141 "\t\tInterrupts statistics\n"));
142 printf(_("\t-m { <keyword> [,...] | ALL }\n"
143 "\t\tPower management statistics\n"
144 "\t\tKeywords are:\n"
145 "\t\tCPU\tCPU instantaneous clock frequency\n"
146 "\t\tFAN\tFans speed\n"
147 "\t\tFREQ\tCPU average clock frequency\n"
148 "\t\tIN\tVoltage inputs\n"
149 "\t\tTEMP\tDevices temperature\n"
150 "\t\tUSB\tUSB devices plugged into the system\n"));
151 printf(_("\t-n { <keyword> [,...] | ALL }\n"
152 "\t\tNetwork statistics\n"
153 "\t\tKeywords are:\n"
154 "\t\tDEV\tNetwork interfaces\n"
155 "\t\tEDEV\tNetwork interfaces (errors)\n"
156 "\t\tNFS\tNFS client\n"
157 "\t\tNFSD\tNFS server\n"
158 "\t\tSOCK\tSockets\t(v4)\n"
159 "\t\tIP\tIP traffic\t(v4)\n"
160 "\t\tEIP\tIP traffic\t(v4) (errors)\n"
161 "\t\tICMP\tICMP traffic\t(v4)\n"
162 "\t\tEICMP\tICMP traffic\t(v4) (errors)\n"
163 "\t\tTCP\tTCP traffic\t(v4)\n"
164 "\t\tETCP\tTCP traffic\t(v4) (errors)\n"
165 "\t\tUDP\tUDP traffic\t(v4)\n"
166 "\t\tSOCK6\tSockets\t(v6)\n"
167 "\t\tIP6\tIP traffic\t(v6)\n"
168 "\t\tEIP6\tIP traffic\t(v6) (errors)\n"
169 "\t\tICMP6\tICMP traffic\t(v6)\n"
170 "\t\tEICMP6\tICMP traffic\t(v6) (errors)\n"
171 "\t\tUDP6\tUDP traffic\t(v6)\n"
172 "\t\tFC\tFibre channel HBAs\n"));
173 printf(_("\t-q\tQueue length and load average statistics\n"));
174 printf(_("\t-R\tMemory statistics\n"));
175 printf(_("\t-r [ ALL ]\n"
176 "\t\tMemory utilization statistics\n"));
177 printf(_("\t-S\tSwap space utilization statistics\n"));
178 printf(_("\t-u [ ALL ]\n"
179 "\t\tCPU utilization statistics\n"));
180 printf(_("\t-v\tKernel tables statistics\n"));
181 printf(_("\t-W\tSwapping statistics\n"));
182 printf(_("\t-w\tTask creation and system switching statistics\n"));
183 printf(_("\t-y\tTTY devices statistics\n"));
188 ***************************************************************************
189 * Give a hint to the user about where is located the data collector.
190 ***************************************************************************
192 void which_sadc(void)
196 if (stat(SADC_PATH, &buf) < 0) {
197 printf(_("Data collector will be sought in PATH\n"));
200 printf(_("Data collector found: %s\n"), SADC_PATH);
206 ***************************************************************************
207 * SIGINT signal handler.
210 * @sig Signal number.
211 ***************************************************************************
213 void int_handler(int sig)
216 printf("\n"); /* Skip "^C" displayed on screen */
221 ***************************************************************************
222 * Init some structures.
223 ***************************************************************************
225 void init_structures(void)
229 for (i = 0; i < 3; i++)
230 memset(&record_hdr[i], 0, RECORD_HEADER_SIZE);
234 ***************************************************************************
235 * Allocate memory for sadc args.
238 * @i Argument number.
239 * @ltemp Argument value.
240 ***************************************************************************
242 void salloc(int i, char *ltemp)
244 if ((args[i] = (char *) malloc(strlen(ltemp) + 1)) == NULL) {
248 strcpy(args[i], ltemp);
252 ***************************************************************************
253 * Display an error message. Happens when the data collector doesn't send
255 ***************************************************************************
257 void print_read_error(void)
259 fprintf(stderr, _("End of data collecting unexpected\n"));
264 ***************************************************************************
265 * Check that every selected activity actually belongs to the sequence list.
266 * If not, then the activity should be unselected since it will not be sent
267 * by sadc. An activity can be not sent if its number of items is null.
270 * @act_nr Size of sequence list.
271 ***************************************************************************
273 void reverse_check_act(unsigned int act_nr)
277 for (i = 0; i < NR_ACT; i++) {
279 if (IS_SELECTED(act[i]->options)) {
281 for (j = 0; j < act_nr; j++) {
282 if (id_seq[j] == act[i]->id)
286 act[i]->options &= ~AO_SELECTED;
292 ***************************************************************************
293 * Determine if a stat header line has to be displayed.
296 * TRUE if a header line has to be displayed.
297 ***************************************************************************
299 int check_line_hdr(void)
303 /* Get number of options entered on the command line */
304 if (get_activity_nr(act, AO_SELECTED, COUNT_OUTPUTS) > 1)
307 for (i = 0; i < NR_ACT; i++) {
308 if (IS_SELECTED(act[i]->options)) {
309 /* Special processing for activities using a bitmap */
310 if (act[i]->bitmap) {
311 if (count_bits(act[i]->bitmap->b_array,
312 BITMAP_SIZE(act[i]->bitmap->b_size)) > 1) {
316 else if (act[i]->nr > 1) {
319 /* Stop now since we have only one selected activity */
328 ***************************************************************************
329 * Print statistics average.
332 * @curr Index in array for current sample statistics.
333 * @read_from_file Set to TRUE if stats are read from a system activity
335 * @act_id Activity that can be displayed, or ~0 for all.
336 * Remember that when reading stats from a file, only
337 * one activity can be displayed at a time.
338 ***************************************************************************
340 void write_stats_avg(int curr, int read_from_file, unsigned int act_id)
343 unsigned long long itv, g_itv;
344 static __nr_t cpu_nr = -1;
347 cpu_nr = act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr;
349 /* Interval value in jiffies */
350 g_itv = get_interval(record_hdr[2].uptime, record_hdr[curr].uptime);
353 itv = get_interval(record_hdr[2].uptime0, record_hdr[curr].uptime0);
357 strncpy(timestamp[curr], _("Average:"), TIMESTAMP_LEN);
358 timestamp[curr][TIMESTAMP_LEN - 1] = '\0';
359 strcpy(timestamp[!curr], timestamp[curr]);
362 TEST_STDOUT(STDOUT_FILENO);
364 for (i = 0; i < NR_ACT; i++) {
366 if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
369 if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
370 /* Display current average activity statistics */
371 (*act[i]->f_print_avg)(act[i], 2, curr,
372 NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv);
376 if (read_from_file) {
378 * Reset number of lines printed only if we read stats
379 * from a system activity file.
386 ***************************************************************************
387 * Print system statistics.
390 * @curr Index in array for current sample statistics.
391 * @read_from_file Set to TRUE if stats are read from a system activity
393 * @use_tm_start Set to TRUE if option -s has been used.
394 * @use_tm_end Set to TRUE if option -e has been used.
395 * @reset Set to TRUE if last_uptime variable should be
396 * reinitialized (used in next_slice() function).
397 * @act_id Activity that can be displayed or ~0 for all.
398 * Remember that when reading stats from a file, only
399 * one activity can be displayed at a time.
400 * @reset_cd TRUE if static cross_day variable should be reset
404 * @cnt Number of remaining lines to display.
407 * 1 if stats have been successfully displayed, and 0 otherwise.
408 ***************************************************************************
410 int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start,
411 int use_tm_end, int reset, unsigned int act_id, int reset_cd)
414 unsigned long long itv, g_itv;
415 static int cross_day = 0;
416 static __nr_t cpu_nr = -1;
419 cpu_nr = act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr;
423 * cross_day is a static variable that is set to 1 when the first
424 * record of stats from a new day is read from a unique data file
425 * (in the case where the file contains data from two consecutive
426 * days). When set to 1, every following records timestamp will
427 * have its hour value increased by 24.
428 * Yet when a new activity (being read from the file) is going to
429 * be displayed, we start reading the file from the beginning
430 * again, and so cross_day should be reset in this case.
436 if (read_from_file) {
437 if (!next_slice(record_hdr[2].uptime0, record_hdr[curr].uptime0,
439 /* Not close enough to desired interval */
443 /* Get then set previous timestamp */
444 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME, &record_hdr[!curr],
447 set_record_timestamp_string(S_F_PREFD_TIME_OUTPUT, &record_hdr[!curr],
448 NULL, timestamp[!curr], 16, &rectime);
450 /* Get then set current timestamp */
451 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME, &record_hdr[curr],
454 set_record_timestamp_string(S_F_PREFD_TIME_OUTPUT, &record_hdr[curr],
455 NULL, timestamp[curr], 16, &rectime);
457 /* Check if we are beginning a new day */
458 if (use_tm_start && record_hdr[!curr].ust_time &&
459 (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) &&
460 (record_hdr[curr].hour < record_hdr[!curr].hour)) {
466 * This is necessary if we want to properly handle something like:
467 * sar -s time_start -e time_end with
468 * time_start(day D) > time_end(day D+1)
470 rectime.tm_hour +=24;
474 if (use_tm_start && (datecmp(&rectime, &tm_start) < 0))
475 /* it's too soon... */
478 /* Get interval values */
479 get_itv_value(&record_hdr[curr], &record_hdr[!curr],
480 cpu_nr, &itv, &g_itv);
483 if (use_tm_end && (datecmp(&rectime, &tm_end) > 0)) {
484 /* It's too late... */
492 TEST_STDOUT(STDOUT_FILENO);
494 for (i = 0; i < NR_ACT; i++) {
496 if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
499 if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
500 /* Display current activity statistics */
501 (*act[i]->f_print)(act[i], !curr, curr,
502 NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv);
510 ***************************************************************************
511 * Display stats since system startup.
514 * @curr Index in array for current sample statistics.
515 ***************************************************************************
517 void write_stats_startup(int curr)
521 /* Set to 0 previous structures corresponding to boot time */
522 memset(&record_hdr[!curr], 0, RECORD_HEADER_SIZE);
523 record_hdr[!curr].record_type = R_STATS;
524 record_hdr[!curr].hour = record_hdr[curr].hour;
525 record_hdr[!curr].minute = record_hdr[curr].minute;
526 record_hdr[!curr].second = record_hdr[curr].second;
527 record_hdr[!curr].ust_time = record_hdr[curr].ust_time;
529 for (i = 0; i < NR_ACT; i++) {
530 if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) {
531 memset(act[i]->buf[!curr], 0,
532 (size_t) act[i]->msize * (size_t) act[i]->nr * (size_t) act[i]->nr2);
536 flags |= S_F_SINCE_BOOT;
539 write_stats(curr, USE_SADC, &count, NO_TM_START, NO_TM_END, NO_RESET,
540 ALL_ACTIVITIES, TRUE);
546 ***************************************************************************
547 * Read data sent by the data collector.
550 * @size Number of bytes of data to read.
553 * @buffer Buffer where data will be saved.
556 * 1 if end of file has been reached, 0 otherwise.
557 ***************************************************************************
559 int sa_read(void *buffer, int size)
565 if ((n = read(STDIN_FILENO, buffer, size)) < 0) {
574 buffer = (char *) buffer + n;
581 ***************************************************************************
582 * Print a Linux restart message (contents of a RESTART record) or a
583 * comment (contents of a COMMENT record).
586 * @curr Index in array for current sample statistics.
587 * @use_tm_start Set to TRUE if option -s has been used.
588 * @use_tm_end Set to TRUE if option -e has been used.
589 * @rtype Record type to display.
590 * @ifd Input file descriptor.
591 * @file Name of file being read.
592 * @file_magic file_magic structure filled with file magic header
596 * 1 if the record has been successfully displayed, and 0 otherwise.
597 ***************************************************************************
599 int sar_print_special(int curr, int use_tm_start, int use_tm_end, int rtype,
600 int ifd, char *file, struct file_magic *file_magic)
602 char cur_time[26], restart[64];
604 unsigned int new_cpu_nr;
606 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME, &record_hdr[curr],
609 set_record_timestamp_string(S_F_PREFD_TIME_OUTPUT, &record_hdr[curr],
610 NULL, cur_time, 26, &rectime);
612 /* The record must be in the interval specified by -s/-e options */
613 if ((use_tm_start && (datecmp(&rectime, &tm_start) < 0)) ||
614 (use_tm_end && (datecmp(&rectime, &tm_end) > 0))) {
618 if (rtype == R_RESTART) {
619 /* Don't forget to read the volatile activities structures */
620 new_cpu_nr = read_vol_act_structures(ifd, act, file, file_magic,
621 file_hdr.sa_vol_act_nr);
624 printf("\n%-11s", cur_time);
625 sprintf(restart, " LINUX RESTART\t(%d CPU)\n",
626 new_cpu_nr > 1 ? new_cpu_nr - 1 : 1);
627 cprintf_s(IS_RESTART, "%s", restart);
631 else if (rtype == R_COMMENT) {
632 char file_comment[MAX_COMMENT_LEN];
634 /* Don't forget to read comment record even if it won't be displayed... */
635 replace_nonprintable_char(ifd, file_comment);
637 if (dp && DISPLAY_COMMENT(flags)) {
638 printf("%-11s", cur_time);
639 cprintf_s(IS_COMMENT, " COM %s\n", file_comment);
648 ***************************************************************************
649 * Read the various statistics sent by the data collector (sadc).
652 * @curr Index in array for current sample statistics.
653 ***************************************************************************
655 void read_sadc_stat_bunch(int curr)
659 /* Read record header (type is always R_STATS since it is read from sadc) */
660 if (sa_read(&record_hdr[curr], RECORD_HEADER_SIZE)) {
662 * SIGINT (sent by sadc) is likely to be received
663 * while we are stuck in sa_read().
664 * If this happens then no data have to be read.
672 for (i = 0; i < NR_ACT; i++) {
676 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
678 if (sa_read(act[p]->buf[curr], act[p]->fsize * act[p]->nr * act[p]->nr2)) {
685 ***************************************************************************
686 * Read stats for current activity from file and display them.
689 * @ifd Input file descriptor.
690 * @fpos Position in file where reading must start.
691 * @curr Index in array for current sample statistics.
692 * @rows Number of rows of screen.
693 * @act_id Activity to display.
694 * @file_actlst List of activities in file.
695 * @file Name of file being read.
696 * @file_magic file_magic structure filled with file magic header data.
699 * @curr Index in array for next sample statistics.
700 * @cnt Number of remaining lines of stats to write.
701 * @eosaf Set to TRUE if EOF (end of file) has been reached.
702 * @reset Set to TRUE if last_uptime variable should be
703 * reinitialized (used in next_slice() function).
704 ***************************************************************************
706 void handle_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf,
707 int rows, unsigned int act_id, int *reset,
708 struct file_activity *file_actlst, char *file,
709 struct file_magic *file_magic)
712 unsigned long lines = 0;
714 int davg = 0, next, inc;
716 if (lseek(ifd, fpos, SEEK_SET) < fpos) {
722 * Restore the first stats collected.
723 * Used to compute the rate displayed on the first line.
725 copy_structures(act, id_seq, record_hdr, !*curr, 2);
729 /* Assess number of lines printed */
730 p = get_activity_position(act, act_id, EXIT_IF_NOT_FOUND);
731 if (act[p]->bitmap) {
732 inc = count_bits(act[p]->bitmap->b_array,
733 BITMAP_SIZE(act[p]->bitmap->b_size));
742 /* Display count lines of stats */
743 *eosaf = sa_fread(ifd, &record_hdr[*curr],
744 RECORD_HEADER_SIZE, SOFT_SIZE);
745 rtype = record_hdr[*curr].record_type;
747 if (!*eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
748 /* Read the extra fields since it's not a special record */
749 read_file_stat_bunch(act, *curr, ifd, file_hdr.sa_act_nr, file_actlst);
752 if ((lines >= rows) || !lines) {
759 if (!*eosaf && (rtype != R_RESTART)) {
761 if (rtype == R_COMMENT) {
762 /* Display comment */
763 next = sar_print_special(*curr, tm_start.use, tm_end.use,
764 R_COMMENT, ifd, file, file_magic);
766 /* A line of comment was actually displayed */
772 /* next is set to 1 when we were close enough to desired interval */
773 next = write_stats(*curr, USE_SA_FILE, cnt, tm_start.use, tm_end.use,
774 *reset, act_id, reset_cd);
776 if (next && (*cnt > 0)) {
787 while (*cnt && !*eosaf && (rtype != R_RESTART));
790 write_stats_avg(!*curr, USE_SA_FILE, act_id);
797 ***************************************************************************
798 * Read header data sent by sadc.
799 ***************************************************************************
801 void read_header_data(void)
803 struct file_magic file_magic;
804 struct file_activity file_act;
808 /* Read magic header */
809 rc = sa_read(&file_magic, FILE_MAGIC_SIZE);
811 sprintf(version, "%d.%d.%d.%d",
812 file_magic.sysstat_version,
813 file_magic.sysstat_patchlevel,
814 file_magic.sysstat_sublevel,
815 file_magic.sysstat_extraversion);
816 if (!file_magic.sysstat_extraversion) {
817 version[strlen(version) - 2] = '\0';
820 if (rc || (file_magic.sysstat_magic != SYSSTAT_MAGIC) ||
821 (file_magic.format_magic != FORMAT_MAGIC) ||
822 strcmp(version, VERSION)) {
824 /* sar and sadc commands are not consistent */
825 if (!rc && (file_magic.sysstat_magic == SYSSTAT_MAGIC)) {
827 _("Using a wrong data collector from a different sysstat version\n"));
835 * No need to take into account file_magic.header_size. We are sure that
836 * sadc and sar are from the same version (we have checked FORMAT_MAGIC
837 * but also VERSION above) and thus the size of file_header is FILE_HEADER_SIZE.
839 if (sa_read(&file_hdr, FILE_HEADER_SIZE)) {
843 if (file_hdr.sa_act_nr > NR_ACT)
846 /* Read activity list */
847 for (i = 0; i < file_hdr.sa_act_nr; i++) {
849 if (sa_read(&file_act, FILE_ACTIVITY_SIZE)) {
853 p = get_activity_position(act, file_act.id, RESUME_IF_NOT_FOUND);
855 if ((p < 0) || (act[p]->fsize != file_act.size)
856 || (file_act.nr <= 0)
857 || (file_act.nr2 <= 0)
858 || (act[p]->magic != file_act.magic))
859 /* Remember that we are reading data from sadc and not from a file... */
862 id_seq[i] = file_act.id; /* We necessarily have "i < NR_ACT" */
863 act[p]->nr = file_act.nr;
864 act[p]->nr2 = file_act.nr2;
871 /* Check that all selected activties are actually sent by sadc */
872 reverse_check_act(file_hdr.sa_act_nr);
878 /* Strange data sent by sadc...! */
879 fprintf(stderr, _("Inconsistent input data\n"));
885 ***************************************************************************
886 * Read statistics from a system activity data file.
889 * @from_file Input file name.
890 ***************************************************************************
892 void read_stats_from_file(char from_file[])
894 struct file_magic file_magic;
895 struct file_activity *file_actlst = NULL;
898 int rows, eosaf = TRUE, reset = FALSE;
902 /* Get window size */
903 rows = get_win_height();
905 /* Read file headers and activity list */
906 check_file_actlst(&ifd, from_file, act, &file_magic, &file_hdr,
907 &file_actlst, id_seq, FALSE);
909 /* Perform required allocations */
910 allocate_structures(act);
912 /* Print report header */
913 print_report_hdr(flags, &rectime, &file_hdr,
914 act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr);
916 /* Read system statistics from file */
919 * If this record is a special (RESTART or COMMENT) one, print it and
920 * (try to) get another one.
923 if (sa_fread(ifd, &record_hdr[0], RECORD_HEADER_SIZE, SOFT_SIZE))
924 /* End of sa data file */
927 rtype = record_hdr[0].record_type;
928 if ((rtype == R_RESTART) || (rtype == R_COMMENT)) {
929 sar_print_special(0, tm_start.use, tm_end.use, rtype,
930 ifd, from_file, &file_magic);
934 * OK: Previous record was not a special one.
935 * So read now the extra fields.
937 read_file_stat_bunch(act, 0, ifd, file_hdr.sa_act_nr,
939 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME,
943 * An error was detected.
944 * The timestamp hasn't been updated.
949 while ((rtype == R_RESTART) || (rtype == R_COMMENT) ||
950 (tm_start.use && (datecmp(&rectime, &tm_start) < 0)) ||
951 (tm_end.use && (datecmp(&rectime, &tm_end) >=0)));
953 /* Save the first stats collected. Will be used to compute the average */
954 copy_structures(act, id_seq, record_hdr, 2, 0);
956 reset = TRUE; /* Set flag to reset last_uptime variable */
958 /* Save current file position */
959 if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) {
965 * Read and write stats located between two possible Linux restarts.
966 * Activities that should be displayed are saved in id_seq[] array.
968 for (i = 0; i < NR_ACT; i++) {
973 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
974 if (!IS_SELECTED(act[p]->options))
977 if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) {
978 handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, rows,
979 act[p]->id, &reset, file_actlst,
980 from_file, &file_magic);
983 unsigned int optf, msk;
985 optf = act[p]->opt_flags;
987 for (msk = 1; msk < 0x100; msk <<= 1) {
988 if ((act[p]->opt_flags & 0xff) & msk) {
989 act[p]->opt_flags &= (0xffffff00 + msk);
991 handle_curr_act_stats(ifd, fpos, &curr, &cnt,
992 &eosaf, rows, act[p]->id,
994 from_file, &file_magic);
995 act[p]->opt_flags = optf;
1002 /* Go to next Linux restart, if possible */
1004 eosaf = sa_fread(ifd, &record_hdr[curr], RECORD_HEADER_SIZE,
1006 rtype = record_hdr[curr].record_type;
1007 if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
1008 read_file_stat_bunch(act, curr, ifd, file_hdr.sa_act_nr,
1011 else if (!eosaf && (rtype == R_COMMENT)) {
1012 /* This was a COMMENT record: print it */
1013 sar_print_special(curr, tm_start.use, tm_end.use, R_COMMENT,
1014 ifd, from_file, &file_magic);
1017 while (!eosaf && (rtype != R_RESTART));
1020 /* The last record we read was a RESTART one: Print it */
1021 if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) {
1022 sar_print_special(curr, tm_start.use, tm_end.use, R_RESTART,
1023 ifd, from_file, &file_magic);
1034 ***************************************************************************
1035 * Read statistics sent by sadc, the data collector.
1036 ***************************************************************************
1038 void read_stats(void)
1041 unsigned long lines;
1045 /* Don't buffer data if redirected to a pipe... */
1046 setbuf(stdout, NULL);
1048 /* Read stats header */
1051 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1052 fprintf(stderr, _("Requested activities not available\n"));
1056 /* Determine if a stat line header has to be displayed */
1057 dis_hdr = check_line_hdr();
1059 lines = rows = get_win_height();
1061 /* Perform required allocations */
1062 allocate_structures(act);
1064 /* Print report header */
1065 print_report_hdr(flags, &rectime, &file_hdr,
1066 act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr);
1068 /* Read system statistics sent by the data collector */
1069 read_sadc_stat_bunch(0);
1072 /* Display stats since boot time and exit */
1073 write_stats_startup(0);
1076 /* Save the first stats collected. Will be used to compute the average */
1077 copy_structures(act, id_seq, record_hdr, 2, 0);
1079 /* Set a handler for SIGINT */
1080 memset(&int_act, 0, sizeof(int_act));
1081 int_act.sa_handler = int_handler;
1082 int_act.sa_flags = SA_RESTART;
1083 sigaction(SIGINT, &int_act, NULL);
1089 read_sadc_stat_bunch(curr);
1090 if (sigint_caught) {
1092 * SIGINT signal caught (it is sent by sadc).
1093 * => Display average stats.
1095 curr ^= 1; /* No data retrieved from last read */
1107 write_stats(curr, USE_SADC, &count, NO_TM_START, tm_end.use,
1108 NO_RESET, ALL_ACTIVITIES, TRUE);
1110 if (record_hdr[curr].record_type == R_LAST_STATS) {
1111 /* File rotation is happening: Re-read header data sent by sadc */
1113 allocate_structures(act);
1126 * Print statistics average.
1127 * At least one line of stats must have been displayed for this.
1128 * (There may be no lines at all if we press Ctrl/C immediately).
1132 write_stats_avg(curr, USE_SADC, ALL_ACTIVITIES);
1137 ***************************************************************************
1138 * Main entry to the sar program.
1139 ***************************************************************************
1141 int main(int argc, char **argv)
1143 int i, rc, opt = 1, args_idx = 2;
1146 char from_file[MAX_FILE_LEN], to_file[MAX_FILE_LEN];
1152 /* Compute page shift in kB */
1155 from_file[0] = to_file[0] = '\0';
1158 /* Init National Language Support */
1162 /* Init color strings */
1165 tm_start.use = tm_end.use = FALSE;
1167 /* Allocate and init activity bitmaps */
1168 allocate_bitmaps(act);
1172 /* Process options */
1173 while (opt < argc) {
1175 if (!strcmp(argv[opt], "--sadc")) {
1180 else if (!strcmp(argv[opt], "-I")) {
1182 /* Parse -I option */
1183 if (parse_sar_I_opt(argv, &opt, act)) {
1192 else if (!strcmp(argv[opt], "-D")) {
1193 /* Option to tell sar to write to saYYYYMMDD data files */
1194 flags |= S_F_SA_YYYYMMDD;
1198 else if (!strcmp(argv[opt], "-P")) {
1199 /* Parse -P option */
1200 if (parse_sa_P_opt(argv, &opt, &flags, act)) {
1205 else if (!strcmp(argv[opt], "-o")) {
1207 /* Output file already specified */
1210 /* Save stats to a file */
1211 if ((argv[++opt]) && strncmp(argv[opt], "-", 1) &&
1212 (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
1213 strncpy(to_file, argv[opt++], MAX_FILE_LEN);
1214 to_file[MAX_FILE_LEN - 1] = '\0';
1217 strcpy(to_file, "-");
1221 else if (!strcmp(argv[opt], "-f")) {
1222 if (from_file[0] || day_offset) {
1223 /* Input file already specified */
1226 /* Read stats from a file */
1227 if ((argv[++opt]) && strncmp(argv[opt], "-", 1) &&
1228 (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
1229 strncpy(from_file, argv[opt++], MAX_FILE_LEN);
1230 from_file[MAX_FILE_LEN - 1] = '\0';
1231 /* Check if this is an alternate directory for sa files */
1232 check_alt_sa_dir(from_file, day_offset, -1);
1235 set_default_file(from_file, day_offset, -1);
1239 else if (!strcmp(argv[opt], "-s")) {
1240 /* Get time start */
1241 if (parse_timestamp(argv, &opt, &tm_start, DEF_TMSTART)) {
1246 else if (!strcmp(argv[opt], "-e")) {
1248 if (parse_timestamp(argv, &opt, &tm_end, DEF_TMEND)) {
1253 else if (!strcmp(argv[opt], "-h")) {
1254 /* Display help message */
1255 display_help(argv[0]);
1258 else if (!strcmp(argv[opt], "-i")) {
1259 if (!argv[++opt] || (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
1262 interval = atol(argv[opt++]);
1266 flags |= S_F_INTERVAL_SET;
1269 else if (!strcmp(argv[opt], "-m")) {
1271 /* Parse option -m */
1272 if (parse_sar_m_opt(argv, &opt, act)) {
1281 else if (!strcmp(argv[opt], "-n")) {
1283 /* Parse option -n */
1284 if (parse_sar_n_opt(argv, &opt, act)) {
1293 else if ((strlen(argv[opt]) > 1) &&
1294 (strlen(argv[opt]) < 4) &&
1295 !strncmp(argv[opt], "-", 1) &&
1296 (strspn(argv[opt] + 1, DIGITS) == (strlen(argv[opt]) - 1))) {
1297 if (from_file[0] || day_offset) {
1298 /* Input file already specified */
1301 day_offset = atoi(argv[opt++] + 1);
1304 else if (!strncmp(argv[opt], "-", 1)) {
1305 /* Other options not previously tested */
1306 if ((rc = parse_sar_opt(argv, &opt, act, &flags, C_SAR)) != 0) {
1315 else if (interval < 0) {
1317 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
1320 interval = atol(argv[opt++]);
1327 /* Get count value */
1328 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
1333 /* Count parameter already set */
1336 count = atol(argv[opt++]);
1343 /* 'sar' is equivalent to 'sar -f' */
1345 ((interval < 0) && !from_file[0] && !to_file[0])) {
1346 set_default_file(from_file, day_offset, -1);
1349 if (tm_start.use && tm_end.use && (tm_end.tm_hour < tm_start.tm_hour)) {
1350 tm_end.tm_hour += 24;
1354 * Check option dependencies.
1356 /* You read from a file OR you write to it... */
1357 if (from_file[0] && to_file[0]) {
1358 fprintf(stderr, _("-f and -o options are mutually exclusive\n"));
1361 /* Use time start or option -i only when reading stats from a file */
1362 if ((tm_start.use || INTERVAL_SET(flags)) && !from_file[0]) {
1364 _("Not reading from a system activity file (use -f option)\n"));
1367 /* Don't print stats since boot time if -o or -f options are used */
1368 if (!interval && (from_file[0] || to_file[0])) {
1372 /* Cannot enter a day shift with -o option */
1373 if (to_file[0] && day_offset) {
1377 if (USE_PRETTY_OPTION(flags)) {
1378 dm_major = get_devmap_major();
1383 * count parameter not set: Display all the contents of the file
1384 * or generate a report continuously.
1389 /* Default is CPU activity... */
1390 select_default_activity(act);
1392 /* Reading stats from file: */
1398 /* Read stats from file */
1399 read_stats_from_file(from_file);
1401 /* Free stuctures and activity bitmaps */
1403 free_structures(act);
1408 /* Reading stats from sadc: */
1410 /* Create anonymous pipe */
1411 if (pipe(fd) == -1) {
1424 if (dup2(fd[1], STDOUT_FILENO) < 0) {
1431 * Prepare options for sadc.
1436 /* Interval value */
1440 else if (!interval) {
1444 sprintf(ltemp, "%ld", interval);
1450 sprintf(ltemp, "%ld", count + 1);
1451 salloc(args_idx++, ltemp);
1454 /* Flags to be passed to sadc */
1455 salloc(args_idx++, "-z");
1457 /* Writing data to a file (option -o) */
1459 /* Set option -D if entered */
1460 if (USE_SA_YYYYMMDD(flags)) {
1461 salloc(args_idx++, "-D");
1463 /* Collect all possible activities (option -S XALL for sadc) */
1464 salloc(args_idx++, "-S");
1465 salloc(args_idx++, K_XALL);
1467 salloc(args_idx++, to_file);
1471 * If option -o hasn't been used, then tell sadc
1472 * to collect only activities that will be displayed.
1476 for (i = 0; i < NR_ACT; i++) {
1477 if (IS_SELECTED(act[i]->options)) {
1478 act_id |= act[i]->group;
1483 snprintf(ltemp, 19, "%d", act_id);
1485 salloc(args_idx++, "-S");
1486 salloc(args_idx++, ltemp);
1490 /* Last arg is NULL */
1491 args[args_idx] = NULL;
1493 /* Call now the data collector */
1494 execv(SADC_PATH, args);
1497 * Note: Don't use execl/execlp since we don't have a fixed number of
1498 * args to give to sadc.
1500 fprintf(stderr, _("Cannot find the data collector (%s)\n"), SADC);
1505 default: /* Parent */
1506 if (dup2(fd[0], STDIN_FILENO) < 0) {
1512 /* Get now the statistics */
1518 /* Free structures and activity bitmaps */
1520 free_structures(act);