2 * sar: report system activity
3 * (C) 1999-2021 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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA *
19 ***************************************************************************
38 #define _(string) gettext(string)
40 #define _(string) (string)
44 #define SCCSID "@(#)sysstat-" VERSION ": " __FILE__ " compiled " __DATE__ " " __TIME__
45 char *sccsid(void) { return (SCCSID); }
49 extern time_t __unix_time;
53 /* Interval and count parameters */
54 long interval = -1, count = 0;
56 /* TRUE if a header line must be printed */
58 /* TRUE if data read from file don't match current machine's endianness */
59 int endian_mismatch = FALSE;
60 /* TRUE if file's data come from a 64 bit machine */
62 /* Number of decimal places */
67 char timestamp[2][TIMESTAMP_LEN];
68 extern unsigned int rec_types_nr[];
70 unsigned long avg_count = 0;
73 struct file_header file_hdr;
75 /* Current record header */
76 struct record_header record_hdr[3];
80 * This array must always be entirely filled (even with trailing zeros).
82 unsigned int id_seq[NR_ACT];
86 /* Contain the date specified by -s and -e options */
87 struct tstamp tm_start, tm_end;
89 char *args[MAX_ARGV_NR];
91 extern struct activity *act[];
92 extern struct report_format sar_fmt;
94 struct sigaction int_act;
95 int sigint_caught = 0;
98 ***************************************************************************
99 * Print usage title message.
102 * @progname Name of sysstat command
103 ***************************************************************************
105 void print_usage_title(FILE *fp, char *progname)
107 fprintf(fp, _("Usage: %s [ options ] [ <interval> [ <count> ] ]\n"),
112 ***************************************************************************
113 * Print usage and exit.
116 * @progname Name of sysstat command
117 ***************************************************************************
119 void usage(char *progname)
121 print_usage_title(stderr, progname);
122 fprintf(stderr, _("Options are:\n"
123 "[ -A ] [ -B ] [ -b ] [ -C ] [ -D ] [ -d ] [ -F [ MOUNT ] ] [ -H ] [ -h ]\n"
124 "[ -p ] [ -r [ ALL ] ] [ -S ] [ -t ] [ -u [ ALL ] ] [ -V ]\n"
125 "[ -v ] [ -W ] [ -w ] [ -y ] [ -z ]\n"
126 "[ -I { <int_list> | SUM | ALL } ] [ -P { <cpu_list> | ALL } ]\n"
127 "[ -m { <keyword> [,...] | ALL } ] [ -n { <keyword> [,...] | ALL } ]\n"
128 "[ -q [ <keyword> [,...] | ALL ] ]\n"
129 "[ --dev=<dev_list> ] [ --fs=<fs_list> ] [ --iface=<iface_list> ]\n"
130 "[ --dec={ 0 | 1 | 2 } ] [ --help ] [ --human ] [ --pretty ] [ --sadc ]\n"
131 "[ -j { SID | ID | LABEL | PATH | UUID | ... } ]\n"
132 "[ -f [ <filename> ] | -o [ <filename> ] | -[0-9]+ ]\n"
133 "[ -i <interval> ] [ -s [ <hh:mm[:ss]> ] ] [ -e [ <hh:mm[:ss]> ] ]\n"));
138 ***************************************************************************
139 * Display a short help message and exit.
142 * @progname Name of sysstat command
143 ***************************************************************************
145 void display_help(char *progname)
147 print_usage_title(stdout, progname);
148 printf(_("Main options and reports (report name between square brackets):\n"));
149 printf(_("\t-B\tPaging statistics [A_PAGE]\n"));
150 printf(_("\t-b\tI/O and transfer rate statistics [A_IO]\n"));
151 printf(_("\t-d\tBlock devices statistics [A_DISK]\n"));
152 printf(_("\t-F [ MOUNT ]\n"));
153 printf(_("\t\tFilesystems statistics [A_FS]\n"));
154 printf(_("\t-H\tHugepages utilization statistics [A_HUGE]\n"));
155 printf(_("\t-I { <int_list> | SUM | ALL }\n"
156 "\t\tInterrupts statistics [A_IRQ]\n"));
157 printf(_("\t-m { <keyword> [,...] | ALL }\n"
158 "\t\tPower management statistics [A_PWR_...]\n"
159 "\t\tKeywords are:\n"
160 "\t\tCPU\tCPU instantaneous clock frequency\n"
161 "\t\tFAN\tFans speed\n"
162 "\t\tFREQ\tCPU average clock frequency\n"
163 "\t\tIN\tVoltage inputs\n"
164 "\t\tTEMP\tDevices temperature\n"
165 "\t\tUSB\tUSB devices plugged into the system\n"));
166 printf(_("\t-n { <keyword> [,...] | ALL }\n"
167 "\t\tNetwork statistics [A_NET_...]\n"
168 "\t\tKeywords are:\n"
169 "\t\tDEV\tNetwork interfaces\n"
170 "\t\tEDEV\tNetwork interfaces (errors)\n"
171 "\t\tNFS\tNFS client\n"
172 "\t\tNFSD\tNFS server\n"
173 "\t\tSOCK\tSockets\t(v4)\n"
174 "\t\tIP\tIP traffic\t(v4)\n"
175 "\t\tEIP\tIP traffic\t(v4) (errors)\n"
176 "\t\tICMP\tICMP traffic\t(v4)\n"
177 "\t\tEICMP\tICMP traffic\t(v4) (errors)\n"
178 "\t\tTCP\tTCP traffic\t(v4)\n"
179 "\t\tETCP\tTCP traffic\t(v4) (errors)\n"
180 "\t\tUDP\tUDP traffic\t(v4)\n"
181 "\t\tSOCK6\tSockets\t(v6)\n"
182 "\t\tIP6\tIP traffic\t(v6)\n"
183 "\t\tEIP6\tIP traffic\t(v6) (errors)\n"
184 "\t\tICMP6\tICMP traffic\t(v6)\n"
185 "\t\tEICMP6\tICMP traffic\t(v6) (errors)\n"
186 "\t\tUDP6\tUDP traffic\t(v6)\n"
187 "\t\tFC\tFibre channel HBAs\n"
188 "\t\tSOFT\tSoftware-based network processing\n"));
189 printf(_("\t-q [ <keyword> [,...] | PSI | ALL ]\n"
190 "\t\tSystem load and pressure-stall statistics\n"
191 "\t\tKeywords are:\n"
192 "\t\tLOAD\tQueue length and load average statistics [A_QUEUE]\n"
193 "\t\tCPU\tPressure-stall CPU statistics [A_PSI_CPU]\n"
194 "\t\tIO\tPressure-stall I/O statistics [A_PSI_IO]\n"
195 "\t\tMEM\tPressure-stall memory statistics [A_PSI_MEM]\n"));
196 printf(_("\t-r [ ALL ]\n"
197 "\t\tMemory utilization statistics [A_MEMORY]\n"));
198 printf(_("\t-S\tSwap space utilization statistics [A_MEMORY]\n"));
199 printf(_("\t-u [ ALL ]\n"
200 "\t\tCPU utilization statistics [A_CPU]\n"));
201 printf(_("\t-v\tKernel tables statistics [A_KTABLES]\n"));
202 printf(_("\t-W\tSwapping statistics [A_SWAP]\n"));
203 printf(_("\t-w\tTask creation and system switching statistics [A_PCSW]\n"));
204 printf(_("\t-y\tTTY devices statistics [A_SERIAL]\n"));
209 ***************************************************************************
210 * Give a hint to the user about where is located the data collector.
211 ***************************************************************************
213 void which_sadc(void)
217 if (stat(SADC_PATH, &buf) < 0) {
218 printf(_("Data collector will be sought in PATH\n"));
221 printf(_("Data collector found: %s\n"), SADC_PATH);
227 ***************************************************************************
228 * SIGINT signal handler.
231 * @sig Signal number.
232 ***************************************************************************
234 void int_handler(int sig)
237 printf("\n"); /* Skip "^C" displayed on screen */
242 ***************************************************************************
243 * Init some structures.
244 ***************************************************************************
246 void init_structures(void)
250 for (i = 0; i < 3; i++)
251 memset(&record_hdr[i], 0, RECORD_HEADER_SIZE);
255 ***************************************************************************
256 * Allocate memory for sadc args.
259 * @i Argument number.
260 * @ltemp Argument value.
261 ***************************************************************************
263 void salloc(int i, char *ltemp)
265 if ((args[i] = (char *) malloc(strlen(ltemp) + 1)) == NULL) {
269 strcpy(args[i], ltemp);
273 ***************************************************************************
274 * Display an error message.
277 * @error_code Code of error message to display.
278 ***************************************************************************
280 void print_read_error(int error_code)
282 switch (error_code) {
284 case END_OF_DATA_UNEXPECTED:
285 /* Happens when the data collector doesn't send enough data */
286 fprintf(stderr, _("End of data collecting unexpected\n"));
290 /* Strange data sent by sadc...! */
291 fprintf(stderr, _("Inconsistent input data\n"));
298 ***************************************************************************
299 * Check that every selected activity actually belongs to the sequence list.
300 * If not, then the activity should be unselected since it will not be sent
301 * by sadc. An activity can be not sent if its number of items is zero.
304 * @act_nr Size of sequence list.
305 ***************************************************************************
307 void reverse_check_act(unsigned int act_nr)
311 for (i = 0; i < NR_ACT; i++) {
313 if (IS_SELECTED(act[i]->options)) {
315 for (j = 0; j < act_nr; j++) {
316 if (id_seq[j] == act[i]->id)
320 act[i]->options &= ~AO_SELECTED;
326 ***************************************************************************
327 * Determine if a stat header line has to be displayed.
330 * TRUE if a header line has to be displayed.
331 ***************************************************************************
333 int check_line_hdr(void)
337 /* Get number of options entered on the command line */
338 if (get_activity_nr(act, AO_SELECTED, COUNT_OUTPUTS) > 1)
341 for (i = 0; i < NR_ACT; i++) {
342 if (IS_SELECTED(act[i]->options)) {
343 /* Special processing for activities using a bitmap */
344 if (act[i]->bitmap) {
345 if (count_bits(act[i]->bitmap->b_array,
346 BITMAP_SIZE(act[i]->bitmap->b_size)) > 1) {
350 else if (act[i]->nr_ini > 1) {
353 /* Stop now since we have only one selected activity */
362 ***************************************************************************
363 * Print statistics average.
366 * @curr Index in array for current sample statistics.
367 * @read_from_file Set to TRUE if stats are read from a system activity
369 * @act_id Activity that can be displayed, or ~0 for all.
370 * Remember that when reading stats from a file, only
371 * one activity can be displayed at a time.
372 ***************************************************************************
374 void write_stats_avg(int curr, int read_from_file, unsigned int act_id)
377 unsigned long long itv;
379 /* Interval value in 1/100th of a second */
380 itv = get_interval(record_hdr[2].uptime_cs, record_hdr[curr].uptime_cs);
382 strncpy(timestamp[curr], _("Average:"), sizeof(timestamp[curr]));
383 timestamp[curr][sizeof(timestamp[curr]) - 1] = '\0';
384 memcpy(timestamp[!curr], timestamp[curr], sizeof(timestamp[!curr]));
387 TEST_STDOUT(STDOUT_FILENO);
389 for (i = 0; i < NR_ACT; i++) {
391 if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
394 if (IS_SELECTED(act[i]->options) && (act[i]->nr[curr] > 0)) {
395 /* Display current average activity statistics */
396 (*act[i]->f_print_avg)(act[i], 2, curr, itv);
400 if (read_from_file) {
402 * Reset number of lines printed only if we read stats
403 * from a system activity file.
410 ***************************************************************************
411 * Print system statistics.
412 * This is called when we read stats either from a file or from sadc.
415 * @curr Index in array for current sample statistics.
416 * @read_from_file Set to TRUE if stats are read from a system activity
418 * @use_tm_start Set to TRUE if option -s has been used.
419 * @use_tm_end Set to TRUE if option -e has been used.
420 * @reset Set to TRUE if last_uptime variable should be
421 * reinitialized (used in next_slice() function).
422 * @act_id Activity that can be displayed or ~0 for all.
423 * Remember that when reading stats from a file, only
424 * one activity can be displayed at a time.
425 * @reset_cd TRUE if static cross_day variable should be reset
429 * @cnt Number of remaining lines to display.
432 * 1 if stats have been successfully displayed, and 0 otherwise.
433 ***************************************************************************
435 int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start,
436 int use_tm_end, int reset, unsigned int act_id, int reset_cd)
438 int i, prev_hour, rc = 0;
439 unsigned long long itv;
440 static int cross_day = FALSE;
444 * cross_day is a static variable that is set to 1 when the first
445 * record of stats from a new day is read from a unique data file
446 * (in the case where the file contains data from two consecutive
447 * days). When set to TRUE, every following records timestamp will
448 * have its hour value increased by 24.
449 * Yet when a new activity (being read from the file) is going to
450 * be displayed, we start reading the file from the beginning
451 * again, and so cross_day should be reset in this case.
457 if (read_from_file && !next_slice(record_hdr[2].uptime_cs, record_hdr[curr].uptime_cs,
459 /* Not close enough to desired interval */
462 /* Get then set previous timestamp */
463 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME, &record_hdr[!curr],
466 prev_hour = rectime.tm_hour;
467 set_record_timestamp_string(flags, &record_hdr[!curr],
468 NULL, timestamp[!curr], TIMESTAMP_LEN, &rectime);
470 /* Get then set current timestamp */
471 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME, &record_hdr[curr],
474 set_record_timestamp_string(flags, &record_hdr[curr],
475 NULL, timestamp[curr], TIMESTAMP_LEN, &rectime);
478 * Check if we are beginning a new day.
479 * Use rectime.tm_hour and prev_hour instead of record_hdr[].hour for comparison
480 * to take into account the current timezone (hours displayed will depend on the
481 * TZ variable value).
483 if (use_tm_start && record_hdr[!curr].ust_time &&
484 (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) &&
485 (rectime.tm_hour < prev_hour)) {
490 if (use_tm_end && (datecmp(&rectime, &tm_end, cross_day) > 0)) {
491 /* End time exceeded */
496 /* Get interval value in 1/100th of a second */
497 get_itv_value(&record_hdr[curr], &record_hdr[!curr], &itv);
502 TEST_STDOUT(STDOUT_FILENO);
504 for (i = 0; i < NR_ACT; i++) {
506 if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
509 if (IS_SELECTED(act[i]->options) && (act[i]->nr[curr] > 0)) {
510 /* Display current activity statistics */
511 (*act[i]->f_print)(act[i], !curr, curr, itv);
520 ***************************************************************************
521 * Display stats since system startup.
524 * @curr Index in array for current sample statistics.
525 ***************************************************************************
527 void write_stats_startup(int curr)
531 /* Set to 0 previous structures corresponding to boot time */
532 memset(&record_hdr[!curr], 0, RECORD_HEADER_SIZE);
533 record_hdr[!curr].record_type = R_STATS;
534 record_hdr[!curr].hour = record_hdr[curr].hour;
535 record_hdr[!curr].minute = record_hdr[curr].minute;
536 record_hdr[!curr].second = record_hdr[curr].second;
537 record_hdr[!curr].ust_time = record_hdr[curr].ust_time;
539 for (i = 0; i < NR_ACT; i++) {
540 if (IS_SELECTED(act[i]->options) && (act[i]->nr[curr] > 0)) {
542 * Using nr[curr] and not nr[!curr] below because we initialize
543 * reference structures for each structure that has been
544 * currently read in memory.
545 * No problem with buffers allocation since they all have the
548 memset(act[i]->buf[!curr], 0,
549 (size_t) act[i]->msize * (size_t) act[i]->nr[curr] * (size_t) act[i]->nr2);
553 flags |= S_F_SINCE_BOOT;
556 write_stats(curr, USE_SADC, &count, NO_TM_START, NO_TM_END, NO_RESET,
557 ALL_ACTIVITIES, TRUE);
563 ***************************************************************************
564 * Read data sent by the data collector.
567 * @size Number of bytes of data to read.
570 * @buffer Buffer where data will be saved.
573 * 0 if all the data have been successfully read.
574 * Otherwise, return the number of bytes left to be read.
575 ***************************************************************************
577 size_t sa_read(void *buffer, size_t size)
583 if ((n = read(STDIN_FILENO, buffer, size)) < 0) {
589 return size; /* EOF */
592 buffer = (char *) buffer + n;
599 ***************************************************************************
600 * Display a restart message (contents of a R_RESTART record).
603 * @tab Number of tabulations (unused here).
604 * @action Action expected from current function (unused here).
605 * @cur_date Date string of current restart message (unused here).
606 * @cur_time Time string of current restart message.
607 * @utc True if @cur_time is expressed in UTC (unused here).
608 * @file_hdr System activity file standard header.
609 * @record_hdr Current record header (unused here).
610 ***************************************************************************
612 __printf_funct_t print_sar_restart(int *tab, int action, char *cur_date, char *cur_time,
613 int utc, struct file_header *file_hdr,
614 struct record_header *record_hdr)
618 printf("\n%-11s", cur_time);
619 sprintf(restart, " LINUX RESTART\t(%d CPU)\n",
620 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
621 cprintf_s(IS_RESTART, "%s", restart);
626 ***************************************************************************
627 * Display a comment (contents of R_COMMENT record).
630 * @tab Number of tabulations (unused here).
631 * @action Action expected from current function (unused here).
632 * @cur_date Date string of current comment (unused here).
633 * @cur_time Time string of current comment.
634 * @utc True if @cur_time is expressed in UTC (unused here).
635 * @comment Comment to display.
636 * @file_hdr System activity file standard header (unused here).
637 * @record_hdr Current record header (unused here).
638 ***************************************************************************
640 __print_funct_t print_sar_comment(int *tab, int action, char *cur_date, char *cur_time, int utc,
641 char *comment, struct file_header *file_hdr,
642 struct record_header *record_hdr)
644 printf("%-11s", cur_time);
645 cprintf_s(IS_COMMENT, " COM %s\n", comment);
649 ***************************************************************************
650 * Read the various statistics sent by the data collector (sadc).
653 * @curr Index in array for current sample statistics.
654 ***************************************************************************
656 void read_sadc_stat_bunch(int curr)
660 /* Read record header (type is always R_STATS since it is read from sadc) */
661 if (sa_read(&record_hdr[curr], RECORD_HEADER_SIZE)) {
663 * SIGINT (sent by sadc) is likely to be received
664 * while we are stuck in sa_read().
665 * If this happens then no data have to be read.
671 fprintf(stderr, "%s: Record header\n", __FUNCTION__);
673 print_read_error(END_OF_DATA_UNEXPECTED);
676 for (i = 0; i < NR_ACT; i++) {
680 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
682 if (HAS_COUNT_FUNCTION(act[p]->options)) {
683 if (sa_read(&(act[p]->nr[curr]), sizeof(__nr_t))) {
685 fprintf(stderr, "%s: Nb of items\n", __FUNCTION__);
687 print_read_error(END_OF_DATA_UNEXPECTED);
689 if ((act[p]->nr[curr] > act[p]->nr_max) || (act[p]->nr[curr] < 0)) {
691 fprintf(stderr, "%s: %s: nr=%d nr_max=%d\n",
692 __FUNCTION__, act[p]->name, act[p]->nr[curr], act[p]->nr_max);
694 print_read_error(INCONSISTENT_INPUT_DATA);
696 if (act[p]->nr[curr] > act[p]->nr_allocated) {
697 reallocate_all_buffers(act[p], act[p]->nr[curr]);
701 * For persistent activities, we must make sure that no statistics
702 * from a previous iteration remain, especially if the number
703 * of structures read is smaller than @nr_ini.
705 if (HAS_PERSISTENT_VALUES(act[p]->options)) {
706 memset(act[p]->buf[curr], 0,
707 (size_t) act[p]->fsize * (size_t) act[p]->nr_ini * (size_t) act[p]->nr2);
710 if (sa_read(act[p]->buf[curr],
711 (size_t) act[p]->fsize * (size_t) act[p]->nr[curr] * (size_t) act[p]->nr2)) {
713 fprintf(stderr, "%s: Statistics\n", __FUNCTION__);
715 print_read_error(END_OF_DATA_UNEXPECTED);
721 ***************************************************************************
722 * Read current activity's statistics (located between two consecutive
723 * LINUX RESTART messages) from file and display them.
726 * @ifd Input file descriptor.
727 * @fpos Position in file where reading must start.
728 * @curr Index in array for current sample statistics.
729 * @rows Number of rows of screen.
730 * @act_id Activity to display.
731 * @file_actlst List of activities in file.
732 * @file Name of file being read.
733 * @file_magic file_magic structure filled with file magic header data.
734 * @rec_hdr_tmp Temporary buffer where current record header will be saved.
736 * TRUE if file's data don't match current machine's endianness.
737 * @arch_64 TRUE if file's data come from a 64 bit machine.
738 * @b_size Size of @rec_hdr_tmp buffer.
741 * @curr Index in array for next sample statistics.
742 * @cnt Number of remaining lines of stats to write.
743 * @eosaf Set to TRUE if EOF (end of file) has been reached.
744 * @reset Set to TRUE if last_uptime variable should be reinitialized
745 * (used in next_slice() function).
746 ***************************************************************************
748 void handle_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf,
749 int rows, unsigned int act_id, int *reset,
750 struct file_activity *file_actlst, char *file,
751 struct file_magic *file_magic, void *rec_hdr_tmp,
752 int endian_mismatch, int arch_64, size_t b_size)
755 unsigned long lines = 0;
757 int davg = 0, next, inc = 0;
759 if (lseek(ifd, fpos, SEEK_SET) < fpos) {
765 * Restore the first stats collected.
766 * Used to compute the rate displayed on the first line.
768 copy_structures(act, id_seq, record_hdr, !*curr, 2);
772 /* Assess number of lines printed when a bitmap is used */
773 p = get_activity_position(act, act_id, EXIT_IF_NOT_FOUND);
774 if (act[p]->bitmap) {
775 inc = count_bits(act[p]->bitmap->b_array,
776 BITMAP_SIZE(act[p]->bitmap->b_size));
782 * Display <count> lines of stats.
783 * Start with reading current sample's record header.
785 *eosaf = read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[*curr],
786 &file_hdr, arch_64, endian_mismatch, UEOF_STOP, b_size,
788 rtype = record_hdr[*curr].record_type;
790 if ((lines >= rows) || !lines) {
797 if (*eosaf || (rtype == R_RESTART))
798 /* This is EOF or we have met a LINUX RESTART record: Stop now */
801 if (rtype != R_COMMENT) {
802 /* Read the extra fields since it's not a special record */
803 if (read_file_stat_bunch(act, *curr, ifd, file_hdr.sa_act_nr, file_actlst,
804 endian_mismatch, arch_64, file, file_magic, UEOF_STOP))
805 /* Error or unexpected EOF */
809 /* Display comment */
810 next = print_special_record(&record_hdr[*curr], flags + S_F_LOCAL_TIME,
811 &tm_start, &tm_end, R_COMMENT, ifd,
813 file_magic, &file_hdr, act, &sar_fmt,
814 endian_mismatch, arch_64);
817 * A line of comment was actually displayed: Count it in the
818 * total number of displayed lines.
819 * If no lines of stats had been previously displayed, ignore it
820 * to make sure the header line will be displayed.
827 /* next is set to 1 when we were close enough to desired interval */
828 next = write_stats(*curr, USE_SA_FILE, cnt, tm_start.use, tm_end.use,
829 *reset, act_id, reset_cd);
831 if (next && (*cnt > 0)) {
843 lines += act[p]->nr[*curr];
851 * At this moment, if we had a R_RESTART record, we still haven't read
852 * the number of CPU following it (nor the possible extra structures).
853 * But in this case, we always have @cnt != 0.
857 write_stats_avg(!*curr, USE_SA_FILE, act_id);
864 ***************************************************************************
865 * Read header data sent by sadc.
866 ***************************************************************************
868 void read_header_data(void)
870 struct file_magic file_magic;
871 struct file_activity file_act;
875 /* Read magic header */
876 rc = sa_read(&file_magic, FILE_MAGIC_SIZE);
878 sprintf(version, "%d.%d.%d.%d",
879 file_magic.sysstat_version,
880 file_magic.sysstat_patchlevel,
881 file_magic.sysstat_sublevel,
882 file_magic.sysstat_extraversion);
883 if (!file_magic.sysstat_extraversion) {
884 version[strlen(version) - 2] = '\0';
887 if (rc || (file_magic.sysstat_magic != SYSSTAT_MAGIC) ||
888 (file_magic.format_magic != FORMAT_MAGIC) ||
889 strcmp(version, VERSION)) {
891 /* sar and sadc commands are not consistent */
892 if (!rc && (file_magic.sysstat_magic == SYSSTAT_MAGIC)) {
894 _("Using a wrong data collector from a different sysstat version\n"));
898 fprintf(stderr, "%s: sysstat_magic=%x format_magic=%x version=%s\n",
899 __FUNCTION__, file_magic.sysstat_magic, file_magic.format_magic, version);
901 if (rc == FILE_MAGIC_SIZE) {
903 * No data (0 byte) have been sent by sadc.
904 * This is probably because no activities have been collected
905 * ("Requested activities not available"). In this case, don't
906 * display an error message: Exit now.
910 print_read_error(INCONSISTENT_INPUT_DATA);
915 * No need to take into account file_magic.header_size. We are sure that
916 * sadc and sar are from the same version (we have checked FORMAT_MAGIC
917 * but also VERSION above) and thus the size of file_header is FILE_HEADER_SIZE.
919 if (sa_read(&file_hdr, FILE_HEADER_SIZE)) {
921 fprintf(stderr, "%s: File header\n", __FUNCTION__);
923 print_read_error(END_OF_DATA_UNEXPECTED);
926 /* All activities are not necessarily selected, but NR_ACT is a max */
927 if (file_hdr.sa_act_nr > NR_ACT) {
929 fprintf(stderr, "%s: sa_act_nr=%d\n", __FUNCTION__, file_hdr.sa_act_nr);
931 print_read_error(INCONSISTENT_INPUT_DATA);
934 if ((file_hdr.act_size != FILE_ACTIVITY_SIZE) ||
935 (file_hdr.rec_size != RECORD_HEADER_SIZE)) {
937 fprintf(stderr, "%s: act_size=%u/%zu rec_size=%u/%zu\n", __FUNCTION__,
938 file_hdr.act_size, FILE_ACTIVITY_SIZE, file_hdr.rec_size, RECORD_HEADER_SIZE);
940 print_read_error(INCONSISTENT_INPUT_DATA);
943 /* Read activity list */
944 for (i = 0; i < file_hdr.sa_act_nr; i++) {
946 if (sa_read(&file_act, FILE_ACTIVITY_SIZE)) {
948 fprintf(stderr, "%s: File activity (%d)\n", __FUNCTION__, i);
950 print_read_error(END_OF_DATA_UNEXPECTED);
953 p = get_activity_position(act, file_act.id, RESUME_IF_NOT_FOUND);
955 if ((p < 0) || (act[p]->fsize != file_act.size)
956 || (act[p]->gtypes_nr[0] != file_act.types_nr[0])
957 || (act[p]->gtypes_nr[1] != file_act.types_nr[1])
958 || (act[p]->gtypes_nr[2] != file_act.types_nr[2])
959 || (file_act.nr <= 0)
960 || (file_act.nr2 <= 0)
961 || (act[p]->magic != file_act.magic)) {
964 fprintf(stderr, "%s: p=%d\n", __FUNCTION__, p);
967 fprintf(stderr, "%s: %s: size=%d/%d magic=%x/%x nr=%d nr2=%d types=%d,%d,%d/%d,%d,%d\n",
968 __FUNCTION__, act[p]->name, act[p]->fsize, file_act.size,
969 act[p]->magic, file_act.magic, file_act.nr, file_act.nr2,
970 act[p]->gtypes_nr[0], act[p]->gtypes_nr[1], act[p]->gtypes_nr[2],
971 file_act.types_nr[0], file_act.types_nr[1], file_act.types_nr[2]);
974 /* Remember that we are reading data from sadc and not from a file... */
975 print_read_error(INCONSISTENT_INPUT_DATA);
978 id_seq[i] = file_act.id; /* We necessarily have "i < NR_ACT" */
979 act[p]->nr_ini = file_act.nr;
980 act[p]->nr2 = file_act.nr2;
987 /* Check that all selected activties are actually sent by sadc */
988 reverse_check_act(file_hdr.sa_act_nr);
994 ***************************************************************************
995 * Read statistics from a system activity data file.
998 * @from_file Input file name.
999 ***************************************************************************
1001 void read_stats_from_file(char from_file[])
1003 struct file_magic file_magic;
1004 struct file_activity *file_actlst = NULL;
1005 char rec_hdr_tmp[MAX_RECORD_HEADER_SIZE];
1008 int rows, eosaf = TRUE, reset = FALSE;
1012 /* Get window size */
1013 rows = get_win_height();
1015 /* Read file headers and activity list */
1016 check_file_actlst(&ifd, from_file, act, flags, &file_magic, &file_hdr,
1017 &file_actlst, id_seq, &endian_mismatch, &arch_64);
1019 /* Perform required allocations */
1020 allocate_structures(act);
1022 /* Print report header */
1023 print_report_hdr(flags, &rectime, &file_hdr);
1025 /* Read system statistics from file */
1028 * If this record is a special (RESTART or COMMENT) one, print it and
1029 * (try to) get another one.
1032 if (read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[0], &file_hdr,
1033 arch_64, endian_mismatch, UEOF_STOP, sizeof(rec_hdr_tmp), flags, &sar_fmt)) {
1034 /* End of sa data file */
1038 rtype = record_hdr[0].record_type;
1039 if ((rtype == R_RESTART) || (rtype == R_COMMENT)) {
1040 print_special_record(&record_hdr[0], flags + S_F_LOCAL_TIME,
1041 &tm_start, &tm_end, rtype, ifd,
1042 &rectime, from_file, 0, &file_magic,
1043 &file_hdr, act, &sar_fmt, endian_mismatch, arch_64);
1047 * OK: Previous record was not a special one.
1048 * So read now the extra fields.
1050 if (read_file_stat_bunch(act, 0, ifd, file_hdr.sa_act_nr,
1051 file_actlst, endian_mismatch, arch_64,
1052 from_file, &file_magic, UEOF_STOP))
1053 /* Possible unexpected EOF */
1056 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME,
1057 &record_hdr[0], &rectime))
1059 * An error was detected.
1060 * The timestamp hasn't been updated.
1065 while ((rtype == R_RESTART) || (rtype == R_COMMENT) ||
1066 (tm_start.use && (datecmp(&rectime, &tm_start, FALSE) < 0)) ||
1067 (tm_end.use && (datecmp(&rectime, &tm_end, FALSE) >= 0)));
1069 /* Save the first stats collected. Will be used to compute the average */
1070 copy_structures(act, id_seq, record_hdr, 2, 0);
1072 reset = TRUE; /* Set flag to reset last_uptime variable */
1074 /* Save current file position */
1075 if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) {
1081 * Read and write stats located between two possible Linux restarts.
1082 * Activities that should be displayed are saved in id_seq[] array.
1083 * Since we are reading from a file, we print all the stats for an
1084 * activity before displaying the next activity.
1085 * id_seq[] has been created in check_file_actlst(), retaining only
1086 * activities known by current sysstat version.
1088 for (i = 0; i < NR_ACT; i++) {
1093 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1094 if (!IS_SELECTED(act[p]->options))
1097 if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) {
1098 handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, rows,
1099 act[p]->id, &reset, file_actlst,
1100 from_file, &file_magic, rec_hdr_tmp,
1101 endian_mismatch, arch_64, sizeof(rec_hdr_tmp));
1104 unsigned int optf, msk;
1106 optf = act[p]->opt_flags;
1108 for (msk = 1; msk < 0x100; msk <<= 1) {
1109 if ((act[p]->opt_flags & 0xff) & msk) {
1110 act[p]->opt_flags &= (0xffffff00 + msk);
1112 handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
1113 rows, act[p]->id, &reset, file_actlst,
1114 from_file, &file_magic, rec_hdr_tmp,
1115 endian_mismatch, arch_64, sizeof(rec_hdr_tmp));
1116 act[p]->opt_flags = optf;
1123 * Go to next Linux restart, if possible.
1124 * Note: If we have @cnt == 0 then the last record we read was not a R_RESTART one
1125 * (else we would have had @cnt != 0, i.e. we would have stopped reading previous activity
1126 * because such a R_RESTART record would have been read, not because all the <count> lines
1127 * had been printed).
1128 * Remember @cnt is decremented only when a real line of stats have been displayed
1129 * (not when a special record has been read).
1132 /* Read next record header */
1133 eosaf = read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[curr],
1134 &file_hdr, arch_64, endian_mismatch, UEOF_STOP, sizeof(rec_hdr_tmp), flags, &sar_fmt);
1135 rtype = record_hdr[curr].record_type;
1137 if (eosaf || (rtype == R_RESTART))
1140 if (rtype != R_COMMENT) {
1141 if (read_file_stat_bunch(act, curr, ifd, file_hdr.sa_act_nr,
1142 file_actlst, endian_mismatch, arch_64,
1143 from_file, &file_magic, UEOF_STOP))
1144 /* Possible unexpected EOF */
1148 /* This was a COMMENT record: Print it */
1149 print_special_record(&record_hdr[curr], flags + S_F_LOCAL_TIME,
1150 &tm_start, &tm_end, R_COMMENT, ifd,
1151 &rectime, from_file, 0,
1152 &file_magic, &file_hdr, act, &sar_fmt,
1153 endian_mismatch, arch_64);
1159 /* The last record we read was a RESTART one: Print it */
1160 if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) {
1161 print_special_record(&record_hdr[curr], flags + S_F_LOCAL_TIME,
1162 &tm_start, &tm_end, R_RESTART, ifd,
1163 &rectime, from_file, 0,
1164 &file_magic, &file_hdr, act, &sar_fmt,
1165 endian_mismatch, arch_64);
1176 ***************************************************************************
1177 * Read statistics sent by sadc, the data collector.
1178 ***************************************************************************
1180 void read_stats(void)
1183 unsigned long lines;
1187 /* Don't buffer data if redirected to a pipe... */
1188 setbuf(stdout, NULL);
1190 /* Read stats header */
1193 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1194 /* Requested activities not available: Exit */
1195 print_collect_error();
1198 /* Determine if a stat line header has to be displayed */
1199 dis_hdr = check_line_hdr();
1201 lines = rows = get_win_height();
1203 /* Perform required allocations */
1204 allocate_structures(act);
1206 /* Print report header */
1207 print_report_hdr(flags, &rectime, &file_hdr);
1209 /* Read system statistics sent by the data collector */
1210 read_sadc_stat_bunch(0);
1213 /* Display stats since boot time and exit */
1214 write_stats_startup(0);
1217 /* Save the first stats collected. Will be used to compute the average */
1218 copy_structures(act, id_seq, record_hdr, 2, 0);
1220 /* Set a handler for SIGINT */
1221 memset(&int_act, 0, sizeof(int_act));
1222 int_act.sa_handler = int_handler;
1223 int_act.sa_flags = SA_RESTART;
1224 sigaction(SIGINT, &int_act, NULL);
1230 read_sadc_stat_bunch(curr);
1231 if (sigint_caught) {
1233 * SIGINT signal caught (it is sent by sadc).
1234 * => Display average stats.
1236 curr ^= 1; /* No data retrieved from last read */
1242 dish = lines / rows;
1248 write_stats(curr, USE_SADC, &count, NO_TM_START, tm_end.use,
1249 NO_RESET, ALL_ACTIVITIES, TRUE);
1251 if (record_hdr[curr].record_type == R_LAST_STATS) {
1252 /* File rotation is happening: Re-read header data sent by sadc */
1254 allocate_structures(act);
1267 * Print statistics average.
1268 * At least one line of stats must have been displayed for this.
1269 * (There may be no lines at all if we press Ctrl/C immediately).
1273 write_stats_avg(curr, USE_SADC, ALL_ACTIVITIES);
1278 ***************************************************************************
1279 * Main entry to the sar program.
1280 ***************************************************************************
1282 int main(int argc, char **argv)
1284 int i, rc, opt = 1, args_idx = 1, p, q;
1287 char from_file[MAX_FILE_LEN], to_file[MAX_FILE_LEN];
1290 /* Compute page shift in kB */
1293 from_file[0] = to_file[0] = '\0';
1296 /* Init National Language Support */
1300 tm_start.use = tm_end.use = FALSE;
1302 /* Allocate and init activity bitmaps */
1303 allocate_bitmaps(act);
1307 /* Process options */
1308 while (opt < argc) {
1310 if (!strcmp(argv[opt], "--sadc")) {
1315 else if (!strncmp(argv[opt], "--dev=", 6)) {
1316 /* Parse devices entered on the command line */
1317 p = get_activity_position(act, A_DISK, EXIT_IF_NOT_FOUND);
1318 parse_sa_devices(argv[opt], act[p], MAX_DEV_LEN, &opt, 6);
1321 else if (!strncmp(argv[opt], "--fs=", 5)) {
1322 /* Parse devices entered on the command line */
1323 p = get_activity_position(act, A_FS, EXIT_IF_NOT_FOUND);
1324 parse_sa_devices(argv[opt], act[p], MAX_FS_LEN, &opt, 5);
1327 else if (!strncmp(argv[opt], "--iface=", 8)) {
1328 /* Parse devices entered on the command line */
1329 p = get_activity_position(act, A_NET_DEV, EXIT_IF_NOT_FOUND);
1330 parse_sa_devices(argv[opt], act[p], MAX_IFACE_LEN, &opt, 8);
1331 q = get_activity_position(act, A_NET_EDEV, EXIT_IF_NOT_FOUND);
1332 act[q]->item_list = act[p]->item_list;
1333 act[q]->item_list_sz = act[p]->item_list_sz;
1334 act[q]->options |= AO_LIST_ON_CMDLINE;
1337 else if (!strcmp(argv[opt], "--help")) {
1338 /* Display help message */
1339 display_help(argv[0]);
1342 else if (!strcmp(argv[opt], "--human")) {
1343 /* Display sizes in a human readable format */
1348 else if (!strcmp(argv[opt], "--pretty")) {
1349 /* Display an easy-to-read report */
1350 flags |= S_F_PRETTY;
1354 else if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
1355 /* Get number of decimal places */
1356 dplaces_nr = atoi(argv[opt] + 6);
1357 if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
1363 else if (!strcmp(argv[opt], "-I")) {
1364 /* Parse -I option */
1365 if (parse_sar_I_opt(argv, &opt, &flags, act)) {
1370 else if (!strcmp(argv[opt], "-D")) {
1371 /* Option to tell sar to write to saYYYYMMDD data files */
1372 flags |= S_F_SA_YYYYMMDD;
1376 else if (!strcmp(argv[opt], "-P")) {
1377 /* Parse -P option */
1378 if (parse_sa_P_opt(argv, &opt, &flags, act)) {
1383 else if (!strcmp(argv[opt], "-o")) {
1385 /* Output file already specified */
1388 /* Save stats to a file */
1389 if ((argv[++opt]) && strncmp(argv[opt], "-", 1) &&
1390 (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
1391 strncpy(to_file, argv[opt++], sizeof(to_file));
1392 to_file[sizeof(to_file) - 1] = '\0';
1395 strcpy(to_file, "-");
1399 else if (!strcmp(argv[opt], "-f")) {
1400 if (from_file[0] || day_offset) {
1401 /* Input file already specified */
1404 /* Read stats from a file */
1405 if ((argv[++opt]) && strncmp(argv[opt], "-", 1) &&
1406 (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
1407 strncpy(from_file, argv[opt++], sizeof(from_file));
1408 from_file[sizeof(from_file) - 1] = '\0';
1409 /* Check if this is an alternate directory for sa files */
1410 check_alt_sa_dir(from_file, day_offset, -1);
1413 set_default_file(from_file, day_offset, -1);
1417 else if (!strcmp(argv[opt], "-s")) {
1418 /* Get time start */
1419 if (parse_timestamp(argv, &opt, &tm_start, DEF_TMSTART)) {
1424 else if (!strcmp(argv[opt], "-e")) {
1426 if (parse_timestamp(argv, &opt, &tm_end, DEF_TMEND)) {
1431 else if (!strcmp(argv[opt], "-i")) {
1432 if (!argv[++opt] || (strspn(argv[opt], DIGITS) != strlen(argv[opt]))) {
1435 interval = atol(argv[opt++]);
1439 flags |= S_F_INTERVAL_SET;
1442 else if (!strcmp(argv[opt], "-m")) {
1446 /* Parse option -m */
1447 if (parse_sar_m_opt(argv, &opt, act)) {
1452 else if (!strcmp(argv[opt], "-n")) {
1456 /* Parse option -n */
1457 if (parse_sar_n_opt(argv, &opt, act)) {
1462 else if (!strcmp(argv[opt], "-q")) {
1464 SELECT_ACTIVITY(A_QUEUE);
1466 /* Parse option -q */
1467 else if (parse_sar_q_opt(argv, &opt, act)) {
1468 SELECT_ACTIVITY(A_QUEUE);
1473 else if (!strncmp(argv[opt], "--getenv", 8)) {
1478 else if (!strncmp(argv[opt], "--unix_time=", 12)) {
1479 if (strspn(argv[opt] + 12, DIGITS) != strlen(argv[opt] + 12)) {
1482 __unix_time = atoll(argv[opt++] + 12);
1485 else if ((strlen(argv[opt]) > 1) &&
1486 (strlen(argv[opt]) < 4) &&
1487 !strncmp(argv[opt], "-", 1) &&
1488 (strspn(argv[opt] + 1, DIGITS) == (strlen(argv[opt]) - 1))) {
1489 if (from_file[0] || day_offset) {
1490 /* Input file already specified */
1493 day_offset = atoi(argv[opt++] + 1);
1496 else if (!strncmp(argv[opt], "-", 1)) {
1497 /* Other options not previously tested */
1498 if ((rc = parse_sar_opt(argv, &opt, act, &flags, C_SAR)) != 0) {
1507 else if (interval < 0) {
1509 if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
1512 interval = atol(argv[opt++]);
1519 /* Get count value */
1520 if ((strspn(argv[opt], DIGITS) != strlen(argv[opt])) ||
1525 /* Count parameter already set */
1528 count = atol(argv[opt++]);
1535 /* Init color strings */
1538 /* 'sar' is equivalent to 'sar -f' */
1540 (((interval < 0) || INTERVAL_SET(flags)) && !from_file[0] && !to_file[0])) {
1541 set_default_file(from_file, day_offset, -1);
1544 if (tm_start.use && tm_end.use && (tm_end.tm_hour < tm_start.tm_hour)) {
1545 tm_end.tm_hour += 24;
1549 * Check option dependencies.
1551 /* You read from a file OR you write to it... */
1552 if (from_file[0] && to_file[0]) {
1553 fprintf(stderr, _("-f and -o options are mutually exclusive\n"));
1556 if (USE_OPTION_A(flags)) {
1557 /* Set -P ALL -I ALL if needed */
1558 set_bitmaps(act, &flags);
1560 /* Use time start or option -i only when reading stats from a file */
1561 if ((tm_start.use || INTERVAL_SET(flags)) && !from_file[0]) {
1563 _("Not reading from a system activity file (use -f option)\n"));
1566 /* Don't print stats since boot time if -o or -f options are used */
1567 if (!interval && (from_file[0] || to_file[0])) {
1571 /* Cannot enter a day shift with -o option */
1572 if (to_file[0] && day_offset) {
1578 * count parameter not set: Display all the contents of the file
1579 * or generate a report continuously.
1584 /* Default is CPU activity... */
1585 select_default_activity(act);
1587 /* Check S_TIME_FORMAT variable contents */
1588 if (!is_iso_time_fmt())
1589 flags |= S_F_PREFD_TIME_OUTPUT;
1591 /* Reading stats from file: */
1597 /* Read stats from file */
1598 read_stats_from_file(from_file);
1600 /* Free structures and activity bitmaps */
1602 free_structures(act);
1607 /* Reading stats from sadc: */
1609 /* Create anonymous pipe */
1610 if (pipe(fd) == -1) {
1623 if (dup2(fd[1], STDOUT_FILENO) < 0) {
1630 * Prepare options for sadc.
1635 /* Interval value */
1639 else if (!interval) {
1642 * Display stats since system startup: Set <interval> to 1.
1643 * <count> arg will also be set to 1 below.
1645 salloc(args_idx++, ltemp);
1648 sprintf(ltemp, "%ld", interval);
1650 salloc(args_idx++, ltemp);
1654 sprintf(ltemp, "%ld", count + 1);
1655 salloc(args_idx++, ltemp);
1660 sprintf(ltemp, "--unix_time=%ld", __unix_time);
1661 salloc(args_idx++, ltemp);
1664 /* Flags to be passed to sadc */
1665 salloc(args_idx++, "-Z");
1667 /* Writing data to a file (option -o) */
1669 /* Set option -D if entered */
1670 if (USE_SA_YYYYMMDD(flags)) {
1671 salloc(args_idx++, "-D");
1673 /* Collect all possible activities (option -S XALL for sadc) */
1674 salloc(args_idx++, "-S");
1675 salloc(args_idx++, K_XALL);
1677 salloc(args_idx++, to_file);
1681 * If option -o hasn't been used, then tell sadc
1682 * to collect only activities that will be displayed.
1684 salloc(args_idx++, "-S");
1685 strcpy(ltemp, K_A_NULL);
1686 for (i = 0; i < NR_ACT; i++) {
1687 if (IS_SELECTED(act[i]->options)) {
1689 strcat(ltemp, act[i]->name);
1692 salloc(args_idx++, ltemp);
1695 /* Last arg is NULL */
1696 args[args_idx] = NULL;
1698 /* Call now the data collector */
1700 fprintf(stderr, "%s: 1.sadc: %s\n", __FUNCTION__, SADC_PATH);
1703 execv(SADC_PATH, args);
1705 fprintf(stderr, "%s: 2.sadc: %s\n", __FUNCTION__, SADC);
1709 * Note: Don't use execl/execlp since we don't have a fixed number of
1710 * args to give to sadc.
1712 fprintf(stderr, _("Cannot find the data collector (%s)\n"), SADC);
1717 default: /* Parent */
1718 if (dup2(fd[0], STDIN_FILENO) < 0) {
1724 /* Get now the statistics */
1730 /* Free structures and activity bitmaps */
1732 free_structures(act);