2 * sar and sadf common routines.
3 * (C) 1999-2023 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 ***************************************************************************
28 #include <unistd.h> /* For STDOUT_FILENO, among others */
33 #include <sys/types.h>
44 #define _(string) gettext(string)
46 #define _(string) (string)
49 int default_file_used = FALSE;
50 extern struct act_bitmap cpu_bitmap;
51 extern unsigned int dm_major;
53 unsigned int hdr_types_nr[] = {FILE_HEADER_ULL_NR, FILE_HEADER_UL_NR, FILE_HEADER_U_NR};
54 unsigned int act_types_nr[] = {FILE_ACTIVITY_ULL_NR, FILE_ACTIVITY_UL_NR, FILE_ACTIVITY_U_NR};
55 unsigned int rec_types_nr[] = {RECORD_HEADER_ULL_NR, RECORD_HEADER_UL_NR, RECORD_HEADER_U_NR};
56 unsigned int extra_desc_types_nr[] = {EXTRA_DESC_ULL_NR, EXTRA_DESC_UL_NR, EXTRA_DESC_U_NR};
59 ***************************************************************************
60 * Look for activity in array.
63 * @act Array of activities.
64 * @act_flag Activity flag to look for.
65 * @stop TRUE if sysstat should exit when activity is not found.
68 * Position of activity in array, or -1 if not found (this may happen when
69 * reading data from a system activity file created by another version of
71 ***************************************************************************
73 int get_activity_position(struct activity *act[], unsigned int act_flag, int stop)
77 for (i = 0; i < NR_ACT; i++) {
78 if (act[i]->id == act_flag)
83 PANIC((int) act_flag);
90 ***************************************************************************
91 * Count number of activities with given option.
94 * @act Array of activities.
95 * @option Option that activities should have to be counted
96 * (eg. AO_COLLECTED...)
97 * @count Set to COUNT_OUTPUTS if each output should be counted for
98 * activities with multiple outputs.
101 * Number of selected activities
102 ***************************************************************************
104 int get_activity_nr(struct activity *act[], unsigned int option, enum count_mode count)
109 for (i = 0; i < NR_ACT; i++) {
110 if ((act[i]->options & option) == option) {
112 if (HAS_MULTIPLE_OUTPUTS(act[i]->options) && (count == COUNT_OUTPUTS)) {
113 for (msk = 1; msk < 0x100; msk <<= 1) {
114 if ((act[i]->opt_flags & 0xff) & msk) {
129 ***************************************************************************
130 * Look for the most recent of saDD and saYYYYMMDD to decide which one to
131 * use. If neither exists then use saDD by default.
134 * @sa_dir Directory where standard daily data files are saved.
135 * @rectime Structure containing the current date.
138 * @sa_name 0 to use saDD data files,
139 * 1 to use saYYYYMMDD data files.
140 ***************************************************************************
142 void guess_sa_name(char *sa_dir, struct tm *rectime, int *sa_name)
144 char filename[MAX_FILE_LEN];
149 /* Use saDD by default */
152 /* Look for saYYYYMMDD */
153 snprintf(filename, sizeof(filename),
154 "%s/sa%04d%02d%02d", sa_dir,
155 rectime->tm_year + 1900,
158 filename[sizeof(filename) - 1] = '\0';
160 if (stat(filename, &sb) < 0)
161 /* Cannot find or access saYYYYMMDD, so use saDD */
163 sa_mtime = sb.st_mtime;
164 nsec = sb.st_mtim.tv_nsec;
167 snprintf(filename, sizeof(filename),
170 filename[sizeof(filename) - 1] = '\0';
172 if (stat(filename, &sb) < 0) {
173 /* Cannot find or access saDD, so use saYYYYMMDD */
178 if ((sa_mtime > sb.st_mtime) ||
179 ((sa_mtime == sb.st_mtime) && (nsec > sb.st_mtim.tv_nsec))) {
180 /* saYYYYMMDD is more recent than saDD, so use it */
186 ***************************************************************************
187 * Set current daily data file name.
190 * @datafile If not an empty string then this is the alternate directory
191 * location where daily data files will be saved.
192 * @d_off Day offset (number of days to go back in the past).
193 * @sa_name 0 for saDD data files,
194 * 1 for saYYYYMMDD data files,
195 * -1 if unknown. In this case, will look for the most recent
196 * of saDD and saYYYYMMDD and use it.
199 * @datafile Name of daily data file.
200 ***************************************************************************
202 void set_default_file(char *datafile, int d_off, int sa_name)
204 char sa_dir[MAX_FILE_LEN];
205 struct tm rectime = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL};
208 /* Set directory where daily data files will be saved */
210 strncpy(sa_dir, datafile, sizeof(sa_dir));
213 strncpy(sa_dir, SA_DIR, sizeof(sa_dir));
215 sa_dir[sizeof(sa_dir) - 1] = '\0';
217 get_time(&rectime, d_off);
220 * Look for the most recent of saDD and saYYYYMMDD
221 * and use it. If neither exists then use saDD.
222 * sa_name is set accordingly.
224 guess_sa_name(sa_dir, &rectime, &sa_name);
227 /* Using saYYYYMMDD data files */
228 err = snprintf(datafile, MAX_FILE_LEN,
229 "%s/sa%04d%02d%02d", sa_dir,
230 rectime.tm_year + 1900,
235 /* Using saDD data files */
236 err = snprintf(datafile, MAX_FILE_LEN,
240 datafile[MAX_FILE_LEN - 1] = '\0';
242 if ((err < 0) || (err >= MAX_FILE_LEN)) {
243 fprintf(stderr, "%s: %s\n", __FUNCTION__, datafile);
247 default_file_used = TRUE;
250 fprintf(stderr, "%s: Datafile: %s\n", __FUNCTION__, datafile);
255 ***************************************************************************
256 * Check data file type. If it is a directory then this is the alternate
257 * location where daily data files will be saved.
260 * @datafile Name of the daily data file. May be a directory.
261 * @d_off Day offset (number of days to go back in the past).
262 * @sa_name 0 for saDD data files,
263 * 1 for saYYYYMMDD data files,
264 * -1 if unknown. In this case, will look for the most recent
265 * of saDD and saYYYYMMDD and use it.
269 * @datafile Name of the daily data file. This is now a plain file, not
273 * 1 if @datafile was a directory, and 0 otherwise.
274 ***************************************************************************
276 int check_alt_sa_dir(char *datafile, int d_off, int sa_name)
278 if (check_dir(datafile)) {
280 * This is a directory: So append
281 * the default file name to it.
283 set_default_file(datafile, d_off, sa_name);
291 ***************************************************************************
292 * Display sysstat version used to create system activity data file.
295 * @st Output stream (stderr or stdout).
296 * @file_magic File magic header.
297 ***************************************************************************
299 void display_sa_file_version(FILE *st, struct file_magic *file_magic)
301 fprintf(st, _("File created by sar/sadc from sysstat version %d.%d.%d"),
302 file_magic->sysstat_version,
303 file_magic->sysstat_patchlevel,
304 file_magic->sysstat_sublevel);
306 if (file_magic->sysstat_extraversion) {
307 fprintf(st, ".%d", file_magic->sysstat_extraversion);
313 ***************************************************************************
314 * An invalid system activity file has been opened for reading.
315 * If this file was created by an old version of sysstat, tell it to the
319 * @fd Descriptor of the file that has been opened.
320 * @file_magic file_magic structure filled with file magic header data.
321 * May contain invalid data.
322 * @file Name of the file being read.
323 * @n Number of bytes read while reading file magic header.
324 * This function may also be called after failing to read file
325 * standard header, or if CPU activity has not been found in
326 * file. In this case, n is set to 0.
327 ***************************************************************************
329 void handle_invalid_sa_file(int fd, struct file_magic *file_magic, char *file,
332 fprintf(stderr, _("Invalid system activity file: %s\n"), file);
334 if (n == FILE_MAGIC_SIZE) {
335 if ((file_magic->sysstat_magic == SYSSTAT_MAGIC) || (file_magic->sysstat_magic == SYSSTAT_MAGIC_SWAPPED)) {
336 unsigned short fmt_magic;
338 /* This is a sysstat file, but this file has an old format */
339 display_sa_file_version(stderr, file_magic);
341 fmt_magic = file_magic->sysstat_magic == SYSSTAT_MAGIC ?
342 file_magic->format_magic : __builtin_bswap16(file_magic->format_magic);
344 _("Current sysstat version cannot read the format of this file (%#x)\n"),
346 if (fmt_magic >= FORMAT_MAGIC_2171) {
348 _("Try to convert it to current format. Enter:\n\n"));
349 fprintf(stderr, "sadf -c %s > %s.new\n\n", file, file);
351 _("You should then be able to read the new file created (%s.new)\n"),
362 ***************************************************************************
363 * Display an error message then exit.
364 ***************************************************************************
366 void print_collect_error(void)
368 fprintf(stderr, _("Requested activities not available\n"));
373 ***************************************************************************
374 * Fill system activity file magic header.
377 * @file_magic System activity file magic header.
378 ***************************************************************************
380 void enum_version_nr(struct file_magic *fm)
385 fm->sysstat_extraversion = 0;
387 strcpy(version, VERSION);
389 /* Get version number */
390 if ((v = strtok(version, ".")) == NULL)
392 fm->sysstat_version = atoi(v) & 0xff;
394 /* Get patchlevel number */
395 if ((v = strtok(NULL, ".")) == NULL)
397 fm->sysstat_patchlevel = atoi(v) & 0xff;
399 /* Get sublevel number */
400 if ((v = strtok(NULL, ".")) == NULL)
402 fm->sysstat_sublevel = atoi(v) & 0xff;
404 /* Get extraversion number. Don't necessarily exist */
405 if ((v = strtok(NULL, ".")) == NULL)
407 fm->sysstat_extraversion = atoi(v) & 0xff;
411 ***************************************************************************
412 * Write data to file. If the write() call was interrupted by a signal, try
413 * again so that the whole buffer can be written.
416 * @fd Output file descriptor.
418 * @nr_bytes Number of bytes to write.
421 * Number of bytes written to file, or -1 on error.
422 ***************************************************************************
424 int write_all(int fd, const void *buf, int nr_bytes)
426 int block, offset = 0;
427 char *buffer = (char *) buf;
429 while (nr_bytes > 0) {
431 block = write(fd, &buffer[offset], nr_bytes);
450 ***************************************************************************
451 * Allocate structures.
454 * @act Array of activities.
455 ***************************************************************************
457 void allocate_structures(struct activity *act[])
461 for (i = 0; i < NR_ACT; i++) {
463 if (act[i]->nr_ini > 0) {
465 /* Look for a possible overflow */
466 check_overflow((unsigned int) act[i]->msize,
467 (unsigned int) act[i]->nr_ini,
468 (unsigned int) act[i]->nr2);
470 for (j = 0; j < 3; j++) {
471 SREALLOC(act[i]->buf[j], void,
472 (size_t) act[i]->msize * (size_t) act[i]->nr_ini * (size_t) act[i]->nr2);
474 act[i]->nr_allocated = act[i]->nr_ini;
480 ***************************************************************************
484 * @act Array of activities.
485 ***************************************************************************
487 void free_structures(struct activity *act[])
491 for (i = 0; i < NR_ACT; i++) {
492 if (act[i]->nr_allocated > 0) {
493 for (j = 0; j < 3; j++) {
494 if (act[i]->buf[j]) {
495 free(act[i]->buf[j]);
496 act[i]->buf[j] = NULL;
499 act[i]->nr_allocated = 0;
505 ***************************************************************************
506 * Reallocate all the buffers for a given activity.
509 * @a Activity whose buffers need to be reallocated.
510 * @nr_min Minimum number of items that the new buffers should be able
512 ***************************************************************************
514 void reallocate_all_buffers(struct activity *a, __nr_t nr_min)
522 if (!a->nr_allocated) {
526 nr_realloc = a->nr_allocated;
528 nr_realloc = nr_realloc * 2;
530 while (nr_realloc < nr_min);
533 /* Look for a possible overflow */
534 check_overflow((unsigned int) a->msize, (unsigned int) nr_realloc,
535 (unsigned int) a->nr2);
537 for (j = 0; j < 3; j++) {
538 SREALLOC(a->buf[j], void,
539 (size_t) a->msize * nr_realloc * (size_t) a->nr2);
540 /* Init additional space which has been allocated */
541 if (a->nr_allocated) {
542 memset((char *) a->buf[j] + a->msize * a->nr_allocated * a->nr2, 0,
543 (size_t) a->msize * (size_t) (nr_realloc - a->nr_allocated) * (size_t) a->nr2);
547 a->nr_allocated = nr_realloc;
551 ***************************************************************************
552 * Check if we are close enough to desired interval.
555 * @uptime_ref Uptime used as reference. This is the system uptime for the
556 * first sample statistics, or the first system uptime after a
557 * LINUX RESTART (in 1/100th of a second).
558 * @uptime Current system uptime (in 1/100th of a second).
559 * @reset TRUE if @last_uptime should be reset with @uptime_ref.
560 * @interval Interval of time.
563 * TRUE if we are actually close enough to desired interval, FALSE otherwise.
564 ***************************************************************************
566 int next_slice(unsigned long long uptime_ref, unsigned long long uptime,
567 int reset, long interval)
569 unsigned long file_interval, entry;
570 static unsigned long long last_uptime = 0;
571 int min, max, pt1, pt2;
574 /* uptime is expressed in 1/100th of a second */
575 if (!last_uptime || reset) {
576 last_uptime = uptime_ref;
579 /* Interval cannot be greater than 0xffffffff here */
580 f = ((double) ((uptime - last_uptime) & 0xffffffff)) / 100;
581 file_interval = (unsigned long) f;
582 if ((f * 10) - (file_interval * 10) >= 5) {
583 file_interval++; /* Rounding to correct value */
586 last_uptime = uptime;
589 /* Smallest time interval: Always close enough to desired interval */
593 * A few notes about the "algorithm" used here to display selected entries
594 * from the system activity file (option -f with -i flag):
595 * Let Iu be the interval value given by the user on the command line,
596 * In the interval between current and previous sample,
597 * and En the current sample (identified by its time stamp) in the file.
598 * En will ne displayed if there is an integer p so that:
599 * p * Iu belongs to [En - In/2, En + In/2[.
601 f = ((double) ((uptime - uptime_ref) & 0xffffffff)) / 100;
602 entry = (unsigned long) f;
603 if ((f * 10) - (entry * 10) >= 5) {
607 min = entry - (file_interval / 2);
608 max = entry + (file_interval / 2) + (file_interval & 0x1);
609 pt1 = (entry / interval) * interval;
610 pt2 = ((entry / interval) + 1) * interval;
612 return (((pt1 >= min) && (pt1 < max)) || ((pt2 >= min) && (pt2 < max)));
616 ***************************************************************************
617 * Use time stamp to fill tstamp_ext structure.
620 * @timestamp Timestamp to decode (format: HH:MM:SS).
623 * @tse Structure containing the decoded timestamp.
626 * 0 if the timestamp has been successfully decoded, 1 otherwise.
627 ***************************************************************************
629 int decode_timestamp(char timestamp[], struct tstamp_ext *tse)
631 timestamp[2] = timestamp[5] = '\0';
633 if ((strspn(timestamp, DIGITS) != 2) ||
634 (strspn(×tamp[3], DIGITS) != 2) ||
635 (strspn(×tamp[6], DIGITS) != 2))
638 tse->tm_time.tm_sec = atoi(×tamp[6]);
639 tse->tm_time.tm_min = atoi(×tamp[3]);
640 tse->tm_time.tm_hour = atoi(timestamp);
642 if ((tse->tm_time.tm_sec < 0) || (tse->tm_time.tm_sec > 59) ||
643 (tse->tm_time.tm_min < 0) || (tse->tm_time.tm_min > 59) ||
644 (tse->tm_time.tm_hour < 0) || (tse->tm_time.tm_hour > 23)) {
649 tse->use = USE_HHMMSS_T;
655 ***************************************************************************
656 * Use time stamp to fill tstamp_ext structure.
659 * @timestamp Epoch time to decode (format: number of seconds since
660 * Januray 1st 1970 00:00:00 UTC).
661 * @flags Flags for common options and system state.
664 * @tse Structure containing the decoded epoch time.
667 * 0 if the epoch time has been successfully decoded, 1 otherwise.
668 ***************************************************************************
670 int decode_epoch(char timestamp[], struct tstamp_ext *tse, uint64_t flags)
672 tse->epoch_time = atol(timestamp);
674 if (!tse->epoch_time) {
679 tse->use = USE_EPOCH_T;
685 ***************************************************************************
686 * Compare two timestamps.
689 * @rectime Date and time for current sample.
690 * @tse Timestamp used as reference.
691 * @cross_day TRUE if a new day has been started.
694 * A positive value if @rectime is greater than @tse,
695 * a negative one otherwise.
696 * Also returns 0 if no valid time is saved in @tse.
697 ***************************************************************************
699 int datecmp(struct tstamp_ext *rectime, struct tstamp_ext *tse, int cross_day)
707 * This is necessary if we want to properly handle something like:
708 * sar -s time_start -e time_end with
709 * time_start(day D) > time_end(day D+1)
711 tm_hour = rectime->tm_time.tm_hour + (24 * (cross_day != 0));
713 if (tm_hour == tse->tm_time.tm_hour) {
714 if (rectime->tm_time.tm_min == tse->tm_time.tm_min)
715 return (rectime->tm_time.tm_sec - tse->tm_time.tm_sec);
717 return (rectime->tm_time.tm_min - tse->tm_time.tm_min);
720 return (tm_hour - tse->tm_time.tm_hour);
723 return (rectime->epoch_time - tse->epoch_time);
725 default: /* NO_TIME */
731 ***************************************************************************
732 * Parse a timestamp entered on the command line (hh:mm[:ss] or number of
733 * seconds since the Epoch) and decode it.
736 * @argv Arguments list.
737 * @opt Index in the arguments list.
738 * @def_timestamp Default timestamp to use.
739 * @flags Flags for common options and system state.
742 * @tse Structure containing the decoded timestamp.
745 * 0 if the timestamp has been successfully decoded, 1 otherwise.
746 ***************************************************************************
748 int parse_timestamp(char *argv[], int *opt, struct tstamp_ext *tse,
749 const char *def_timestamp, uint64_t flags)
754 if (argv[++(*opt)] && strncmp(argv[*opt], "-", 1)) {
755 switch (strlen(argv[*opt])) {
758 if (argv[*opt][2] != ':')
760 strncpy(timestamp, argv[(*opt)++], 5);
762 strcat(timestamp, ":00");
767 if ((argv[*opt][2] != ':') || (argv[*opt][5] != ':'))
769 strncpy(timestamp, argv[(*opt)++], 8);
774 if (strspn(argv[*opt], DIGITS) == 10) {
775 /* This is actually a timestamp */
776 strncpy(timestamp, argv[(*opt)++], 10);
777 timestamp[10] = '\0';
779 return decode_epoch(timestamp, tse, flags);
786 strncpy(timestamp, def_timestamp, 8);
790 return decode_timestamp(timestamp, tse);
794 ***************************************************************************
795 * Set interval value.
798 * @record_hdr_curr Record with current sample statistics.
799 * @record_hdr_prev Record with previous sample statistics.
802 * @itv Interval of time in 1/100th of a second.
803 ***************************************************************************
805 void get_itv_value(struct record_header *record_hdr_curr,
806 struct record_header *record_hdr_prev,
807 unsigned long long *itv)
809 /* Interval value in jiffies */
810 *itv = get_interval(record_hdr_prev->uptime_cs,
811 record_hdr_curr->uptime_cs);
815 ***************************************************************************
816 * Fill the tm_time structure with the file's creation date, based on file's
817 * time data saved in file header.
818 * The resulting timestamp is expressed in the locale of the file creator or
819 * in the user's own locale, depending on whether option -t has been used
823 * @flags Flags for common options and system state.
824 * @file_hdr System activity file standard header.
827 * @tm_time Date (and possibly time) from file header. Only the date,
828 * not the time, should be used by the caller.
829 ***************************************************************************
831 void get_file_timestamp_struct(uint64_t flags, struct tm *tm_time,
832 struct file_header *file_hdr)
834 time_t t = file_hdr->sa_ust_time;
836 if (PRINT_TRUE_TIME(flags)) {
837 /* Get local time. This is just to fill fields with a default value. */
838 get_time(tm_time, 0);
840 tm_time->tm_mday = file_hdr->sa_day;
841 tm_time->tm_mon = file_hdr->sa_month;
842 tm_time->tm_year = file_hdr->sa_year;
844 * Call mktime() to set DST (Daylight Saving Time) flag.
845 * Has anyone a better way to do it?
847 tm_time->tm_hour = tm_time->tm_min = tm_time->tm_sec = 0;
851 localtime_r(&t, tm_time);
856 ***************************************************************************
857 * Print report header.
860 * @flags Flags for common options and system state.
861 * @file_hdr System activity file standard header.
864 * @tm_time Date and time from file header.
865 ***************************************************************************
867 void print_report_hdr(uint64_t flags, struct tm *tm_time,
868 struct file_header *file_hdr)
871 /* Get date of file creation */
872 get_file_timestamp_struct(flags, tm_time, file_hdr);
875 * Display the header.
876 * NB: Number of CPU (value in [1, NR_CPUS + 1]).
877 * 1 means that there is only one proc and non SMP kernel.
878 * 2 means one proc and SMP kernel. Etc.
880 print_gal_header(tm_time, file_hdr->sa_sysname, file_hdr->sa_release,
881 file_hdr->sa_nodename, file_hdr->sa_machine,
882 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1,
887 ***************************************************************************
888 * Network interfaces may now be registered (and unregistered) dynamically.
889 * This is what we try to guess here.
892 * @a Activity structure with statistics.
893 * @curr Index in array for current sample statistics.
894 * @ref Index in array for sample statistics used as reference.
895 * @pos Index on current network interface.
898 * Position of current network interface in array of sample statistics used
900 * -1 if it is a new interface (it was not present in array of stats used
902 * -2 if it is a known interface but which has been unregistered then
903 * registered again on the interval.
904 ***************************************************************************
906 int check_net_dev_reg(struct activity *a, int curr, int ref, int pos)
908 struct stats_net_dev *sndc, *sndp;
913 * No items found in previous iteration:
914 * Current interface is necessarily new.
918 if (j >= a->nr[ref]) {
923 sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + pos * a->msize);
926 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + j * a->msize);
928 if (!strcmp(sndc->interface, sndp->interface)) {
930 * Network interface found.
931 * If a counter has decreased, then we may assume that the
932 * corresponding interface was unregistered, then registered again.
934 if ((sndc->rx_packets < sndp->rx_packets) ||
935 (sndc->tx_packets < sndp->tx_packets) ||
936 (sndc->rx_bytes < sndp->rx_bytes) ||
937 (sndc->tx_bytes < sndp->tx_bytes) ||
938 (sndc->rx_compressed < sndp->rx_compressed) ||
939 (sndc->tx_compressed < sndp->tx_compressed) ||
940 (sndc->multicast < sndp->multicast)) {
943 * Special processing for rx_bytes (_packets) and
944 * tx_bytes (_packets) counters: If the number of
945 * bytes (packets) has decreased, whereas the number of
946 * packets (bytes) has increased, then assume that the
947 * relevant counter has met an overflow condition, and that
948 * the interface was not unregistered, which is all the
949 * more plausible that the previous value for the counter
950 * was > ULLONG_MAX/2.
951 * NB: the average value displayed will be wrong in this case...
953 * If such an overflow is detected, just set the flag. There is no
954 * need to handle this in a special way: the difference is still
955 * properly calculated if the result is of the same type (i.e.
956 * unsigned long) as the two values.
960 if ((sndc->rx_bytes < sndp->rx_bytes) &&
961 (sndc->rx_packets > sndp->rx_packets) &&
962 (sndp->rx_bytes > (~0ULL >> 1))) {
965 if ((sndc->tx_bytes < sndp->tx_bytes) &&
966 (sndc->tx_packets > sndp->tx_packets) &&
967 (sndp->tx_bytes > (~0ULL >> 1))) {
970 if ((sndc->rx_packets < sndp->rx_packets) &&
971 (sndc->rx_bytes > sndp->rx_bytes) &&
972 (sndp->rx_packets > (~0ULL >> 1))) {
975 if ((sndc->tx_packets < sndp->tx_packets) &&
976 (sndc->tx_bytes > sndp->tx_bytes) &&
977 (sndp->tx_packets > (~0ULL >> 1))) {
983 * OK: Assume here that the device was
984 * actually unregistered.
990 if (++j >= a->nr[ref]) {
996 /* This is a newly registered interface */
1001 ***************************************************************************
1002 * Network interfaces may now be registered (and unregistered) dynamically.
1003 * This is what we try to guess here.
1006 * @a Activity structure with statistics.
1007 * @curr Index in array for current sample statistics.
1008 * @ref Index in array for sample statistics used as reference.
1009 * @pos Index on current network interface.
1012 * Position of current network interface in array of sample statistics used
1014 * -1 if it is a newly registered interface.
1015 * -2 if it is a known interface but which has been unregistered then
1016 * registered again on the interval.
1017 ***************************************************************************
1019 int check_net_edev_reg(struct activity *a, int curr, int ref, int pos)
1021 struct stats_net_edev *snedc, *snedp;
1026 * No items found in previous iteration:
1027 * Current interface is necessarily new.
1031 if (j >= a->nr[ref]) {
1036 snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + pos * a->msize);
1039 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + j * a->msize);
1041 if (!strcmp(snedc->interface, snedp->interface)) {
1043 * Network interface found.
1044 * If a counter has decreased, then we may assume that the
1045 * corresponding interface was unregistered, then registered again.
1047 if ((snedc->tx_errors < snedp->tx_errors) ||
1048 (snedc->collisions < snedp->collisions) ||
1049 (snedc->rx_dropped < snedp->rx_dropped) ||
1050 (snedc->tx_dropped < snedp->tx_dropped) ||
1051 (snedc->tx_carrier_errors < snedp->tx_carrier_errors) ||
1052 (snedc->rx_frame_errors < snedp->rx_frame_errors) ||
1053 (snedc->rx_fifo_errors < snedp->rx_fifo_errors) ||
1054 (snedc->tx_fifo_errors < snedp->tx_fifo_errors))
1056 * OK: assume here that the device was
1057 * actually unregistered.
1063 if (++j >= a->nr[ref]) {
1069 /* This is a newly registered interface */
1074 ***************************************************************************
1075 * Disks may be registered dynamically (true in /proc/diskstats file).
1076 * This is what we try to guess here.
1079 * @a Activity structure with statistics.
1080 * @curr Index in array for current sample statistics.
1081 * @ref Index in array for sample statistics used as reference.
1082 * @pos Index on current disk.
1085 * Position of current disk in array of sample statistics used as reference
1086 * -1 if it is a newly registered device.
1087 * -2 if it is a known device but which has been unregistered then registered
1088 * again on the interval.
1089 ***************************************************************************
1091 int check_disk_reg(struct activity *a, int curr, int ref, int pos)
1093 struct stats_disk *sdc, *sdp;
1098 * No items found in previous iteration:
1099 * Current interface is necessarily new.
1103 if (j >= a->nr[ref]) {
1108 sdc = (struct stats_disk *) ((char *) a->buf[curr] + pos * a->msize);
1111 sdp = (struct stats_disk *) ((char *) a->buf[ref] + j * a->msize);
1113 if ((sdc->major == sdp->major) &&
1114 (sdc->minor == sdp->minor)) {
1117 * If all the counters have decreased then the likelyhood
1118 * is that the disk has been unregistered and a new disk inserted.
1119 * If only one or two have decreased then the likelyhood
1120 * is that the counter has simply wrapped.
1121 * Don't take into account a counter if its previous value was 0
1122 * (this may be a read-only device, or a kernel that doesn't
1123 * support discard stats yet...)
1125 if ((sdc->nr_ios < sdp->nr_ios) &&
1126 (!sdp->rd_sect || (sdc->rd_sect < sdp->rd_sect)) &&
1127 (!sdp->wr_sect || (sdc->wr_sect < sdp->wr_sect)) &&
1128 (!sdp->dc_sect || (sdc->dc_sect < sdp->dc_sect)))
1129 /* Same device registered again */
1134 if (++j >= a->nr[ref]) {
1140 /* This is a newly registered device */
1145 ***************************************************************************
1146 * Allocate bitmaps for activities that have one.
1149 * @act Array of activities.
1150 ***************************************************************************
1152 void allocate_bitmaps(struct activity *act[])
1156 for (i = 0; i < NR_ACT; i++) {
1158 * If current activity has a bitmap which has not already
1159 * been allocated, then allocate it.
1160 * Note that a same bitmap may be used by several activities.
1162 if (act[i]->bitmap && !act[i]->bitmap->b_array) {
1163 SREALLOC(act[i]->bitmap->b_array, unsigned char,
1164 BITMAP_SIZE(act[i]->bitmap->b_size));
1170 ***************************************************************************
1171 * Free bitmaps for activities that have one.
1174 * @act Array of activities.
1175 ***************************************************************************
1177 void free_bitmaps(struct activity *act[])
1181 for (i = 0; i < NR_ACT; i++) {
1182 if (act[i]->bitmap && act[i]->bitmap->b_array) {
1183 free(act[i]->bitmap->b_array);
1184 /* Set pointer to NULL to prevent it from being freed again */
1185 act[i]->bitmap->b_array = NULL;
1191 ***************************************************************************
1192 * Select all activities, even if they have no associated items.
1195 * @act Array of activities.
1198 * @act Array of activities, all of the being selected.
1199 ***************************************************************************
1201 void select_all_activities(struct activity *act[])
1205 for (i = 0; i < NR_ACT; i++) {
1206 act[i]->options |= AO_SELECTED;
1211 ***************************************************************************
1212 * Select CPU activity if no other activities have been explicitly selected.
1213 * Also select CPU "all" if no other CPU has been selected.
1216 * @act Array of activities.
1219 * @act Array of activities with CPU activity selected if needed.
1220 ***************************************************************************
1222 void select_default_activity(struct activity *act[])
1226 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1228 /* Default is CPU activity... */
1229 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1231 * Yet A_CPU activity may not be available in file
1232 * since the user can choose not to collect it.
1234 act[p]->options |= AO_SELECTED;
1238 * If no CPU's have been selected then select CPU "all".
1239 * cpu_bitmap bitmap may be used by several activities (A_CPU, A_PWR_CPU...)
1241 if (!count_bits(cpu_bitmap.b_array, BITMAP_SIZE(cpu_bitmap.b_size))) {
1242 cpu_bitmap.b_array[0] |= 0x01;
1247 ***************************************************************************
1248 * Swap bytes for every numerical field in structure. Used to convert from
1249 * one endianness type (big-endian or little-endian) to the other.
1252 * @types_nr Number of fields in structure for each following types:
1253 * unsigned long long, unsigned long and int.
1254 * @ps Pointer on structure.
1255 * @is64bit TRUE if data come from a 64-bit machine.
1256 ***************************************************************************
1258 void swap_struct(const unsigned int types_nr[], void *ps, int is64bit)
1264 x = (uint64_t *) ps;
1265 /* For each field of type long long (or double) */
1266 for (i = 0; i < types_nr[0]; i++) {
1267 *x = __builtin_bswap64(*x);
1268 x = (uint64_t *) ((char *) x + ULL_ALIGNMENT_WIDTH);
1272 /* For each field of type long */
1273 for (i = 0; i < types_nr[1]; i++) {
1275 *x = __builtin_bswap64(*x);
1276 x = (uint64_t *) ((char *) x + UL_ALIGNMENT_WIDTH);
1279 *y = __builtin_bswap32(*y);
1280 y = (uint32_t *) ((char *) y + UL_ALIGNMENT_WIDTH);
1287 /* For each field of type int */
1288 for (i = 0; i < types_nr[2]; i++) {
1289 *y = __builtin_bswap32(*y);
1290 y = (uint32_t *) ((char *) y + U_ALIGNMENT_WIDTH);
1295 ***************************************************************************
1296 * Map the fields of a structure containing statistics read from a file to
1297 * those of the structure known by current sysstat version.
1298 * Each structure (either read from file or from current sysstat version)
1299 * is described by 3 values: The number of [unsigned] long long integers,
1300 * the number of [unsigned] long integers following in the structure, and
1301 * last the number of [unsigned] integers.
1302 * We assume that those numbers will *never* decrease with newer sysstat
1306 * @gtypes_nr Structure description as expected for current sysstat version.
1307 * @ftypes_nr Structure description as read from file.
1308 * @ps Pointer on structure containing statistics.
1309 * @f_size Size of the structure containing statistics. This is the
1310 * size of the structure *read from file*.
1311 * @g_size Size of the structure expected by current sysstat version.
1312 * @b_size Size of the buffer pointed by @ps.
1315 * -1 if an error has been encountered, or 0 otherwise.
1316 ***************************************************************************
1318 int remap_struct(const unsigned int gtypes_nr[], const unsigned int ftypes_nr[],
1319 void *ps, unsigned int f_size, unsigned int g_size, size_t b_size)
1325 if (MAP_SIZE(ftypes_nr) > f_size)
1328 /* Remap [unsigned] long fields */
1329 d = gtypes_nr[0] - ftypes_nr[0];
1331 if (ftypes_nr[0] * ULL_ALIGNMENT_WIDTH < ftypes_nr[0])
1335 n = MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH,
1336 g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH);
1337 if ((ftypes_nr[0] * ULL_ALIGNMENT_WIDTH >= b_size) ||
1338 (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH + n > b_size) ||
1339 (ftypes_nr[0] * ULL_ALIGNMENT_WIDTH + n > b_size))
1342 memmove(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH,
1343 ((char *) ps) + ftypes_nr[0] * ULL_ALIGNMENT_WIDTH, n);
1345 memset(((char *) ps) + ftypes_nr[0] * ULL_ALIGNMENT_WIDTH,
1346 0, d * ULL_ALIGNMENT_WIDTH);
1349 /* Remap [unsigned] int fields */
1350 d = gtypes_nr[1] - ftypes_nr[1];
1352 if (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1353 ftypes_nr[1] * UL_ALIGNMENT_WIDTH < ftypes_nr[1])
1357 n = MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH
1358 - ftypes_nr[1] * UL_ALIGNMENT_WIDTH,
1359 g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1360 - gtypes_nr[1] * UL_ALIGNMENT_WIDTH);
1361 if ((gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1362 ftypes_nr[1] * UL_ALIGNMENT_WIDTH >= b_size) ||
1363 (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1364 gtypes_nr[1] * UL_ALIGNMENT_WIDTH + n > b_size) ||
1365 (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1366 ftypes_nr[1] * UL_ALIGNMENT_WIDTH + n > b_size))
1369 memmove(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1370 + gtypes_nr[1] * UL_ALIGNMENT_WIDTH,
1371 ((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1372 + ftypes_nr[1] * UL_ALIGNMENT_WIDTH, n);
1374 memset(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1375 + ftypes_nr[1] * UL_ALIGNMENT_WIDTH,
1376 0, d * UL_ALIGNMENT_WIDTH);
1379 /* Remap possible fields (like strings of chars) following int fields */
1380 d = gtypes_nr[2] - ftypes_nr[2];
1382 if (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1383 gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
1384 ftypes_nr[2] * U_ALIGNMENT_WIDTH < ftypes_nr[2])
1388 n = MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH
1389 - ftypes_nr[1] * UL_ALIGNMENT_WIDTH
1390 - ftypes_nr[2] * U_ALIGNMENT_WIDTH,
1391 g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1392 - gtypes_nr[1] * UL_ALIGNMENT_WIDTH
1393 - gtypes_nr[2] * U_ALIGNMENT_WIDTH);
1394 if ((gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1395 gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
1396 ftypes_nr[2] * U_ALIGNMENT_WIDTH >= b_size) ||
1397 (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1398 gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
1399 gtypes_nr[2] * U_ALIGNMENT_WIDTH + n > b_size) ||
1400 (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1401 gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
1402 ftypes_nr[2] * U_ALIGNMENT_WIDTH + n > b_size))
1405 memmove(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1406 + gtypes_nr[1] * UL_ALIGNMENT_WIDTH
1407 + gtypes_nr[2] * U_ALIGNMENT_WIDTH,
1408 ((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1409 + gtypes_nr[1] * UL_ALIGNMENT_WIDTH
1410 + ftypes_nr[2] * U_ALIGNMENT_WIDTH, n);
1412 memset(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1413 + gtypes_nr[1] * UL_ALIGNMENT_WIDTH
1414 + ftypes_nr[2] * U_ALIGNMENT_WIDTH,
1415 0, d * U_ALIGNMENT_WIDTH);
1422 ***************************************************************************
1423 * Read data from a system activity data file.
1426 * @ifd Input file descriptor.
1427 * @buffer Buffer where data are read.
1428 * @size Number of bytes to read.
1429 * @mode If set to HARD_SIZE, indicate that an EOF should be considered
1431 * @oneof Set to UEOF_CONT if an unexpected end of file should not make
1432 * sadf stop. Default behavior is to stop on unexpected EOF.
1435 * 1 if EOF has been reached,
1436 * 2 if an unexpected EOF has been reached (and sadf was told to continue),
1438 ***************************************************************************
1440 int sa_fread(int ifd, void *buffer, size_t size, enum size_mode mode, enum on_eof oneof)
1444 if ((n = read(ifd, buffer, size)) < 0) {
1445 fprintf(stderr, _("Error while reading system activity file: %s\n"),
1451 if (!n && (mode == SOFT_SIZE))
1455 fprintf(stderr, _("End of system activity file unexpected\n"));
1456 if (oneof == UEOF_CONT)
1466 ***************************************************************************
1467 * Skip unknown extra structures present in file.
1470 * @ifd System activity data file descriptor.
1472 * TRUE if file's data don't match current machine's endianness.
1473 * @arch_64 TRUE if file's data come from a 64 bit machine.
1476 * -1 on error, 0 otherwise.
1477 ***************************************************************************
1479 int skip_extra_struct(int ifd, int endian_mismatch, int arch_64)
1482 struct extra_desc xtra_d;
1485 /* Read extra structure description */
1486 sa_fread(ifd, &xtra_d, EXTRA_DESC_SIZE, HARD_SIZE, UEOF_STOP);
1489 * We don't need to remap as the extra_desc structure won't change,
1490 * but we may need to normalize endianness anyway.
1492 if (endian_mismatch) {
1493 swap_struct(extra_desc_types_nr, &xtra_d, arch_64);
1496 /* Check values consistency */
1497 if (MAP_SIZE(xtra_d.extra_types_nr) > xtra_d.extra_size) {
1499 fprintf(stderr, "%s: extra_size=%u types=%u,%u,%u\n",
1500 __FUNCTION__, xtra_d.extra_size,
1501 xtra_d.extra_types_nr[0], xtra_d.extra_types_nr[1], xtra_d.extra_types_nr[2]);
1506 if ((xtra_d.extra_nr > MAX_EXTRA_NR) || (xtra_d.extra_size > MAX_EXTRA_SIZE)) {
1508 fprintf(stderr, "%s: extra_size=%u extra_nr=%u\n",
1509 __FUNCTION__, xtra_d.extra_size, xtra_d.extra_size);
1514 /* Ignore current unknown extra structures */
1515 for (i = 0; i < xtra_d.extra_nr; i++) {
1516 if (lseek(ifd, xtra_d.extra_size, SEEK_CUR) < xtra_d.extra_size)
1520 while (xtra_d.extra_next);
1526 ***************************************************************************
1527 * Read the record header of current sample and process it.
1530 * @ifd Input file descriptor.
1531 * @buffer Buffer where data will be read.
1532 * @record_hdr Structure where record header will be saved.
1533 * @file_hdr file_hdr structure containing data read from file standard
1535 * @arch_64 TRUE if file's data come from a 64-bit machine.
1537 * TRUE if data read from file don't match current machine's
1539 * @oneof Set to EOF_CONT if an unexpected end of file should not make
1540 * sadf stop. Default behavior is to stop on unexpected EOF.
1541 * @b_size @buffer size.
1542 * @flags Flags for common options and system state.
1543 * @ofmt Pointer on report output format structure.
1546 * @record_hdr Record header for current sample.
1549 * 1 if EOF has been reached, 0 otherwise.
1550 ***************************************************************************
1552 int read_record_hdr(int ifd, void *buffer, struct record_header *record_hdr,
1553 struct file_header *file_hdr, int arch_64, int endian_mismatch,
1554 int oneof, size_t b_size, uint64_t flags, struct report_format *ofmt)
1559 if ((rc = sa_fread(ifd, buffer, (size_t) file_hdr->rec_size, SOFT_SIZE, oneof)) != 0)
1560 /* End of sa data file */
1563 /* Remap record header structure to that expected by current version */
1564 if (remap_struct(rec_types_nr, file_hdr->rec_types_nr, buffer,
1565 file_hdr->rec_size, RECORD_HEADER_SIZE, b_size) < 0)
1567 memcpy(record_hdr, buffer, RECORD_HEADER_SIZE);
1569 /* Normalize endianness */
1570 if (endian_mismatch) {
1571 swap_struct(rec_types_nr, record_hdr, arch_64);
1574 /* Raw output in debug mode */
1575 if (DISPLAY_DEBUG_MODE(flags) && (ofmt->id == F_RAW_OUTPUT)) {
1578 sprintf(out, "# uptime_cs; %llu; ust_time; %llu; extra_next; %u; record_type; %d; HH:MM:SS; %02d:%02d:%02d\n",
1579 record_hdr->uptime_cs, record_hdr->ust_time,
1580 record_hdr->extra_next, record_hdr->record_type,
1581 record_hdr->hour, record_hdr->minute, record_hdr->second);
1582 cprintf_s(IS_COMMENT, "%s", out);
1586 if (!record_hdr->record_type || (record_hdr->record_type > R_EXTRA_MAX) ||
1587 (record_hdr->hour > 23) || (record_hdr->minute > 59) || (record_hdr->second > 60) || (record_hdr->ust_time < 1000000000)) {
1589 fprintf(stderr, "%s: record_type=%d HH:MM:SS=%02d:%02d:%02d (%llu)\n",
1590 __FUNCTION__, record_hdr->record_type,
1591 record_hdr->hour, record_hdr->minute, record_hdr->second,
1592 record_hdr->ust_time);
1598 * Skip unknown extra structures if present.
1599 * This will be done later for R_COMMENT and R_RESTART records, as extra structures
1600 * are saved after the comment or the number of CPU.
1602 if ((record_hdr->record_type != R_COMMENT) && (record_hdr->record_type != R_RESTART) &&
1603 record_hdr->extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
1606 while ((record_hdr->record_type >= R_EXTRA_MIN) && (record_hdr->record_type <= R_EXTRA_MAX)) ;
1611 fprintf(stderr, _("Invalid data read\n"));
1616 ***************************************************************************
1617 * Move structures data.
1620 * @act Array of activities.
1621 * @id_seq Activity sequence in file.
1622 * @record_hdr Current record header.
1623 * @dest Index in array where stats have to be copied to.
1624 * @src Index in array where stats to copy are.
1625 ***************************************************************************
1627 void copy_structures(struct activity *act[], unsigned int id_seq[],
1628 struct record_header record_hdr[], int dest, int src)
1632 memcpy(&record_hdr[dest], &record_hdr[src], RECORD_HEADER_SIZE);
1634 for (i = 0; i < NR_ACT; i++) {
1639 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1641 memcpy(act[p]->buf[dest], act[p]->buf[src],
1642 (size_t) act[p]->msize * (size_t) act[p]->nr_allocated * (size_t) act[p]->nr2);
1643 act[p]->nr[dest] = act[p]->nr[src];
1648 ***************************************************************************
1649 * Read an __nr_t value from file.
1650 * Such a value can be the new number of CPU saved after a RESTART record,
1651 * or the number of structures to read saved before the structures containing
1652 * statistics for an activity with a varying number of items in file.
1655 * @ifd Input file descriptor.
1656 * @file Name of file being read.
1657 * @file_magic file_magic structure filled with file magic header data.
1659 * TRUE if file's data don't match current machine's endianness.
1660 * @arch_64 TRUE if file's data come from a 64 bit machine.
1661 * @non_zero TRUE if value should not be zero.
1664 * __nr_t value, as read from file.
1665 ***************************************************************************
1667 __nr_t read_nr_value(int ifd, char *file, struct file_magic *file_magic,
1668 int endian_mismatch, int arch_64, int non_zero)
1671 unsigned int nr_types_nr[] = {0, 0, 1};
1673 sa_fread(ifd, &value, sizeof(__nr_t), HARD_SIZE, UEOF_STOP);
1675 /* Normalize endianness for file_activity structures */
1676 if (endian_mismatch) {
1677 swap_struct(nr_types_nr, &value, arch_64);
1680 if ((non_zero && !value) || (value < 0)) {
1682 fprintf(stderr, "%s: Value=%d\n",
1683 __FUNCTION__, value);
1685 /* Value number cannot be zero or negative */
1686 handle_invalid_sa_file(ifd, file_magic, file, 0);
1693 ***************************************************************************
1694 * Read varying part of the statistics from a daily data file.
1697 * @act Array of activities.
1698 * @curr Index in array for current sample statistics.
1699 * @ifd Input file descriptor.
1700 * @act_nr Number of activities in file.
1701 * @file_actlst Activity list in file.
1703 * TRUE if file's data don't match current machine's endianness.
1704 * @arch_64 TRUE if file's data come from a 64 bit machine.
1705 * @dfile Name of system activity data file.
1706 * @file_magic file_magic structure containing data read from file magic
1708 * @oneof Set to UEOF_CONT if an unexpected end of file should not make
1709 * sadf stop. Default behavior is to stop on unexpected EOF.
1712 * 2 if an error has been encountered (e.g. unexpected EOF),
1714 ***************************************************************************
1716 int read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
1717 struct file_activity *file_actlst, int endian_mismatch,
1718 int arch_64, char *dfile, struct file_magic *file_magic,
1722 struct file_activity *fal = file_actlst;
1726 for (i = 0; i < act_nr; i++, fal++) {
1728 /* Read __nr_t value preceding statistics structures if it exists */
1730 nr_value = read_nr_value(ifd, dfile, file_magic,
1731 endian_mismatch, arch_64, FALSE);
1737 if (nr_value > NR_MAX) {
1739 fprintf(stderr, "%s: Value=%d Max=%d\n", __FUNCTION__, nr_value, NR_MAX);
1741 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1744 if (((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0) ||
1745 (act[p]->magic != fal->magic)) {
1747 * Ignore current activity in file, which is unknown to
1748 * current sysstat version or has an unknown format.
1751 offset = (off_t) fal->size * (off_t) nr_value * (off_t) fal->nr2;
1752 if (lseek(ifd, offset, SEEK_CUR) < offset) {
1755 if (oneof == UEOF_CONT)
1763 if (nr_value > act[p]->nr_max) {
1765 fprintf(stderr, "%s: %s: Value=%d Max=%d\n",
1766 __FUNCTION__, act[p]->name, nr_value, act[p]->nr_max);
1768 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1770 act[p]->nr[curr] = nr_value;
1772 /* Reallocate buffers if needed */
1773 if (nr_value > act[p]->nr_allocated) {
1774 reallocate_all_buffers(act[p], nr_value);
1778 * For persistent activities, we must make sure that no statistics
1779 * from a previous iteration remain, especially if the number
1780 * of structures read is smaller than @nr_ini.
1782 if (HAS_PERSISTENT_VALUES(act[p]->options)) {
1783 memset(act[p]->buf[curr], 0,
1784 (size_t) act[p]->msize * (size_t) act[p]->nr_ini * (size_t) act[p]->nr2);
1787 /* OK, this is a known activity: Read the stats structures */
1788 if ((nr_value > 0) &&
1789 ((nr_value > 1) || (act[p]->nr2 > 1)) &&
1790 (act[p]->msize > act[p]->fsize)) {
1792 for (j = 0; j < (nr_value * act[p]->nr2); j++) {
1793 if (sa_fread(ifd, (char *) act[p]->buf[curr] + j * act[p]->msize,
1794 (size_t) act[p]->fsize, HARD_SIZE, oneof) > 0)
1795 /* Unexpected EOF */
1799 else if (nr_value > 0) {
1801 * Note: If msize was smaller than fsize,
1802 * then it has been set to fsize in check_file_actlst().
1804 if (sa_fread(ifd, act[p]->buf[curr],
1805 (size_t) act[p]->fsize * (size_t) nr_value * (size_t) act[p]->nr2,
1806 HARD_SIZE, oneof) > 0)
1807 /* Unexpected EOF */
1811 /* nr_value == 0: Nothing to read */
1815 /* Normalize endianness for current activity's structures */
1816 if (endian_mismatch) {
1817 for (j = 0; j < (nr_value * act[p]->nr2); j++) {
1818 swap_struct(act[p]->ftypes_nr, (char *) act[p]->buf[curr] + j * act[p]->msize,
1823 /* Remap structure's fields to those known by current sysstat version */
1824 for (j = 0; j < (nr_value * act[p]->nr2); j++) {
1825 if (remap_struct(act[p]->gtypes_nr, act[p]->ftypes_nr,
1826 (char *) act[p]->buf[curr] + j * act[p]->msize,
1827 act[p]->fsize, act[p]->msize, act[p]->msize) < 0)
1836 ***************************************************************************
1837 * Open a sysstat activity data file and read its magic structure.
1840 * @dfile Name of system activity data file.
1841 * @ignore Set to 1 if a true sysstat activity file but with a bad
1842 * format should not yield an error message. Useful with
1843 * sadf -H and sadf -c.
1846 * @fd System activity data file descriptor.
1847 * @file_magic file_magic structure containing data read from file magic
1850 * TRUE if file's data don't match current machine's endianness.
1851 * @do_swap TRUE if endianness should be normalized for sysstat_magic
1852 * and format_magic numbers.
1855 * -1 if data file is a sysstat file with an old format (which we cannot
1856 * read), 0 otherwise.
1857 ***************************************************************************
1859 int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
1860 int ignore, int *endian_mismatch, int do_swap)
1863 unsigned int fm_types_nr[] = {FILE_MAGIC_ULL_NR, FILE_MAGIC_UL_NR, FILE_MAGIC_U_NR};
1865 /* Open sa data file */
1866 if ((*fd = open(dfile, O_RDONLY)) < 0) {
1867 int saved_errno = errno;
1869 fprintf(stderr, _("Cannot open %s: %s\n"), dfile, strerror(errno));
1871 if ((saved_errno == ENOENT) && default_file_used) {
1872 fprintf(stderr, _("Please check if data collecting is enabled\n"));
1877 /* Read file magic data */
1878 n = read(*fd, file_magic, FILE_MAGIC_SIZE);
1880 if ((n != FILE_MAGIC_SIZE) ||
1881 ((file_magic->sysstat_magic != SYSSTAT_MAGIC) && (file_magic->sysstat_magic != SYSSTAT_MAGIC_SWAPPED)) ||
1882 ((file_magic->format_magic != FORMAT_MAGIC) && (file_magic->format_magic != FORMAT_MAGIC_SWAPPED) && !ignore)) {
1884 fprintf(stderr, "%s: Bytes read=%d sysstat_magic=%x format_magic=%x\n",
1885 __FUNCTION__, n, file_magic->sysstat_magic, file_magic->format_magic);
1887 /* Display error message and exit */
1888 handle_invalid_sa_file(*fd, file_magic, dfile, n);
1891 *endian_mismatch = (file_magic->sysstat_magic != SYSSTAT_MAGIC);
1892 if (*endian_mismatch) {
1894 /* Swap bytes for file_magic fields */
1895 file_magic->sysstat_magic = SYSSTAT_MAGIC;
1896 file_magic->format_magic = __builtin_bswap16(file_magic->format_magic);
1899 * Start swapping at field "header_size" position.
1900 * May not exist for older versions but in this case, it won't be used.
1902 swap_struct(fm_types_nr, &file_magic->header_size, 0);
1905 if ((file_magic->sysstat_version > 10) ||
1906 ((file_magic->sysstat_version == 10) && (file_magic->sysstat_patchlevel >= 3))) {
1907 /* header_size field exists only for sysstat versions 10.3.1 and later */
1908 if ((file_magic->header_size <= MIN_FILE_HEADER_SIZE) ||
1909 (file_magic->header_size > MAX_FILE_HEADER_SIZE)) {
1911 fprintf(stderr, "%s: header_size=%u\n",
1912 __FUNCTION__, file_magic->header_size);
1914 /* Display error message and exit */
1915 handle_invalid_sa_file(*fd, file_magic, dfile, n);
1918 if ((file_magic->sysstat_version > 11) ||
1919 ((file_magic->sysstat_version == 11) && (file_magic->sysstat_patchlevel >= 7))) {
1920 /* hdr_types_nr field exists only for sysstat versions 11.7.1 and later */
1921 if (MAP_SIZE(file_magic->hdr_types_nr) > file_magic->header_size) {
1923 fprintf(stderr, "%s: map_size=%u header_size=%u\n",
1924 __FUNCTION__, MAP_SIZE(file_magic->hdr_types_nr), file_magic->header_size);
1926 handle_invalid_sa_file(*fd, file_magic, dfile, n);
1930 if ((file_magic->format_magic != FORMAT_MAGIC) &&
1931 (file_magic->format_magic != FORMAT_MAGIC_SWAPPED))
1933 * This is an old (or new) sa datafile format to
1934 * be read by sadf (since @ignore was set to TRUE).
1942 ***************************************************************************
1943 * Open a data file, and perform various checks before reading.
1944 * NB: This is called only when reading a datafile (sar and sadf), never
1945 * when writing or appending data to a datafile.
1948 * @dfile Name of system activity data file.
1949 * @act Array of activities.
1950 * @flags Flags for common options and system state.
1953 * @ifd System activity data file descriptor.
1954 * @file_magic file_magic structure containing data read from file magic
1956 * @file_hdr file_hdr structure containing data read from file standard
1958 * @file_actlst Acvtivity list in file.
1959 * @id_seq Activity sequence.
1961 * TRUE if file's data don't match current machine's endianness.
1962 * @arch_64 TRUE if file's data come from a 64 bit machine.
1963 ***************************************************************************
1965 void check_file_actlst(int *ifd, char *dfile, struct activity *act[], uint64_t flags,
1966 struct file_magic *file_magic, struct file_header *file_hdr,
1967 struct file_activity **file_actlst, unsigned int id_seq[],
1968 int *endian_mismatch, int *arch_64)
1970 int i, j, k, p, skip;
1971 struct file_activity *fal;
1972 void *buffer = NULL;
1973 size_t bh_size = FILE_HEADER_SIZE;
1974 size_t ba_size = FILE_ACTIVITY_SIZE;
1976 /* Open sa data file and read its magic structure */
1977 if (sa_open_read_magic(ifd, dfile, file_magic,
1978 DISPLAY_HDR_ONLY(flags), endian_mismatch, TRUE) < 0)
1980 * Not current sysstat's format.
1981 * Return now so that sadf -H can display at least
1982 * file's version and magic number.
1987 * We know now that we have a *compatible* sysstat datafile format
1988 * (correct FORMAT_MAGIC value), and in this case, we should have
1989 * checked header_size value. Anyway, with a corrupted datafile,
1990 * this may not be the case. So check again.
1992 if ((file_magic->header_size <= MIN_FILE_HEADER_SIZE) ||
1993 (file_magic->header_size > MAX_FILE_HEADER_SIZE)) {
1995 fprintf(stderr, "%s: header_size=%u\n",
1996 __FUNCTION__, file_magic->header_size);
2001 /* Allocate buffer for file_header structure */
2002 if (file_magic->header_size > FILE_HEADER_SIZE) {
2003 bh_size = file_magic->header_size;
2005 SREALLOC(buffer, char, bh_size);
2007 /* Read sa data file standard header and allocate activity list */
2008 sa_fread(*ifd, buffer, (size_t) file_magic->header_size, HARD_SIZE, UEOF_STOP);
2010 * Data file header size (file_magic->header_size) may be greater or
2011 * smaller than FILE_HEADER_SIZE. Remap the fields of the file header
2012 * then copy its contents to the expected structure.
2014 if (remap_struct(hdr_types_nr, file_magic->hdr_types_nr, buffer,
2015 file_magic->header_size, FILE_HEADER_SIZE, bh_size) < 0)
2018 memcpy(file_hdr, buffer, FILE_HEADER_SIZE);
2022 /* Tell that data come from a 64 bit machine */
2023 *arch_64 = (file_hdr->sa_sizeof_long == SIZEOF_LONG_64BIT);
2025 /* Normalize endianness for file_hdr structure */
2026 if (*endian_mismatch) {
2027 swap_struct(hdr_types_nr, file_hdr, *arch_64);
2032 * NB: Compare against MAX_NR_ACT and not NR_ACT because
2033 * we are maybe reading a datafile from a future sysstat version
2034 * with more activities than known today.
2036 if ((file_hdr->sa_act_nr > MAX_NR_ACT) ||
2037 (file_hdr->act_size > MAX_FILE_ACTIVITY_SIZE) ||
2038 (file_hdr->rec_size > MAX_RECORD_HEADER_SIZE) ||
2039 (MAP_SIZE(file_hdr->act_types_nr) > file_hdr->act_size) ||
2040 (MAP_SIZE(file_hdr->rec_types_nr) > file_hdr->rec_size)) {
2042 fprintf(stderr, "%s: sa_act_nr=%u act_size=%u rec_size=%u map_size(act)=%u map_size(rec)=%u\n",
2043 __FUNCTION__, file_hdr->sa_act_nr, file_hdr->act_size, file_hdr->rec_size,
2044 MAP_SIZE(file_hdr->act_types_nr), MAP_SIZE(file_hdr->rec_types_nr));
2046 /* Maybe a "false positive" sysstat datafile? */
2050 /* Allocate buffer for file_activity structures */
2051 if (file_hdr->act_size > FILE_ACTIVITY_SIZE) {
2052 ba_size = file_hdr->act_size;
2054 SREALLOC(buffer, char, ba_size);
2055 SREALLOC(*file_actlst, struct file_activity, FILE_ACTIVITY_SIZE * file_hdr->sa_act_nr);
2058 /* Read activity list */
2060 for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
2062 /* Read current file_activity structure from file */
2063 sa_fread(*ifd, buffer, (size_t) file_hdr->act_size, HARD_SIZE, UEOF_STOP);
2066 * Data file_activity size (file_hdr->act_size) may be greater or
2067 * smaller than FILE_ACTIVITY_SIZE. Remap the fields of the file's structure
2068 * then copy its contents to the expected structure.
2070 if (remap_struct(act_types_nr, file_hdr->act_types_nr, buffer,
2071 file_hdr->act_size, FILE_ACTIVITY_SIZE, ba_size) < 0)
2073 memcpy(fal, buffer, FILE_ACTIVITY_SIZE);
2075 /* Normalize endianness for file_activity structures */
2076 if (*endian_mismatch) {
2077 swap_struct(act_types_nr, fal, *arch_64);
2081 * Every activity, known or unknown, should have
2082 * at least one item and sub-item, and a size value in
2084 * Also check that the number of items and sub-items
2085 * doesn't exceed a max value. This is necessary
2086 * because we will use @nr and @nr2 to
2087 * allocate memory to read the file contents. So we
2088 * must make sure the file is not corrupted.
2089 * NB: Another check will be made below for known
2090 * activities which have each a specific max value.
2092 if ((fal->nr < 1) || (fal->nr2 < 1) ||
2093 (fal->nr > NR_MAX) || (fal->nr2 > NR2_MAX) ||
2094 (fal->size <= 0) || (fal->size > MAX_ITEM_STRUCT_SIZE)) {
2096 fprintf(stderr, "%s: id=%u nr=%d nr2=%d size=%d\n",
2097 __FUNCTION__, fal->id, fal->nr, fal->nr2, fal->size);
2102 if ((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0)
2103 /* Unknown activity */
2106 if ((fal->magic != act[p]->magic) && !DISPLAY_HDR_ONLY(flags)) {
2113 /* Check max value for known activities */
2114 if (fal->nr > act[p]->nr_max) {
2116 fprintf(stderr, "%s: id=%u nr=%d nr_max=%d\n",
2117 __FUNCTION__, fal->id, fal->nr, act[p]->nr_max);
2123 * Number of fields of each type ("long long", or "long"
2124 * or "int") composing the structure with statistics may
2125 * only increase with new sysstat versions, unless we change
2126 * the activity's magic number. Here, we may
2127 * be reading a file created by current sysstat version,
2128 * or by an older or a newer version.
2130 if (!(((fal->types_nr[0] >= act[p]->gtypes_nr[0]) &&
2131 (fal->types_nr[1] >= act[p]->gtypes_nr[1]) &&
2132 (fal->types_nr[2] >= act[p]->gtypes_nr[2]))
2134 ((fal->types_nr[0] <= act[p]->gtypes_nr[0]) &&
2135 (fal->types_nr[1] <= act[p]->gtypes_nr[1]) &&
2136 (fal->types_nr[2] <= act[p]->gtypes_nr[2]))) &&
2137 (fal->magic == act[p]->magic) && !DISPLAY_HDR_ONLY(flags)) {
2139 fprintf(stderr, "%s: id=%u file=%u,%u,%u activity=%u,%u,%u\n",
2140 __FUNCTION__, fal->id, fal->types_nr[0], fal->types_nr[1], fal->types_nr[2],
2141 act[p]->gtypes_nr[0], act[p]->gtypes_nr[1], act[p]->gtypes_nr[2]);
2146 if (MAP_SIZE(fal->types_nr) > fal->size) {
2148 fprintf(stderr, "%s: id=%u size=%d map_size=%u\n",
2149 __FUNCTION__, fal->id, fal->size, MAP_SIZE(fal->types_nr));
2154 for (k = 0; k < 3; k++) {
2155 act[p]->ftypes_nr[k] = fal->types_nr[k];
2158 if (fal->size > act[p]->msize) {
2159 act[p]->msize = fal->size;
2162 act[p]->nr_ini = fal->nr;
2163 act[p]->nr2 = fal->nr2;
2164 act[p]->fsize = fal->size;
2167 * This is a known activity with a known format
2168 * (magical number). Only such activities will be displayed.
2169 * (Well, this may also be an unknown format if we have entered sadf -H.)
2172 id_seq[j++] = fal->id;
2176 while (j < NR_ACT) {
2183 /* Check that at least one activity selected by the user is available in file */
2184 for (i = 0; i < NR_ACT; i++) {
2186 if (!IS_SELECTED(act[i]->options))
2189 /* Here is a selected activity: Does it exist in file? */
2191 for (j = 0; j < file_hdr->sa_act_nr; j++, fal++) {
2192 if (act[i]->id == fal->id)
2195 if (j == file_hdr->sa_act_nr) {
2196 /* No: Unselect it */
2197 act[i]->options &= ~AO_SELECTED;
2202 * None of selected activities exist in file: Abort.
2203 * NB: Error is ignored if we only want to display
2204 * datafile header (sadf -H).
2206 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES) && !DISPLAY_HDR_ONLY(flags)) {
2207 fprintf(stderr, _("Requested activities not available in file %s\n"),
2214 * Check if there are some extra structures.
2215 * We will just skip them as they are unknown for now.
2217 if (file_hdr->extra_next && (skip_extra_struct(*ifd, *endian_mismatch, *arch_64) < 0))
2226 handle_invalid_sa_file(*ifd, file_magic, dfile, 0);
2230 ***************************************************************************
2231 * Look for item in list.
2234 * @list Pointer on the start of the linked list.
2235 * @item_name Item name to look for.
2238 * 1 if item found in list, 0 otherwise.
2239 ***************************************************************************
2241 int search_list_item(struct sa_item *list, char *item_name)
2243 while (list != NULL) {
2244 if (!strcmp(list->item_name, item_name))
2245 return 1; /* Item found in list */
2249 /* Item not found */
2254 ***************************************************************************
2255 * Add item to the list.
2258 * @list Address of pointer on the start of the linked list.
2259 * @item_name Name of the item.
2260 * @max_len Max length of an item.
2263 * 1 if item has been added to the list (since it was not previously there),
2264 * and 0 otherwise (item already in list or item name too long).
2265 ***************************************************************************
2267 int add_list_item(struct sa_item **list, char *item_name, int max_len)
2272 if ((len = strnlen(item_name, max_len)) == max_len)
2276 while (*list != NULL) {
2278 if (!strcmp(e->item_name, item_name))
2279 return 0; /* Item found in list */
2283 /* Item not found: Add it to the list */
2284 SREALLOC(*list, struct sa_item, sizeof(struct sa_item));
2286 if ((e->item_name = (char *) malloc(len + 1)) == NULL) {
2290 strcpy(e->item_name, item_name);
2296 ***************************************************************************
2297 * Parse sar activities options (also used by sadf).
2300 * @argv Arguments list.
2301 * @opt Index in list of arguments.
2302 * @caller Indicate whether it's sar or sadf that called this function.
2305 * @act Array of selected activities.
2306 * @flags Common flags and system state.
2310 ***************************************************************************
2312 int parse_sar_opt(char *argv[], int *opt, struct activity *act[],
2313 uint64_t *flags, int caller)
2317 for (i = 1; *(argv[*opt] + i); i++) {
2319 * Note: argv[*opt] contains something like "-BruW"
2320 * *(argv[*opt] + i) will contain 'B', 'r', etc.
2323 switch (*(argv[*opt] + i)) {
2326 select_all_activities(act);
2327 *flags |= S_F_OPTION_A;
2330 * Force '-r ALL -u ALL -F'.
2331 * Setting -F is compulsory because corresponding activity
2332 * has AO_MULTIPLE_OUTPUTS flag set.
2333 * -P ALL will be set only if corresponding option has
2334 * not been exlicitly entered on the command line.
2336 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
2337 act[p]->opt_flags |= AO_F_MEMORY + AO_F_SWAP + AO_F_MEM_ALL;
2339 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
2340 act[p]->opt_flags = AO_F_CPU_ALL;
2342 p = get_activity_position(act, A_FS, EXIT_IF_NOT_FOUND);
2343 act[p]->opt_flags = AO_F_FILESYSTEM;
2347 SELECT_ACTIVITY(A_PAGE);
2351 SELECT_ACTIVITY(A_IO);
2355 *flags |= S_F_COMMENT;
2359 SELECT_ACTIVITY(A_DISK);
2363 p = get_activity_position(act, A_FS, EXIT_IF_NOT_FOUND);
2364 act[p]->options |= AO_SELECTED;
2365 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_MOUNT)) {
2367 act[p]->opt_flags |= AO_F_MOUNT;
2371 act[p]->opt_flags |= AO_F_FILESYSTEM;
2376 SELECT_ACTIVITY(A_HUGE);
2380 /* Option -h is equivalent to --pretty --human */
2381 *flags |= S_F_PRETTY + S_F_UNIT;
2385 p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
2386 act[p]->options |= AO_SELECTED;
2388 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] &&
2389 (!strcmp(argv[*opt + 1], K_ALL) || !strcmp(argv[*opt + 1], K_SUM))) {
2391 /* Select int "sum". Keyword ALL is ignored */
2392 if (!strcmp(argv[*opt], K_SUM)) {
2393 act[p]->item_list_sz += add_list_item(&(act[p]->item_list), K_LOWERSUM, MAX_SA_IRQ_LEN);
2394 act[p]->options |= AO_LIST_ON_CMDLINE;
2401 if (!argv[*opt + 1]) {
2405 if (!strcmp(argv[*opt], K_SID)) {
2406 *flags |= S_F_DEV_SID + S_F_PRETTY;
2410 if (strnlen(argv[*opt], sizeof(persistent_name_type)) >= sizeof(persistent_name_type) - 1)
2413 strncpy(persistent_name_type, argv[*opt], sizeof(persistent_name_type) - 1);
2414 persistent_name_type[sizeof(persistent_name_type) - 1] = '\0';
2415 strtolower(persistent_name_type);
2416 if (!get_persistent_type_dir(persistent_name_type)) {
2417 fprintf(stderr, _("Invalid type of persistent device name\n"));
2420 /* Pretty print report (option -j implies option -p) */
2421 *flags |= S_F_PERSIST_NAME + S_F_PRETTY;
2426 *flags |= S_F_PRETTY;
2430 /* Option -q grouped with other ones */
2431 SELECT_ACTIVITY(A_QUEUE);
2435 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
2436 act[p]->options |= AO_SELECTED;
2437 act[p]->opt_flags |= AO_F_MEMORY;
2438 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
2440 act[p]->opt_flags |= AO_F_MEM_ALL;
2446 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
2447 act[p]->options |= AO_SELECTED;
2448 act[p]->opt_flags |= AO_F_SWAP;
2453 * Check sar option -t here (as it can be combined
2454 * with other ones, eg. "sar -rtu ..."
2455 * But sadf option -t is checked in sadf.c as it won't
2456 * be entered as a sar option after "--".
2458 if (caller != C_SAR) {
2461 *flags |= S_F_TRUE_TIME;
2465 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
2466 act[p]->options |= AO_SELECTED;
2467 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
2469 act[p]->opt_flags = AO_F_CPU_ALL;
2473 act[p]->opt_flags = AO_F_CPU_DEF;
2478 SELECT_ACTIVITY(A_KTABLES);
2482 SELECT_ACTIVITY(A_PCSW);
2486 SELECT_ACTIVITY(A_SWAP);
2490 SELECT_ACTIVITY(A_SERIAL);
2494 *flags |= S_F_ZERO_OMIT;
2509 ***************************************************************************
2510 * Parse sar "-m" option.
2513 * @argv Arguments list.
2514 * @opt Index in list of arguments.
2517 * @act Array of selected activities.
2520 * 0 on success, 1 otherwise.
2521 ***************************************************************************
2523 int parse_sar_m_opt(char *argv[], int *opt, struct activity *act[])
2527 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
2528 if (!strcmp(t, K_CPU)) {
2529 SELECT_ACTIVITY(A_PWR_CPU);
2531 else if (!strcmp(t, K_FAN)) {
2532 SELECT_ACTIVITY(A_PWR_FAN);
2534 else if (!strcmp(t, K_IN)) {
2535 SELECT_ACTIVITY(A_PWR_IN);
2537 else if (!strcmp(t, K_TEMP)) {
2538 SELECT_ACTIVITY(A_PWR_TEMP);
2540 else if (!strcmp(t, K_FREQ)) {
2541 SELECT_ACTIVITY(A_PWR_FREQ);
2543 else if (!strcmp(t, K_USB)) {
2544 SELECT_ACTIVITY(A_PWR_USB);
2546 else if (!strcmp(t, K_BAT)) {
2547 SELECT_ACTIVITY(A_PWR_BAT);
2549 else if (!strcmp(t, K_ALL)) {
2550 SELECT_ACTIVITY(A_PWR_CPU);
2551 SELECT_ACTIVITY(A_PWR_FAN);
2552 SELECT_ACTIVITY(A_PWR_IN);
2553 SELECT_ACTIVITY(A_PWR_TEMP);
2554 SELECT_ACTIVITY(A_PWR_FREQ);
2555 SELECT_ACTIVITY(A_PWR_USB);
2556 SELECT_ACTIVITY(A_PWR_BAT);
2567 ***************************************************************************
2568 * Parse sar "-n" option.
2571 * @argv Arguments list.
2572 * @opt Index in list of arguments.
2575 * @act Array of selected activities.
2578 * 0 on success, 1 otherwise.
2579 ***************************************************************************
2581 int parse_sar_n_opt(char *argv[], int *opt, struct activity *act[])
2585 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
2586 if (!strcmp(t, K_DEV)) {
2587 SELECT_ACTIVITY(A_NET_DEV);
2589 else if (!strcmp(t, K_EDEV)) {
2590 SELECT_ACTIVITY(A_NET_EDEV);
2592 else if (!strcmp(t, K_SOCK)) {
2593 SELECT_ACTIVITY(A_NET_SOCK);
2595 else if (!strcmp(t, K_NFS)) {
2596 SELECT_ACTIVITY(A_NET_NFS);
2598 else if (!strcmp(t, K_NFSD)) {
2599 SELECT_ACTIVITY(A_NET_NFSD);
2601 else if (!strcmp(t, K_IP)) {
2602 SELECT_ACTIVITY(A_NET_IP);
2604 else if (!strcmp(t, K_EIP)) {
2605 SELECT_ACTIVITY(A_NET_EIP);
2607 else if (!strcmp(t, K_ICMP)) {
2608 SELECT_ACTIVITY(A_NET_ICMP);
2610 else if (!strcmp(t, K_EICMP)) {
2611 SELECT_ACTIVITY(A_NET_EICMP);
2613 else if (!strcmp(t, K_TCP)) {
2614 SELECT_ACTIVITY(A_NET_TCP);
2616 else if (!strcmp(t, K_ETCP)) {
2617 SELECT_ACTIVITY(A_NET_ETCP);
2619 else if (!strcmp(t, K_UDP)) {
2620 SELECT_ACTIVITY(A_NET_UDP);
2622 else if (!strcmp(t, K_SOCK6)) {
2623 SELECT_ACTIVITY(A_NET_SOCK6);
2625 else if (!strcmp(t, K_IP6)) {
2626 SELECT_ACTIVITY(A_NET_IP6);
2628 else if (!strcmp(t, K_EIP6)) {
2629 SELECT_ACTIVITY(A_NET_EIP6);
2631 else if (!strcmp(t, K_ICMP6)) {
2632 SELECT_ACTIVITY(A_NET_ICMP6);
2634 else if (!strcmp(t, K_EICMP6)) {
2635 SELECT_ACTIVITY(A_NET_EICMP6);
2637 else if (!strcmp(t, K_UDP6)) {
2638 SELECT_ACTIVITY(A_NET_UDP6);
2640 else if (!strcmp(t, K_FC)) {
2641 SELECT_ACTIVITY(A_NET_FC);
2643 else if (!strcmp(t, K_SOFT)) {
2644 SELECT_ACTIVITY(A_NET_SOFT);
2646 else if (!strcmp(t, K_ALL)) {
2647 SELECT_ACTIVITY(A_NET_DEV);
2648 SELECT_ACTIVITY(A_NET_EDEV);
2649 SELECT_ACTIVITY(A_NET_SOCK);
2650 SELECT_ACTIVITY(A_NET_NFS);
2651 SELECT_ACTIVITY(A_NET_NFSD);
2652 SELECT_ACTIVITY(A_NET_IP);
2653 SELECT_ACTIVITY(A_NET_EIP);
2654 SELECT_ACTIVITY(A_NET_ICMP);
2655 SELECT_ACTIVITY(A_NET_EICMP);
2656 SELECT_ACTIVITY(A_NET_TCP);
2657 SELECT_ACTIVITY(A_NET_ETCP);
2658 SELECT_ACTIVITY(A_NET_UDP);
2659 SELECT_ACTIVITY(A_NET_SOCK6);
2660 SELECT_ACTIVITY(A_NET_IP6);
2661 SELECT_ACTIVITY(A_NET_EIP6);
2662 SELECT_ACTIVITY(A_NET_ICMP6);
2663 SELECT_ACTIVITY(A_NET_EICMP6);
2664 SELECT_ACTIVITY(A_NET_UDP6);
2665 SELECT_ACTIVITY(A_NET_FC);
2666 SELECT_ACTIVITY(A_NET_SOFT);
2677 ***************************************************************************
2678 * Parse sar "-q" option.
2681 * @argv Arguments list.
2682 * @opt Index in list of arguments.
2685 * @act Array of selected activities.
2688 * 0 on success, 1 otherwise.
2689 ***************************************************************************
2691 int parse_sar_q_opt(char *argv[], int *opt, struct activity *act[])
2695 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
2696 if (!strcmp(t, K_LOAD)) {
2697 SELECT_ACTIVITY(A_QUEUE);
2699 else if (!strcmp(t, K_PSI_CPU)) {
2700 SELECT_ACTIVITY(A_PSI_CPU);
2702 else if (!strcmp(t, K_PSI_IO)) {
2703 SELECT_ACTIVITY(A_PSI_IO);
2705 else if (!strcmp(t, K_PSI_MEM)) {
2706 SELECT_ACTIVITY(A_PSI_MEM);
2708 else if (!strcmp(t, K_PSI)) {
2709 SELECT_ACTIVITY(A_PSI_CPU);
2710 SELECT_ACTIVITY(A_PSI_IO);
2711 SELECT_ACTIVITY(A_PSI_MEM);
2713 else if (!strcmp(t, K_ALL)) {
2714 SELECT_ACTIVITY(A_QUEUE);
2715 SELECT_ACTIVITY(A_PSI_CPU);
2716 SELECT_ACTIVITY(A_PSI_IO);
2717 SELECT_ACTIVITY(A_PSI_MEM);
2728 ***************************************************************************
2729 * Parse sar and sadf "-P" option.
2732 * @argv Arguments list.
2733 * @opt Index in list of arguments.
2734 * @act Array of activities.
2737 * @flags Common flags and system state.
2738 * @act Array of activities, with CPUs selected.
2741 * 0 on success, 1 otherwise.
2742 ***************************************************************************
2744 int parse_sa_P_opt(char *argv[], int *opt, uint64_t *flags, struct activity *act[])
2748 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
2750 if (argv[++(*opt)]) {
2751 if (parse_values(argv[*opt], act[p]->bitmap->b_array,
2752 act[p]->bitmap->b_size, K_LOWERALL))
2755 *flags |= S_F_OPTION_P;
2763 ***************************************************************************
2764 * If option -A has been used, force -P ALL only if corresponding
2765 * option has not been explicitly entered on the command line.
2768 * @flags Common flags and system state.
2771 * @act Array of selected activities.
2772 ***************************************************************************
2774 void set_bitmaps(struct activity *act[], uint64_t *flags)
2776 if (!USE_OPTION_P(*flags)) {
2778 int p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
2779 memset(act[p]->bitmap->b_array, ~0,
2780 BITMAP_SIZE(act[p]->bitmap->b_size));
2785 ***************************************************************************
2786 * Parse devices entered on the command line and save them in activity's
2790 * @argv Argument with list of devices.
2791 * @a Activity for which devices are entered on the command line.
2792 * @max_len Max length of a device name.
2793 * @opt Index in list of arguments.
2794 * @pos Position is string where is located the first device.
2795 * @max_val If > 0 then ranges of values are allowed (e.g. 3-5,9-, etc.)
2796 * Values are in range [0..@max_val].
2799 * @opt Index on next argument.
2800 ***************************************************************************
2802 void parse_sa_devices(char *argv, struct activity *a, int max_len, int *opt, int pos,
2805 int i, val_low, val;
2809 for (t = strtok(argv + pos, ","); t; t = strtok(NULL, ",")) {
2811 /* Test ranges of values, if allowed */
2812 if ((max_val > 0) && (strlen(t) <= 16) && (strspn(t, XDIGITS) == strlen(t))) {
2813 if (parse_range_values(t, max_val, &val_low, &val) == 0) {
2814 /* This is a real range of values: Save each if its values */
2815 for (i = val_low; i <= val; i++) {
2816 snprintf(svalue, sizeof(svalue), "%d", i);
2817 svalue[sizeof(svalue) - 1] = '\0';
2818 a->item_list_sz += add_list_item(&(a->item_list), svalue, max_len);
2823 a->item_list_sz += add_list_item(&(a->item_list), t, max_len);
2825 if (a->item_list_sz) {
2826 a->options |= AO_LIST_ON_CMDLINE;
2832 ***************************************************************************
2833 * Compute network interface utilization.
2836 * @st_net_dev Structure with network interface stats.
2837 * @rx Number of bytes received per second.
2838 * @tx Number of bytes transmitted per second.
2841 * NIC utilization (0-100%).
2842 ***************************************************************************
2844 double compute_ifutil(struct stats_net_dev *st_net_dev, double rx, double tx)
2846 if (st_net_dev->speed) {
2847 unsigned long long speed = (unsigned long long) st_net_dev->speed * 1000000;
2849 if (st_net_dev->duplex == C_DUPLEX_FULL) {
2852 return (rx * 800 / speed);
2855 return (tx * 800 / speed);
2860 return ((rx + tx) * 800 / speed);
2868 ***************************************************************************
2869 * Read and replace unprintable characters in comment with ".".
2872 * @ifd Input file descriptor.
2874 ***************************************************************************
2876 void replace_nonprintable_char(int ifd, char *comment)
2881 sa_fread(ifd, comment, MAX_COMMENT_LEN, HARD_SIZE, UEOF_STOP);
2882 comment[MAX_COMMENT_LEN - 1] = '\0';
2884 /* Replace non printable chars */
2885 for (i = 0; i < strlen(comment); i++) {
2886 if (!isprint(comment[i]))
2892 ***************************************************************************
2893 * Fill the rectime and loctime structures with current record's date and
2894 * time, based on current record's "number of seconds since the epoch" saved
2896 * For loctime (if given): The timestamp is expressed in local time.
2897 * For rectime: The timestamp is expressed in UTC, in local time, or in the
2898 * time of the file's creator depending on options entered by the user on the
2902 * @l_flags Flags indicating the type of time expected by the user.
2903 * S_F_LOCAL_TIME means time should be expressed in local time.
2904 * S_F_TRUE_TIME means time should be expressed in time of
2906 * Default is time expressed in UTC (except for sar, where it
2908 * @record_hdr Record header containing the number of seconds since the
2909 * epoch, and the HH:MM:SS of the file's creator.
2912 * @rectime Structure where timestamp for current record has been saved
2913 * (in local time, in UTC or in time of file's creator
2914 * depending on options used).
2917 * 1 if an error was detected, or 0 otherwise.
2918 ***************************************************************************
2920 int sa_get_record_timestamp_struct(uint64_t l_flags, struct record_header *record_hdr,
2921 struct tstamp_ext *rectime)
2924 time_t t = (time_t) record_hdr->ust_time;
2927 rectime->epoch_time = record_hdr->ust_time;
2929 if (!PRINT_LOCAL_TIME(l_flags) && !PRINT_TRUE_TIME(l_flags)) {
2932 * (the user doesn't want local time nor time of file's creator).
2934 ltm = gmtime_r(&t, &(rectime->tm_time));
2938 * Fill generic rectime structure in local time.
2939 * Done so that we have some default values.
2941 ltm = localtime_r(&t, &(rectime->tm_time));
2942 rectime->tm_time.tm_gmtoff = TRUE;
2949 if (PRINT_TRUE_TIME(l_flags)) {
2950 /* Time of file's creator */
2951 rectime->tm_time.tm_hour = record_hdr->hour;
2952 rectime->tm_time.tm_min = record_hdr->minute;
2953 rectime->tm_time.tm_sec = record_hdr->second;
2960 ***************************************************************************
2961 * Set current record's timestamp strings (date and time) using the time
2962 * data saved in @rectime structure. The string may be the number of seconds
2963 * since the epoch if flag S_F_SEC_EPOCH has been set.
2966 * @l_flags Flags indicating the type of time expected by the user.
2967 * S_F_SEC_EPOCH means the time should be expressed in seconds
2968 * since the epoch (01/01/1970).
2969 * @cur_date String where timestamp's date will be saved. May be NULL.
2970 * @cur_time String where timestamp's time will be saved.
2971 * @len Maximum length of timestamp strings.
2972 * @rectime Structure with current timestamp (expressed in local time or
2973 * in UTC depending on whether options -T or -t have been used
2974 * or not) that should be broken down in date and time strings.
2977 * @cur_date Timestamp's date string (if expected).
2978 * @cur_time Timestamp's time string. May contain the number of seconds
2979 * since the epoch (01-01-1970) if corresponding option has
2981 ***************************************************************************
2983 void set_record_timestamp_string(uint64_t l_flags, char *cur_date, char *cur_time, int len,
2984 struct tstamp_ext *rectime)
2986 /* Set cur_time date value */
2987 if (PRINT_SEC_EPOCH(l_flags) && cur_date) {
2988 sprintf(cur_time, "%llu", rectime->epoch_time);
2989 strcpy(cur_date, "");
2993 * If options -T or -t have been used then cur_time is
2994 * expressed in local time. Else it is expressed in UTC.
2997 strftime(cur_date, len, "%Y-%m-%d", &(rectime->tm_time));
2999 if (USE_PREFD_TIME_OUTPUT(l_flags)) {
3000 strftime(cur_time, len, "%X", &(rectime->tm_time));
3003 strftime(cur_time, len, "%H:%M:%S", &(rectime->tm_time));
3009 ***************************************************************************
3010 * Print contents of a special (RESTART or COMMENT) record.
3011 * Note: This function is called only when reading a file.
3014 * @record_hdr Current record header.
3015 * @l_flags Flags for common options.
3016 * @tm_start Structure filled when option -s has been used.
3017 * @tm_end Structure filled when option -e has been used.
3018 * @rtype Record type (R_RESTART or R_COMMENT).
3019 * @ifd Input file descriptor.
3020 * @rectime Structure where timestamp (expressed in local time or in UTC
3021 * depending on whether options -T/-t have been used or not) can
3022 * be saved for current record.
3023 * @file Name of file being read.
3024 * @tab Number of tabulations to print.
3025 * @my_tz Current timezone.
3026 * @file_magic file_magic structure filled with file magic header data.
3027 * @file_hdr System activity file standard header.
3028 * @act Array of activities.
3029 * @ofmt Pointer on report output format structure.
3031 * TRUE if file's data don't match current machine's endianness.
3032 * @arch_64 TRUE if file's data come from a 64 bit machine.
3035 * @rectime Structure where timestamp (expressed in local time or in UTC)
3039 * 1 if the record has been successfully displayed, and 0 otherwise.
3040 ***************************************************************************
3042 int print_special_record(struct record_header *record_hdr, uint64_t l_flags,
3043 struct tstamp_ext *tm_start, struct tstamp_ext *tm_end, int rtype,
3044 int ifd, struct tstamp_ext *rectime, char *file, int tab, char *my_tz,
3045 struct file_magic *file_magic, struct file_header *file_hdr,
3046 struct activity *act[], struct report_format *ofmt,
3047 int endian_mismatch, int arch_64)
3049 char cur_date[TIMESTAMP_LEN], cur_time[TIMESTAMP_LEN];
3052 /* Fill timestamp structure (rectime) for current record */
3053 if (sa_get_record_timestamp_struct(l_flags, record_hdr, rectime))
3056 /* The record must be in the interval specified by -s/-e options */
3057 if ((datecmp(rectime, tm_start, FALSE) < 0) ||
3058 (datecmp(rectime, tm_end, FALSE) > 0)) {
3059 /* Will not display the special record */
3063 /* Set date and time strings to be displayed for current record */
3064 set_record_timestamp_string(l_flags, cur_date, cur_time, TIMESTAMP_LEN,
3068 if (rtype == R_RESTART) {
3071 /* Read new cpu number following RESTART record */
3072 file_hdr->sa_cpu_nr = read_nr_value(ifd, file, file_magic,
3073 endian_mismatch, arch_64, TRUE);
3076 * We don't know if CPU related activities will be displayed or not.
3077 * But if it is the case, @nr_ini will be used in the loop
3078 * to process all CPUs. So update their value here and
3079 * reallocate buffers if needed.
3080 * NB: We may have nr_allocated=0 here if the activity has
3081 * not been collected in file (or if it has an unknown format).
3083 for (p = 0; p < NR_ACT; p++) {
3084 if (HAS_PERSISTENT_VALUES(act[p]->options) && (act[p]->nr_ini > 0)) {
3085 act[p]->nr_ini = file_hdr->sa_cpu_nr;
3086 if (act[p]->nr_ini > act[p]->nr_allocated) {
3087 reallocate_all_buffers(act[p], act[p]->nr_ini);
3092 /* Ignore unknown extra structures if present */
3093 if (record_hdr->extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
3099 if (*ofmt->f_restart) {
3100 (*ofmt->f_restart)(&tab, F_MAIN, cur_date, cur_time, my_tz, file_hdr, record_hdr);
3103 else if (rtype == R_COMMENT) {
3104 char file_comment[MAX_COMMENT_LEN];
3106 /* Read and replace non printable chars in comment */
3107 replace_nonprintable_char(ifd, file_comment);
3109 /* Ignore unknown extra structures if present */
3110 if (record_hdr->extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
3113 if (!dp || !DISPLAY_COMMENT(l_flags))
3116 if (*ofmt->f_comment) {
3117 (*ofmt->f_comment)(&tab, F_MAIN, cur_date, cur_time, my_tz,
3118 file_comment, file_hdr, record_hdr);
3126 ***************************************************************************
3127 * Compute global CPU statistics as the sum of individual CPU ones, and
3128 * calculate interval for global CPU.
3129 * Also identify offline CPU.
3132 * @a Activity structure with statistics.
3133 * @prev Index in array where stats used as reference are.
3134 * @curr Index in array for current sample statistics.
3135 * @flags Flags for common options and system state.
3136 * @offline_cpu_bitmap
3137 * CPU bitmap for offline CPU.
3140 * @a Activity structure with updated statistics (those for global
3141 * CPU, and also those for offline CPU).
3142 * @offline_cpu_bitmap
3143 * CPU bitmap with offline CPU.
3146 * Interval for global CPU.
3147 ***************************************************************************
3149 unsigned long long get_global_cpu_statistics(struct activity *a, int prev, int curr,
3150 uint64_t flags, unsigned char offline_cpu_bitmap[])
3153 unsigned long long tot_jiffies_c, tot_jiffies_p;
3154 unsigned long long deltot_jiffies = 0;
3155 struct stats_cpu *scc, *scp;
3156 struct stats_cpu *scc_all = (struct stats_cpu *) ((char *) a->buf[curr]);
3157 struct stats_cpu *scp_all = (struct stats_cpu *) ((char *) a->buf[prev]);
3160 * Initial processing.
3161 * Compute CPU "all" as sum of all individual CPU. Done only on SMP machines (a->nr_ini > 1).
3162 * For UP machines we keep the values read from global CPU line in /proc/stat.
3163 * Also look for offline CPU: They won't be displayed, and some of their values may
3164 * have to be modified.
3166 if (a->nr_ini > 1) {
3167 memset(scc_all, 0, sizeof(struct stats_cpu));
3168 memset(scp_all, 0, sizeof(struct stats_cpu));
3171 for (i = 1; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
3174 * The size of a->buf[...] CPU structure may be different from the default
3175 * sizeof(struct stats_cpu) value if data have been read from a file!
3176 * That's why we don't use a syntax like:
3177 * scc = (struct stats_cpu *) a->buf[...] + i;
3179 scc = (struct stats_cpu *) ((char *) a->buf[curr] + i * a->msize);
3180 scp = (struct stats_cpu *) ((char *) a->buf[prev] + i * a->msize);
3183 * Compute the total number of jiffies spent by current processor.
3184 * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
3185 * already include them.
3187 tot_jiffies_c = scc->cpu_user + scc->cpu_nice +
3188 scc->cpu_sys + scc->cpu_idle +
3189 scc->cpu_iowait + scc->cpu_hardirq +
3190 scc->cpu_steal + scc->cpu_softirq;
3191 tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
3192 scp->cpu_sys + scp->cpu_idle +
3193 scp->cpu_iowait + scp->cpu_hardirq +
3194 scp->cpu_steal + scp->cpu_softirq;
3197 * If the CPU is offline then it is omited from /proc/stat:
3198 * All the fields couldn't have been read and the sum of them is zero.
3200 if (tot_jiffies_c == 0) {
3202 * CPU is currently offline.
3203 * Set current struct fields (which have been set to zero)
3204 * to values from previous iteration. Hence their values won't
3205 * jump from zero when the CPU comes back online.
3206 * Note that this workaround no longer fully applies with recent kernels,
3207 * as I have noticed that when a CPU comes back online, some fields
3208 * restart from their previous value (e.g. user, nice, system)
3209 * whereas others restart from zero (idle, iowait)! To deal with this,
3210 * the get_per_cpu_interval() function will set these previous values
3211 * to zero if necessary.
3216 * Mark CPU as offline to not display it
3217 * (and thus it will not be confused with a tickless CPU).
3219 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3222 if ((tot_jiffies_p == 0) && !WANT_SINCE_BOOT(flags)) {
3224 * CPU has just come back online.
3225 * Unfortunately, no reference values are available
3226 * from a previous iteration, probably because it was
3227 * already offline when the first sample has been taken.
3228 * So don't display that CPU to prevent "jump-from-zero"
3229 * output syndrome, and don't take it into account for CPU "all".
3231 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3236 * Get interval for current CPU and add it to global CPU.
3237 * Note: Previous idle and iowait values (saved in scp) may be modified here.
3239 deltot_jiffies += get_per_cpu_interval(scc, scp);
3241 scc_all->cpu_user += scc->cpu_user;
3242 scp_all->cpu_user += scp->cpu_user;
3244 scc_all->cpu_nice += scc->cpu_nice;
3245 scp_all->cpu_nice += scp->cpu_nice;
3247 scc_all->cpu_sys += scc->cpu_sys;
3248 scp_all->cpu_sys += scp->cpu_sys;
3250 scc_all->cpu_idle += scc->cpu_idle;
3251 scp_all->cpu_idle += scp->cpu_idle;
3253 scc_all->cpu_iowait += scc->cpu_iowait;
3254 scp_all->cpu_iowait += scp->cpu_iowait;
3256 scc_all->cpu_hardirq += scc->cpu_hardirq;
3257 scp_all->cpu_hardirq += scp->cpu_hardirq;
3259 scc_all->cpu_steal += scc->cpu_steal;
3260 scp_all->cpu_steal += scp->cpu_steal;
3262 scc_all->cpu_softirq += scc->cpu_softirq;
3263 scp_all->cpu_softirq += scp->cpu_softirq;
3265 scc_all->cpu_guest += scc->cpu_guest;
3266 scp_all->cpu_guest += scp->cpu_guest;
3268 scc_all->cpu_guest_nice += scc->cpu_guest_nice;
3269 scp_all->cpu_guest_nice += scp->cpu_guest_nice;
3272 return deltot_jiffies;
3276 ***************************************************************************
3277 * Compute softnet statistics for CPU "all" as the sum of individual CPU
3279 * Also identify offline CPU.
3282 * @a Activity structure with statistics.
3283 * @prev Index in array where stats used as reference are.
3284 * @curr Index in array for current sample statistics.
3285 * @flags Flags for common options and system state.
3286 * @offline_cpu_bitmap
3287 * CPU bitmap for offline CPU.
3290 * @a Activity structure with updated statistics (those for global
3291 * CPU, and also those for offline CPU).
3292 * @offline_cpu_bitmap
3293 * CPU bitmap with offline CPU.
3294 ***************************************************************************
3296 void get_global_soft_statistics(struct activity *a, int prev, int curr,
3297 uint64_t flags, unsigned char offline_cpu_bitmap[])
3300 struct stats_softnet *ssnc, *ssnp;
3301 struct stats_softnet *ssnc_all = (struct stats_softnet *) ((char *) a->buf[curr]);
3302 struct stats_softnet *ssnp_all = (struct stats_softnet *) ((char *) a->buf[prev]);
3305 * Init structures that will contain values for CPU "all".
3306 * CPU "all" doesn't exist in /proc/net/softnet_stat file, so
3307 * we compute its values as the sum of the values of each CPU.
3309 memset(ssnc_all, 0, sizeof(struct stats_softnet));
3310 memset(ssnp_all, 0, sizeof(struct stats_softnet));
3312 for (i = 1; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
3315 * The size of a->buf[...] CPU structure may be different from the default
3316 * sizeof(struct stats_softnet) value if data have been read from a file!
3317 * That's why we don't use a syntax like:
3318 * ssnc = (struct stats_softnet *) a->buf[...] + i;
3320 ssnc = (struct stats_softnet *) ((char *) a->buf[curr] + i * a->msize);
3321 ssnp = (struct stats_softnet *) ((char *) a->buf[prev] + i * a->msize);
3323 if ((ssnp->processed + ssnp->dropped + ssnp->time_squeeze +
3324 ssnp->received_rps + ssnp->flow_limit + ssnp->backlog_len == 0) &&
3325 !WANT_SINCE_BOOT(flags)) {
3327 * No previous sample for current CPU: Don't display it unless
3328 * we want stats since last boot time.
3329 * (CPU may be online but we don't display it because all
3330 * its counters would appear to jump from zero...)
3332 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3336 if (ssnc->processed + ssnc->dropped + ssnc->time_squeeze +
3337 ssnc->received_rps + ssnc->flow_limit + ssnc->backlog_len == 0) {
3338 /* Assume current CPU is offline */
3340 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3343 ssnc_all->processed += ssnc->processed;
3344 ssnc_all->dropped += ssnc->dropped;
3345 ssnc_all->time_squeeze += ssnc->time_squeeze;
3346 ssnc_all->received_rps += ssnc->received_rps;
3347 ssnc_all->flow_limit += ssnc->flow_limit;
3348 ssnc_all->backlog_len += ssnc->backlog_len;
3350 ssnp_all->processed += ssnp->processed;
3351 ssnp_all->dropped += ssnp->dropped;
3352 ssnp_all->time_squeeze += ssnp->time_squeeze;
3353 ssnp_all->received_rps += ssnp->received_rps;
3354 ssnp_all->flow_limit += ssnp->flow_limit;
3355 ssnp_all->backlog_len += ssnp->backlog_len;
3360 ***************************************************************************
3361 * Identify offline CPU (those for which all interrupts are 0) and keep
3362 * interrupts statistics (their values are persistent). Include also CPU
3363 * which have not been selected (this is necessary so that the header of the
3364 * interrupts statistics report can be displayed).
3367 * @a Activity structure with statistics.
3368 * @prev Index in array where stats used as reference are.
3369 * @curr Index in array for current sample statistics.
3370 * @flags Flags for common options and system state.
3371 * @masked_cpu_bitmap
3372 * CPU bitmap for offline and unselected CPU.
3375 * @a Activity structure with updated statistics (those for global
3376 * CPU, and also those for offline CPU).
3377 * @masked_cpu_bitmap
3378 * CPU bitmap with offline and unselected CPU.
3379 ***************************************************************************
3381 void get_global_int_statistics(struct activity *a, int prev, int curr,
3382 uint64_t flags, unsigned char masked_cpu_bitmap[])
3385 struct stats_irq *stc_cpu_sum, *stp_cpu_sum;
3387 for (i = 0; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
3390 * The size of a->buf[...] CPU structure may be different from the default
3391 * sizeof(struct stats_irq) value if data have been read from a file!
3392 * That's why we don't use a syntax like:
3393 * stc_cpu_sum = (struct stats_irq *) a->buf[...] + i;
3395 stc_cpu_sum = (struct stats_irq *) ((char *) a->buf[curr] + i * a->msize * a->nr2);
3396 stp_cpu_sum = (struct stats_irq *) ((char *) a->buf[prev] + i * a->msize * a->nr2);
3399 * Check if current CPU is back online but with no previous sample for it,
3400 * or if it has not been selected.
3402 if (((stp_cpu_sum->irq_nr == 0) && !WANT_SINCE_BOOT(flags)) ||
3403 (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))) {
3404 /* CPU should not be displayed */
3405 masked_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3409 if (stc_cpu_sum->irq_nr == 0) {
3410 /* Assume current CPU is offline */
3411 masked_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3412 memcpy(stc_cpu_sum, stp_cpu_sum, (size_t) a->msize * a->nr2);
3419 ***************************************************************************
3420 * Get filesystem name to display. This may be either the persistent name
3421 * if requested by the user, the standard filesystem name (e.g. /dev/sda1,
3422 * /dev/sdb3, etc.) or the mount point. This is used when displaying
3423 * filesystem statistics: sar -F or sadf -- -F).
3426 * @a Activity structure.
3427 * @flags Flags for common options and system state.
3428 * @st_fs Statistics for current filesystem.
3431 * Filesystem name to display.
3432 ***************************************************************************
3434 char *get_fs_name_to_display(struct activity *a, uint64_t flags, struct stats_filesystem *st_fs)
3436 char *pname = NULL, *persist_dev_name;
3438 if (DISPLAY_PERSIST_NAME_S(flags) && !DISPLAY_MOUNT(a->opt_flags)) {
3439 char fname[MAX_FS_LEN];
3441 strncpy(fname, st_fs->fs_name, sizeof(fname));
3442 fname[sizeof(fname) - 1] = '\0';
3443 if ((persist_dev_name = get_persistent_name_from_pretty(basename(fname))) != NULL) {
3444 pname = persist_dev_name;
3448 pname = DISPLAY_MOUNT(a->opt_flags) ? st_fs->mountp : st_fs->fs_name;
3454 * **************************************************************************
3455 * Make a few checks on timestamps entered with options -s/-e.
3458 * @tm_start Timestamp entered with option -s.
3459 * @tm_end Timestamp entered with option -e.
3462 * 1 if an error has been detected.
3463 ***************************************************************************
3465 int check_time_limits(struct tstamp_ext *tm_start, struct tstamp_ext *tm_end)
3467 if ((tm_start->use == USE_HHMMSS_T) && (tm_end->use == USE_HHMMSS_T) &&
3468 (tm_end->tm_time.tm_hour < tm_start->tm_time.tm_hour)) {
3469 tm_end->tm_time.tm_hour += 24;
3472 if ((tm_start->use == USE_EPOCH_T) && (tm_end->use == USE_EPOCH_T) &&
3473 (tm_end->epoch_time < tm_start->epoch_time))
3479 #endif /* SOURCE_SADC undefined */