2 * sar: report system activity
3 * (C) 1999-2022 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> ] "
130 "[ --int=<int_list> ]\n"
131 "[ --dec={ 0 | 1 | 2 } ] [ --help ] [ --human ] [ --pretty ] [ --sadc ]\n"
132 "[ -j { SID | ID | LABEL | PATH | UUID | ... } ]\n"
133 "[ -f [ <filename> ] | -o [ <filename> ] | -[0-9]+ ]\n"
134 "[ -i <interval> ] [ -s [ <hh:mm[:ss]> ] ] [ -e [ <hh:mm[:ss]> ] ]\n"));
139 ***************************************************************************
140 * Display a short help message and exit.
143 * @progname Name of sysstat command
144 ***************************************************************************
146 void display_help(char *progname)
148 print_usage_title(stdout, progname);
149 printf(_("Main options and reports (report name between square brackets):\n"));
150 printf(_("\t-B\tPaging statistics [A_PAGE]\n"));
151 printf(_("\t-b\tI/O and transfer rate statistics [A_IO]\n"));
152 printf(_("\t-d\tBlock devices statistics [A_DISK]\n"));
153 printf(_("\t-F [ MOUNT ]\n"));
154 printf(_("\t\tFilesystems statistics [A_FS]\n"));
155 printf(_("\t-H\tHugepages utilization statistics [A_HUGE]\n"));
156 printf(_("\t-I { <int_list> | SUM | ALL }\n"
157 "\t\tInterrupts statistics [A_IRQ]\n"));
158 printf(_("\t-m { <keyword> [,...] | ALL }\n"
159 "\t\tPower management statistics [A_PWR_...]\n"
160 "\t\tKeywords are:\n"
161 "\t\tCPU\tCPU instantaneous clock frequency\n"
162 "\t\tFAN\tFans speed\n"
163 "\t\tFREQ\tCPU average clock frequency\n"
164 "\t\tIN\tVoltage inputs\n"
165 "\t\tTEMP\tDevices temperature\n"
166 "\t\tUSB\tUSB devices plugged into the system\n"));
167 printf(_("\t-n { <keyword> [,...] | ALL }\n"
168 "\t\tNetwork statistics [A_NET_...]\n"
169 "\t\tKeywords are:\n"
170 "\t\tDEV\tNetwork interfaces\n"
171 "\t\tEDEV\tNetwork interfaces (errors)\n"
172 "\t\tNFS\tNFS client\n"
173 "\t\tNFSD\tNFS server\n"
174 "\t\tSOCK\tSockets\t(v4)\n"
175 "\t\tIP\tIP traffic\t(v4)\n"
176 "\t\tEIP\tIP traffic\t(v4) (errors)\n"
177 "\t\tICMP\tICMP traffic\t(v4)\n"
178 "\t\tEICMP\tICMP traffic\t(v4) (errors)\n"
179 "\t\tTCP\tTCP traffic\t(v4)\n"
180 "\t\tETCP\tTCP traffic\t(v4) (errors)\n"
181 "\t\tUDP\tUDP traffic\t(v4)\n"
182 "\t\tSOCK6\tSockets\t(v6)\n"
183 "\t\tIP6\tIP traffic\t(v6)\n"
184 "\t\tEIP6\tIP traffic\t(v6) (errors)\n"
185 "\t\tICMP6\tICMP traffic\t(v6)\n"
186 "\t\tEICMP6\tICMP traffic\t(v6) (errors)\n"
187 "\t\tUDP6\tUDP traffic\t(v6)\n"
188 "\t\tFC\tFibre channel HBAs\n"
189 "\t\tSOFT\tSoftware-based network processing\n"));
190 printf(_("\t-q [ <keyword> [,...] | PSI | ALL ]\n"
191 "\t\tSystem load and pressure-stall statistics\n"
192 "\t\tKeywords are:\n"
193 "\t\tLOAD\tQueue length and load average statistics [A_QUEUE]\n"
194 "\t\tCPU\tPressure-stall CPU statistics [A_PSI_CPU]\n"
195 "\t\tIO\tPressure-stall I/O statistics [A_PSI_IO]\n"
196 "\t\tMEM\tPressure-stall memory statistics [A_PSI_MEM]\n"));
197 printf(_("\t-r [ ALL ]\n"
198 "\t\tMemory utilization statistics [A_MEMORY]\n"));
199 printf(_("\t-S\tSwap space utilization statistics [A_MEMORY]\n"));
200 printf(_("\t-u [ ALL ]\n"
201 "\t\tCPU utilization statistics [A_CPU]\n"));
202 printf(_("\t-v\tKernel tables statistics [A_KTABLES]\n"));
203 printf(_("\t-W\tSwapping statistics [A_SWAP]\n"));
204 printf(_("\t-w\tTask creation and system switching statistics [A_PCSW]\n"));
205 printf(_("\t-y\tTTY devices statistics [A_SERIAL]\n"));
210 ***************************************************************************
211 * Give a hint to the user about where is located the data collector.
212 ***************************************************************************
214 void which_sadc(void)
218 if (stat(SADC_PATH, &buf) < 0) {
219 printf(_("Data collector will be sought in PATH\n"));
222 printf(_("Data collector found: %s\n"), SADC_PATH);
228 ***************************************************************************
229 * SIGINT signal handler.
232 * @sig Signal number.
233 ***************************************************************************
235 void int_handler(int sig)
238 printf("\n"); /* Skip "^C" displayed on screen */
243 ***************************************************************************
244 * Init some structures.
245 ***************************************************************************
247 void init_structures(void)
251 for (i = 0; i < 3; i++)
252 memset(&record_hdr[i], 0, RECORD_HEADER_SIZE);
256 ***************************************************************************
257 * Allocate memory for sadc args.
260 * @i Argument number.
261 * @ltemp Argument value.
262 ***************************************************************************
264 void salloc(int i, char *ltemp)
266 if ((args[i] = (char *) malloc(strlen(ltemp) + 1)) == NULL) {
270 strcpy(args[i], ltemp);
274 ***************************************************************************
275 * Display an error message.
278 * @error_code Code of error message to display.
279 ***************************************************************************
281 void print_read_error(int error_code)
283 switch (error_code) {
285 case END_OF_DATA_UNEXPECTED:
286 /* Happens when the data collector doesn't send enough data */
287 fprintf(stderr, _("End of data collecting unexpected\n"));
291 /* Strange data sent by sadc...! */
292 fprintf(stderr, _("Inconsistent input data\n"));
299 ***************************************************************************
300 * Check that every selected activity actually belongs to the sequence list.
301 * If not, then the activity should be unselected since it will not be sent
302 * by sadc. An activity can be not sent if its number of items is zero.
305 * @act_nr Size of sequence list.
306 ***************************************************************************
308 void reverse_check_act(unsigned int act_nr)
312 for (i = 0; i < NR_ACT; i++) {
314 if (IS_SELECTED(act[i]->options)) {
316 for (j = 0; j < act_nr; j++) {
317 if (id_seq[j] == act[i]->id)
321 act[i]->options &= ~AO_SELECTED;
327 ***************************************************************************
328 * Determine if a stat header line has to be displayed.
331 * TRUE if a header line has to be displayed.
332 ***************************************************************************
334 int check_line_hdr(void)
338 /* Get number of options entered on the command line */
339 if (get_activity_nr(act, AO_SELECTED, COUNT_OUTPUTS) > 1)
342 for (i = 0; i < NR_ACT; i++) {
343 if (IS_SELECTED(act[i]->options)) {
344 /* Special processing for activities using a bitmap */
345 if (act[i]->bitmap) {
346 if (count_bits(act[i]->bitmap->b_array,
347 BITMAP_SIZE(act[i]->bitmap->b_size)) > 1) {
351 else if (act[i]->nr_ini > 1) {
354 /* Stop now since we have only one selected activity */
363 ***************************************************************************
364 * Print statistics average.
367 * @curr Index in array for current sample statistics.
368 * @read_from_file Set to TRUE if stats are read from a system activity
370 * @act_id Activity that can be displayed, or ~0 for all.
371 * Remember that when reading stats from a file, only
372 * one activity can be displayed at a time.
373 ***************************************************************************
375 void write_stats_avg(int curr, int read_from_file, unsigned int act_id)
378 unsigned long long itv;
380 /* Interval value in 1/100th of a second */
381 itv = get_interval(record_hdr[2].uptime_cs, record_hdr[curr].uptime_cs);
383 strncpy(timestamp[curr], _("Average:"), sizeof(timestamp[curr]));
384 timestamp[curr][sizeof(timestamp[curr]) - 1] = '\0';
385 memcpy(timestamp[!curr], timestamp[curr], sizeof(timestamp[!curr]));
388 TEST_STDOUT(STDOUT_FILENO);
390 for (i = 0; i < NR_ACT; i++) {
392 if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
395 if (IS_SELECTED(act[i]->options) && (act[i]->nr[curr] > 0)) {
396 /* Display current average activity statistics */
397 (*act[i]->f_print_avg)(act[i], 2, curr, itv);
401 if (read_from_file) {
403 * Reset number of lines printed only if we read stats
404 * from a system activity file.
411 ***************************************************************************
412 * Print system statistics.
413 * This is called when we read stats either from a file or from sadc.
416 * @curr Index in array for current sample statistics.
417 * @read_from_file Set to TRUE if stats are read from a system activity
419 * @use_tm_start Set to TRUE if option -s has been used.
420 * @use_tm_end Set to TRUE if option -e has been used.
421 * @reset Set to TRUE if last_uptime variable should be
422 * reinitialized (used in next_slice() function).
423 * @act_id Activity that can be displayed or ~0 for all.
424 * Remember that when reading stats from a file, only
425 * one activity can be displayed at a time.
426 * @reset_cd TRUE if static cross_day variable should be reset
430 * @cnt Number of remaining lines to display.
433 * 1 if stats have been successfully displayed, and 0 otherwise.
434 ***************************************************************************
436 int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start,
437 int use_tm_end, int reset, unsigned int act_id, int reset_cd)
439 int i, prev_hour, rc = 0;
440 unsigned long long itv;
441 static int cross_day = FALSE;
445 * cross_day is a static variable that is set to 1 when the first
446 * record of stats from a new day is read from a unique data file
447 * (in the case where the file contains data from two consecutive
448 * days). When set to TRUE, every following records timestamp will
449 * have its hour value increased by 24.
450 * Yet when a new activity (being read from the file) is going to
451 * be displayed, we start reading the file from the beginning
452 * again, and so cross_day should be reset in this case.
458 if (read_from_file && !next_slice(record_hdr[2].uptime_cs, record_hdr[curr].uptime_cs,
460 /* Not close enough to desired interval */
463 /* Get then set previous timestamp */
464 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME, &record_hdr[!curr],
467 prev_hour = rectime.tm_hour;
468 set_record_timestamp_string(flags, &record_hdr[!curr],
469 NULL, timestamp[!curr], TIMESTAMP_LEN, &rectime);
471 /* Get then set current timestamp */
472 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME, &record_hdr[curr],
475 set_record_timestamp_string(flags, &record_hdr[curr],
476 NULL, timestamp[curr], TIMESTAMP_LEN, &rectime);
479 * Check if we are beginning a new day.
480 * Use rectime.tm_hour and prev_hour instead of record_hdr[].hour for comparison
481 * to take into account the current timezone (hours displayed will depend on the
482 * TZ variable value).
484 if (use_tm_start && record_hdr[!curr].ust_time &&
485 (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) &&
486 (rectime.tm_hour < prev_hour)) {
491 if (use_tm_end && (datecmp(&rectime, &tm_end, cross_day) > 0)) {
492 /* End time exceeded */
497 /* Get interval value in 1/100th of a second */
498 get_itv_value(&record_hdr[curr], &record_hdr[!curr], &itv);
503 TEST_STDOUT(STDOUT_FILENO);
505 for (i = 0; i < NR_ACT; i++) {
507 if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id))
510 if (IS_SELECTED(act[i]->options) && (act[i]->nr[curr] > 0)) {
511 /* Display current activity statistics */
512 (*act[i]->f_print)(act[i], !curr, curr, itv);
521 ***************************************************************************
522 * Display stats since system startup.
525 * @curr Index in array for current sample statistics.
526 ***************************************************************************
528 void write_stats_startup(int curr)
532 /* Set to 0 previous structures corresponding to boot time */
533 memset(&record_hdr[!curr], 0, RECORD_HEADER_SIZE);
534 record_hdr[!curr].record_type = R_STATS;
535 record_hdr[!curr].hour = record_hdr[curr].hour;
536 record_hdr[!curr].minute = record_hdr[curr].minute;
537 record_hdr[!curr].second = record_hdr[curr].second;
538 record_hdr[!curr].ust_time = record_hdr[curr].ust_time;
540 for (i = 0; i < NR_ACT; i++) {
541 if (IS_SELECTED(act[i]->options) && (act[i]->nr[curr] > 0)) {
543 * Using nr[curr] and not nr[!curr] below because we initialize
544 * reference structures for each structure that has been
545 * currently read in memory.
546 * No problem with buffers allocation since they all have the
549 memset(act[i]->buf[!curr], 0,
550 (size_t) act[i]->msize * (size_t) act[i]->nr[curr] * (size_t) act[i]->nr2);
554 flags |= S_F_SINCE_BOOT;
557 write_stats(curr, USE_SADC, &count, NO_TM_START, NO_TM_END, NO_RESET,
558 ALL_ACTIVITIES, TRUE);
564 ***************************************************************************
565 * Read data sent by the data collector.
568 * @size Number of bytes of data to read.
571 * @buffer Buffer where data will be saved.
574 * 0 if all the data have been successfully read.
575 * Otherwise, return the number of bytes left to be read.
576 ***************************************************************************
578 size_t sa_read(void *buffer, size_t size)
584 if ((n = read(STDIN_FILENO, buffer, size)) < 0) {
590 return size; /* EOF */
593 buffer = (char *) buffer + n;
600 ***************************************************************************
601 * Display a restart message (contents of a R_RESTART record).
604 * @tab Number of tabulations (unused here).
605 * @action Action expected from current function (unused here).
606 * @cur_date Date string of current restart message (unused here).
607 * @cur_time Time string of current restart message.
608 * @utc True if @cur_time is expressed in UTC (unused here).
609 * @file_hdr System activity file standard header.
610 * @record_hdr Current record header (unused here).
611 ***************************************************************************
613 __printf_funct_t print_sar_restart(int *tab, int action, char *cur_date, char *cur_time,
614 int utc, struct file_header *file_hdr,
615 struct record_header *record_hdr)
619 printf("\n%-11s", cur_time);
620 sprintf(restart, " LINUX RESTART\t(%d CPU)\n",
621 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1);
622 cprintf_s(IS_RESTART, "%s", restart);
627 ***************************************************************************
628 * Display a comment (contents of R_COMMENT record).
631 * @tab Number of tabulations (unused here).
632 * @action Action expected from current function (unused here).
633 * @cur_date Date string of current comment (unused here).
634 * @cur_time Time string of current comment.
635 * @utc True if @cur_time is expressed in UTC (unused here).
636 * @comment Comment to display.
637 * @file_hdr System activity file standard header (unused here).
638 * @record_hdr Current record header (unused here).
639 ***************************************************************************
641 __print_funct_t print_sar_comment(int *tab, int action, char *cur_date, char *cur_time, int utc,
642 char *comment, struct file_header *file_hdr,
643 struct record_header *record_hdr)
645 printf("%-11s", cur_time);
646 cprintf_s(IS_COMMENT, " COM %s\n", comment);
650 ***************************************************************************
651 * Read the various statistics sent by the data collector (sadc).
654 * @curr Index in array for current sample statistics.
655 ***************************************************************************
657 void read_sadc_stat_bunch(int curr)
661 /* Read record header (type is always R_STATS since it is read from sadc) */
662 if (sa_read(&record_hdr[curr], RECORD_HEADER_SIZE)) {
664 * SIGINT (sent by sadc) is likely to be received
665 * while we are stuck in sa_read().
666 * If this happens then no data have to be read.
672 fprintf(stderr, "%s: Record header\n", __FUNCTION__);
674 print_read_error(END_OF_DATA_UNEXPECTED);
677 for (i = 0; i < NR_ACT; i++) {
681 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
683 if (HAS_COUNT_FUNCTION(act[p]->options)) {
684 if (sa_read(&(act[p]->nr[curr]), sizeof(__nr_t))) {
686 fprintf(stderr, "%s: Nb of items\n", __FUNCTION__);
688 print_read_error(END_OF_DATA_UNEXPECTED);
690 if ((act[p]->nr[curr] > act[p]->nr_max) || (act[p]->nr[curr] < 0)) {
692 fprintf(stderr, "%s: %s: nr=%d nr_max=%d\n",
693 __FUNCTION__, act[p]->name, act[p]->nr[curr], act[p]->nr_max);
695 print_read_error(INCONSISTENT_INPUT_DATA);
697 if (act[p]->nr[curr] > act[p]->nr_allocated) {
698 reallocate_all_buffers(act[p], act[p]->nr[curr]);
702 * For persistent activities, we must make sure that no statistics
703 * from a previous iteration remain, especially if the number
704 * of structures read is smaller than @nr_ini.
706 if (HAS_PERSISTENT_VALUES(act[p]->options)) {
707 memset(act[p]->buf[curr], 0,
708 (size_t) act[p]->fsize * (size_t) act[p]->nr_ini * (size_t) act[p]->nr2);
711 if (sa_read(act[p]->buf[curr],
712 (size_t) act[p]->fsize * (size_t) act[p]->nr[curr] * (size_t) act[p]->nr2)) {
714 fprintf(stderr, "%s: Statistics\n", __FUNCTION__);
716 print_read_error(END_OF_DATA_UNEXPECTED);
722 ***************************************************************************
723 * Read current activity's statistics (located between two consecutive
724 * LINUX RESTART messages) from file and display them.
727 * @ifd Input file descriptor.
728 * @fpos Position in file where reading must start.
729 * @curr Index in array for current sample statistics.
730 * @rows Number of rows of screen.
731 * @act_id Activity to display.
732 * @file_actlst List of activities in file.
733 * @file Name of file being read.
734 * @file_magic file_magic structure filled with file magic header data.
735 * @rec_hdr_tmp Temporary buffer where current record header will be saved.
737 * TRUE if file's data don't match current machine's endianness.
738 * @arch_64 TRUE if file's data come from a 64 bit machine.
739 * @b_size Size of @rec_hdr_tmp buffer.
742 * @curr Index in array for next sample statistics.
743 * @cnt Number of remaining lines of stats to write.
744 * @eosaf Set to TRUE if EOF (end of file) has been reached.
745 * @reset Set to TRUE if last_uptime variable should be reinitialized
746 * (used in next_slice() function).
747 ***************************************************************************
749 void handle_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf,
750 int rows, unsigned int act_id, int *reset,
751 struct file_activity *file_actlst, char *file,
752 struct file_magic *file_magic, void *rec_hdr_tmp,
753 int endian_mismatch, int arch_64, size_t b_size)
756 unsigned long lines = 0;
758 int davg = 0, next, inc = 0;
760 if (lseek(ifd, fpos, SEEK_SET) < fpos) {
766 * Restore the first stats collected.
767 * Used to compute the rate displayed on the first line.
769 copy_structures(act, id_seq, record_hdr, !*curr, 2);
773 /* Assess number of lines printed when a bitmap is used */
774 p = get_activity_position(act, act_id, EXIT_IF_NOT_FOUND);
775 if (act[p]->bitmap) {
776 inc = count_bits(act[p]->bitmap->b_array,
777 BITMAP_SIZE(act[p]->bitmap->b_size));
783 * Display <count> lines of stats.
784 * Start with reading current sample's record header.
786 *eosaf = read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[*curr],
787 &file_hdr, arch_64, endian_mismatch, UEOF_STOP, b_size,
789 rtype = record_hdr[*curr].record_type;
791 if ((lines >= rows) || !lines) {
798 if (*eosaf || (rtype == R_RESTART))
799 /* This is EOF or we have met a LINUX RESTART record: Stop now */
802 if (rtype != R_COMMENT) {
803 /* Read the extra fields since it's not a special record */
804 if (read_file_stat_bunch(act, *curr, ifd, file_hdr.sa_act_nr, file_actlst,
805 endian_mismatch, arch_64, file, file_magic, UEOF_STOP))
806 /* Error or unexpected EOF */
810 /* Display comment */
811 next = print_special_record(&record_hdr[*curr], flags + S_F_LOCAL_TIME,
812 &tm_start, &tm_end, R_COMMENT, ifd,
814 file_magic, &file_hdr, act, &sar_fmt,
815 endian_mismatch, arch_64);
818 * A line of comment was actually displayed: Count it in the
819 * total number of displayed lines.
820 * If no lines of stats had been previously displayed, ignore it
821 * to make sure the header line will be displayed.
828 /* next is set to 1 when we were close enough to desired interval */
829 next = write_stats(*curr, USE_SA_FILE, cnt, tm_start.use, tm_end.use,
830 *reset, act_id, reset_cd);
832 if (next && (*cnt > 0)) {
844 lines += act[p]->nr[*curr];
852 * At this moment, if we had a R_RESTART record, we still haven't read
853 * the number of CPU following it (nor the possible extra structures).
854 * But in this case, we always have @cnt != 0.
858 write_stats_avg(!*curr, USE_SA_FILE, act_id);
865 ***************************************************************************
866 * Read header data sent by sadc.
867 ***************************************************************************
869 void read_header_data(void)
871 struct file_magic file_magic;
872 struct file_activity file_act;
876 /* Read magic header */
877 rc = sa_read(&file_magic, FILE_MAGIC_SIZE);
879 sprintf(version, "%d.%d.%d.%d",
880 file_magic.sysstat_version,
881 file_magic.sysstat_patchlevel,
882 file_magic.sysstat_sublevel,
883 file_magic.sysstat_extraversion);
884 if (!file_magic.sysstat_extraversion) {
885 version[strlen(version) - 2] = '\0';
888 if (rc || (file_magic.sysstat_magic != SYSSTAT_MAGIC) ||
889 (file_magic.format_magic != FORMAT_MAGIC) ||
890 strcmp(version, VERSION)) {
892 /* sar and sadc commands are not consistent */
893 if (!rc && (file_magic.sysstat_magic == SYSSTAT_MAGIC)) {
895 _("Using a wrong data collector from a different sysstat version\n"));
899 fprintf(stderr, "%s: sysstat_magic=%x format_magic=%x version=%s\n",
900 __FUNCTION__, file_magic.sysstat_magic, file_magic.format_magic, version);
902 if (rc == FILE_MAGIC_SIZE) {
904 * No data (0 byte) have been sent by sadc.
905 * This is probably because no activities have been collected
906 * ("Requested activities not available"). In this case, don't
907 * display an error message: Exit now.
911 print_read_error(INCONSISTENT_INPUT_DATA);
916 * No need to take into account file_magic.header_size. We are sure that
917 * sadc and sar are from the same version (we have checked FORMAT_MAGIC
918 * but also VERSION above) and thus the size of file_header is FILE_HEADER_SIZE.
920 if (sa_read(&file_hdr, FILE_HEADER_SIZE)) {
922 fprintf(stderr, "%s: File header\n", __FUNCTION__);
924 print_read_error(END_OF_DATA_UNEXPECTED);
927 /* All activities are not necessarily selected, but NR_ACT is a max */
928 if (file_hdr.sa_act_nr > NR_ACT) {
930 fprintf(stderr, "%s: sa_act_nr=%d\n", __FUNCTION__, file_hdr.sa_act_nr);
932 print_read_error(INCONSISTENT_INPUT_DATA);
935 if ((file_hdr.act_size != FILE_ACTIVITY_SIZE) ||
936 (file_hdr.rec_size != RECORD_HEADER_SIZE)) {
938 fprintf(stderr, "%s: act_size=%u/%zu rec_size=%u/%zu\n", __FUNCTION__,
939 file_hdr.act_size, FILE_ACTIVITY_SIZE, file_hdr.rec_size, RECORD_HEADER_SIZE);
941 print_read_error(INCONSISTENT_INPUT_DATA);
944 /* Read activity list */
945 for (i = 0; i < file_hdr.sa_act_nr; i++) {
947 if (sa_read(&file_act, FILE_ACTIVITY_SIZE)) {
949 fprintf(stderr, "%s: File activity (%d)\n", __FUNCTION__, i);
951 print_read_error(END_OF_DATA_UNEXPECTED);
954 p = get_activity_position(act, file_act.id, RESUME_IF_NOT_FOUND);
956 if ((p < 0) || (act[p]->fsize != file_act.size)
957 || (act[p]->gtypes_nr[0] != file_act.types_nr[0])
958 || (act[p]->gtypes_nr[1] != file_act.types_nr[1])
959 || (act[p]->gtypes_nr[2] != file_act.types_nr[2])
960 || (file_act.nr <= 0)
961 || (file_act.nr2 <= 0)
962 || (act[p]->magic != file_act.magic)) {
965 fprintf(stderr, "%s: p=%d\n", __FUNCTION__, p);
968 fprintf(stderr, "%s: %s: size=%d/%d magic=%x/%x nr=%d nr2=%d types=%d,%d,%d/%d,%d,%d\n",
969 __FUNCTION__, act[p]->name, act[p]->fsize, file_act.size,
970 act[p]->magic, file_act.magic, file_act.nr, file_act.nr2,
971 act[p]->gtypes_nr[0], act[p]->gtypes_nr[1], act[p]->gtypes_nr[2],
972 file_act.types_nr[0], file_act.types_nr[1], file_act.types_nr[2]);
975 /* Remember that we are reading data from sadc and not from a file... */
976 print_read_error(INCONSISTENT_INPUT_DATA);
979 id_seq[i] = file_act.id; /* We necessarily have "i < NR_ACT" */
980 act[p]->nr_ini = file_act.nr;
981 act[p]->nr2 = file_act.nr2;
988 /* Check that all selected activties are actually sent by sadc */
989 reverse_check_act(file_hdr.sa_act_nr);
995 ***************************************************************************
996 * Read statistics from a system activity data file.
999 * @from_file Input file name.
1000 ***************************************************************************
1002 void read_stats_from_file(char from_file[])
1004 struct file_magic file_magic;
1005 struct file_activity *file_actlst = NULL;
1006 char rec_hdr_tmp[MAX_RECORD_HEADER_SIZE];
1009 int rows, eosaf = TRUE, reset = FALSE;
1013 /* Get window size */
1014 rows = get_win_height();
1016 /* Read file headers and activity list */
1017 check_file_actlst(&ifd, from_file, act, flags, &file_magic, &file_hdr,
1018 &file_actlst, id_seq, &endian_mismatch, &arch_64);
1020 /* Perform required allocations */
1021 allocate_structures(act);
1023 /* Print report header */
1024 print_report_hdr(flags, &rectime, &file_hdr);
1026 /* Read system statistics from file */
1029 * If this record is a special (RESTART or COMMENT) one, print it and
1030 * (try to) get another one.
1033 if (read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[0], &file_hdr,
1034 arch_64, endian_mismatch, UEOF_STOP, sizeof(rec_hdr_tmp), flags, &sar_fmt)) {
1035 /* End of sa data file */
1039 rtype = record_hdr[0].record_type;
1040 if ((rtype == R_RESTART) || (rtype == R_COMMENT)) {
1041 print_special_record(&record_hdr[0], flags + S_F_LOCAL_TIME,
1042 &tm_start, &tm_end, rtype, ifd,
1043 &rectime, from_file, 0, &file_magic,
1044 &file_hdr, act, &sar_fmt, endian_mismatch, arch_64);
1048 * OK: Previous record was not a special one.
1049 * So read now the extra fields.
1051 if (read_file_stat_bunch(act, 0, ifd, file_hdr.sa_act_nr,
1052 file_actlst, endian_mismatch, arch_64,
1053 from_file, &file_magic, UEOF_STOP))
1054 /* Possible unexpected EOF */
1057 if (sa_get_record_timestamp_struct(flags + S_F_LOCAL_TIME,
1058 &record_hdr[0], &rectime))
1060 * An error was detected.
1061 * The timestamp hasn't been updated.
1066 while ((rtype == R_RESTART) || (rtype == R_COMMENT) ||
1067 (tm_start.use && (datecmp(&rectime, &tm_start, FALSE) < 0)) ||
1068 (tm_end.use && (datecmp(&rectime, &tm_end, FALSE) >= 0)));
1070 /* Save the first stats collected. Will be used to compute the average */
1071 copy_structures(act, id_seq, record_hdr, 2, 0);
1073 reset = TRUE; /* Set flag to reset last_uptime variable */
1075 /* Save current file position */
1076 if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) {
1082 * Read and write stats located between two possible Linux restarts.
1083 * Activities that should be displayed are saved in id_seq[] array.
1084 * Since we are reading from a file, we print all the stats for an
1085 * activity before displaying the next activity.
1086 * id_seq[] has been created in check_file_actlst(), retaining only
1087 * activities known by current sysstat version.
1089 for (i = 0; i < NR_ACT; i++) {
1094 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1095 if (!IS_SELECTED(act[p]->options))
1098 if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) {
1099 handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, rows,
1100 act[p]->id, &reset, file_actlst,
1101 from_file, &file_magic, rec_hdr_tmp,
1102 endian_mismatch, arch_64, sizeof(rec_hdr_tmp));
1105 unsigned int optf, msk;
1107 optf = act[p]->opt_flags;
1109 for (msk = 1; msk < 0x100; msk <<= 1) {
1110 if ((act[p]->opt_flags & 0xff) & msk) {
1111 act[p]->opt_flags &= (0xffffff00 + msk);
1113 handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf,
1114 rows, act[p]->id, &reset, file_actlst,
1115 from_file, &file_magic, rec_hdr_tmp,
1116 endian_mismatch, arch_64, sizeof(rec_hdr_tmp));
1117 act[p]->opt_flags = optf;
1124 * Go to next Linux restart, if possible.
1125 * Note: If we have @cnt == 0 then the last record we read was not a R_RESTART one
1126 * (else we would have had @cnt != 0, i.e. we would have stopped reading previous activity
1127 * because such a R_RESTART record would have been read, not because all the <count> lines
1128 * had been printed).
1129 * Remember @cnt is decremented only when a real line of stats have been displayed
1130 * (not when a special record has been read).
1133 /* Read next record header */
1134 eosaf = read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[curr],
1135 &file_hdr, arch_64, endian_mismatch, UEOF_STOP, sizeof(rec_hdr_tmp), flags, &sar_fmt);
1136 rtype = record_hdr[curr].record_type;
1138 if (eosaf || (rtype == R_RESTART))
1141 if (rtype != R_COMMENT) {
1142 if (read_file_stat_bunch(act, curr, ifd, file_hdr.sa_act_nr,
1143 file_actlst, endian_mismatch, arch_64,
1144 from_file, &file_magic, UEOF_STOP))
1145 /* Possible unexpected EOF */
1149 /* This was a COMMENT record: Print it */
1150 print_special_record(&record_hdr[curr], flags + S_F_LOCAL_TIME,
1151 &tm_start, &tm_end, R_COMMENT, ifd,
1152 &rectime, from_file, 0,
1153 &file_magic, &file_hdr, act, &sar_fmt,
1154 endian_mismatch, arch_64);
1160 /* The last record we read was a RESTART one: Print it */
1161 if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) {
1162 print_special_record(&record_hdr[curr], flags + S_F_LOCAL_TIME,
1163 &tm_start, &tm_end, R_RESTART, ifd,
1164 &rectime, from_file, 0,
1165 &file_magic, &file_hdr, act, &sar_fmt,
1166 endian_mismatch, arch_64);
1177 ***************************************************************************
1178 * Read statistics sent by sadc, the data collector.
1179 ***************************************************************************
1181 void read_stats(void)
1184 unsigned long lines;
1188 /* Don't buffer data if redirected to a pipe... */
1189 setbuf(stdout, NULL);
1191 /* Read stats header */
1194 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1195 /* Requested activities not available: Exit */
1196 print_collect_error();
1199 /* Determine if a stat line header has to be displayed */
1200 dis_hdr = check_line_hdr();
1202 lines = rows = get_win_height();
1204 /* Perform required allocations */
1205 allocate_structures(act);
1207 /* Print report header */
1208 print_report_hdr(flags, &rectime, &file_hdr);
1210 /* Read system statistics sent by the data collector */
1211 read_sadc_stat_bunch(0);
1214 /* Display stats since boot time and exit */
1215 write_stats_startup(0);
1218 /* Save the first stats collected. Will be used to compute the average */
1219 copy_structures(act, id_seq, record_hdr, 2, 0);
1221 /* Set a handler for SIGINT */
1222 memset(&int_act, 0, sizeof(int_act));
1223 int_act.sa_handler = int_handler;
1224 int_act.sa_flags = SA_RESTART;
1225 sigaction(SIGINT, &int_act, NULL);
1231 read_sadc_stat_bunch(curr);
1232 if (sigint_caught) {
1234 * SIGINT signal caught (it is sent by sadc).
1235 * => Display average stats.
1237 curr ^= 1; /* No data retrieved from last read */
1243 dish = lines / rows;
1249 write_stats(curr, USE_SADC, &count, NO_TM_START, tm_end.use,
1250 NO_RESET, ALL_ACTIVITIES, TRUE);
1252 if (record_hdr[curr].record_type == R_LAST_STATS) {
1253 /* File rotation is happening: Re-read header data sent by sadc */
1255 allocate_structures(act);
1268 * Print statistics average.
1269 * At least one line of stats must have been displayed for this.
1270 * (There may be no lines at all if we press Ctrl/C immediately).
1274 write_stats_avg(curr, USE_SADC, ALL_ACTIVITIES);
1279 ***************************************************************************
1280 * Main entry to the sar program.
1281 ***************************************************************************
1283 int main(int argc, char **argv)
1285 int i, rc, opt = 1, args_idx = 1, p, q;
1288 char from_file[MAX_FILE_LEN], to_file[MAX_FILE_LEN];
1291 /* Compute page shift in kB */
1294 from_file[0] = to_file[0] = '\0';
1297 /* Init National Language Support */
1301 tm_start.use = tm_end.use = FALSE;
1303 /* Allocate and init activity bitmaps */
1304 allocate_bitmaps(act);
1308 /* Process options */
1309 while (opt < argc) {
1311 if (!strcmp(argv[opt], "--sadc")) {
1316 else if (!strncmp(argv[opt], "--dev=", 6)) {
1317 /* Parse devices entered on the command line */
1318 p = get_activity_position(act, A_DISK, EXIT_IF_NOT_FOUND);
1319 parse_sa_devices(argv[opt], act[p], MAX_DEV_LEN, &opt, 6, NO_RANGE);
1322 else if (!strncmp(argv[opt], "--fs=", 5)) {
1323 /* Parse devices entered on the command line */
1324 p = get_activity_position(act, A_FS, EXIT_IF_NOT_FOUND);
1325 parse_sa_devices(argv[opt], act[p], MAX_FS_LEN, &opt, 5, NO_RANGE);
1328 else if (!strncmp(argv[opt], "--iface=", 8)) {
1329 /* Parse devices entered on the command line */
1330 p = get_activity_position(act, A_NET_DEV, EXIT_IF_NOT_FOUND);
1331 parse_sa_devices(argv[opt], act[p], MAX_IFACE_LEN, &opt, 8, NO_RANGE);
1332 q = get_activity_position(act, A_NET_EDEV, EXIT_IF_NOT_FOUND);
1333 act[q]->item_list = act[p]->item_list;
1334 act[q]->item_list_sz = act[p]->item_list_sz;
1335 act[q]->options |= AO_LIST_ON_CMDLINE;
1338 else if (!strncmp(argv[opt], "--int=", 6)) {
1339 /* Parse interrupts names entered on the command line */
1340 p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
1341 parse_sa_devices(argv[opt], act[p], MAX_SA_IRQ_LEN, &opt, 6, NR_IRQS);
1344 else if (!strcmp(argv[opt], "--help")) {
1345 /* Display help message */
1346 display_help(argv[0]);
1349 else if (!strcmp(argv[opt], "--human")) {
1350 /* Display sizes in a human readable format */
1355 else if (!strcmp(argv[opt], "--pretty")) {
1356 /* Display an easy-to-read report */
1357 flags |= S_F_PRETTY;
1361 else if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
1362 /* Get number of decimal places */
1363 dplaces_nr = atoi(argv[opt] + 6);
1364 if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
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 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);