2 * sar and sadf common routines.
3 * (C) 1999-2021 by Sebastien GODARD (sysstat <at> orange.fr)
5 ***************************************************************************
6 * This program is free software; you can redistribute it and/or modify it *
7 * under the terms of the GNU General Public License as published by the *
8 * Free Software Foundation; either version 2 of the License, or (at your *
9 * option) any later version. *
11 * This program is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY *
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
16 * You should have received a copy of the GNU General Public License along *
17 * with this program; if not, write to the Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA *
19 ***************************************************************************
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};
57 unsigned int nr_types_nr[] = {0, 0, 1};
60 ***************************************************************************
61 * Look for activity in array.
64 * @act Array of activities.
65 * @act_flag Activity flag to look for.
66 * @stop TRUE if sysstat should exit when activity is not found.
69 * Position of activity in array, or -1 if not found (this may happen when
70 * reading data from a system activity file created by another version of
72 ***************************************************************************
74 int get_activity_position(struct activity *act[], unsigned int act_flag, int stop)
78 for (i = 0; i < NR_ACT; i++) {
79 if (act[i]->id == act_flag)
84 PANIC((int) act_flag);
91 ***************************************************************************
92 * Count number of activities with given option.
95 * @act Array of activities.
96 * @option Option that activities should have to be counted
97 * (eg. AO_COLLECTED...)
98 * @count_outputs TRUE if each output should be counted for activities with
102 * Number of selected activities
103 ***************************************************************************
105 int get_activity_nr(struct activity *act[], unsigned int option, int count_outputs)
110 for (i = 0; i < NR_ACT; i++) {
111 if ((act[i]->options & option) == option) {
113 if (HAS_MULTIPLE_OUTPUTS(act[i]->options) && count_outputs) {
114 for (msk = 1; msk < 0x100; msk <<= 1) {
115 if ((act[i]->opt_flags & 0xff) & msk) {
130 ***************************************************************************
131 * Look for the most recent of saDD and saYYYYMMDD to decide which one to
132 * use. If neither exists then use saDD by default.
135 * @sa_dir Directory where standard daily data files are saved.
136 * @rectime Structure containing the current date.
139 * @sa_name 0 to use saDD data files,
140 * 1 to use saYYYYMMDD data files.
141 ***************************************************************************
143 void guess_sa_name(char *sa_dir, struct tm *rectime, int *sa_name)
145 char filename[MAX_FILE_LEN];
150 /* Use saDD by default */
153 /* Look for saYYYYMMDD */
154 snprintf(filename, sizeof(filename),
155 "%s/sa%04d%02d%02d", sa_dir,
156 rectime->tm_year + 1900,
159 filename[sizeof(filename) - 1] = '\0';
161 if (stat(filename, &sb) < 0)
162 /* Cannot find or access saYYYYMMDD, so use saDD */
164 sa_mtime = sb.st_mtime;
165 nsec = sb.st_mtim.tv_nsec;
168 snprintf(filename, sizeof(filename),
171 filename[sizeof(filename) - 1] = '\0';
173 if (stat(filename, &sb) < 0) {
174 /* Cannot find or access saDD, so use saYYYYMMDD */
179 if ((sa_mtime > sb.st_mtime) ||
180 ((sa_mtime == sb.st_mtime) && (nsec > sb.st_mtim.tv_nsec))) {
181 /* saYYYYMMDD is more recent than saDD, so use it */
187 ***************************************************************************
188 * Set current daily data file name.
191 * @datafile If not an empty string then this is the alternate directory
192 * location where daily data files will be saved.
193 * @d_off Day offset (number of days to go back in the past).
194 * @sa_name 0 for saDD data files,
195 * 1 for saYYYYMMDD data files,
196 * -1 if unknown. In this case, will look for the most recent
197 * of saDD and saYYYYMMDD and use it.
200 * @datafile Name of daily data file.
201 ***************************************************************************
203 void set_default_file(char *datafile, int d_off, int sa_name)
205 char sa_dir[MAX_FILE_LEN];
206 struct tm rectime = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL};
209 /* Set directory where daily data files will be saved */
211 strncpy(sa_dir, datafile, sizeof(sa_dir));
214 strncpy(sa_dir, SA_DIR, sizeof(sa_dir));
216 sa_dir[sizeof(sa_dir) - 1] = '\0';
218 get_time(&rectime, d_off);
221 * Look for the most recent of saDD and saYYYYMMDD
222 * and use it. If neither exists then use saDD.
223 * sa_name is set accordingly.
225 guess_sa_name(sa_dir, &rectime, &sa_name);
228 /* Using saYYYYMMDD data files */
229 err = snprintf(datafile, MAX_FILE_LEN,
230 "%s/sa%04d%02d%02d", sa_dir,
231 rectime.tm_year + 1900,
236 /* Using saDD data files */
237 err = snprintf(datafile, MAX_FILE_LEN,
241 datafile[MAX_FILE_LEN - 1] = '\0';
243 if ((err < 0) || (err >= MAX_FILE_LEN)) {
244 fprintf(stderr, "%s: %s\n", __FUNCTION__, datafile);
248 default_file_used = TRUE;
251 fprintf(stderr, "%s: Datafile: %s\n", __FUNCTION__, datafile);
256 ***************************************************************************
257 * Check data file type. If it is a directory then this is the alternate
258 * location where daily data files will be saved.
261 * @datafile Name of the daily data file. May be a directory.
262 * @d_off Day offset (number of days to go back in the past).
263 * @sa_name 0 for saDD data files,
264 * 1 for saYYYYMMDD data files,
265 * -1 if unknown. In this case, will look for the most recent
266 * of saDD and saYYYYMMDD and use it.
270 * @datafile Name of the daily data file. This is now a plain file, not
274 * 1 if @datafile was a directory, and 0 otherwise.
275 ***************************************************************************
277 int check_alt_sa_dir(char *datafile, int d_off, int sa_name)
279 if (check_dir(datafile)) {
281 * This is a directory: So append
282 * the default file name to it.
284 set_default_file(datafile, d_off, sa_name);
292 ***************************************************************************
293 * Display sysstat version used to create system activity data file.
296 * @st Output stream (stderr or stdout).
297 * @file_magic File magic header.
298 ***************************************************************************
300 void display_sa_file_version(FILE *st, struct file_magic *file_magic)
302 fprintf(st, _("File created by sar/sadc from sysstat version %d.%d.%d"),
303 file_magic->sysstat_version,
304 file_magic->sysstat_patchlevel,
305 file_magic->sysstat_sublevel);
307 if (file_magic->sysstat_extraversion) {
308 fprintf(st, ".%d", file_magic->sysstat_extraversion);
314 ***************************************************************************
315 * An invalid system activity file has been opened for reading.
316 * If this file was created by an old version of sysstat, tell it to the
320 * @fd Descriptor of the file that has been opened.
321 * @file_magic file_magic structure filled with file magic header data.
322 * May contain invalid data.
323 * @file Name of the file being read.
324 * @n Number of bytes read while reading file magic header.
325 * This function may also be called after failing to read file
326 * standard header, or if CPU activity has not been found in
327 * file. In this case, n is set to 0.
328 ***************************************************************************
330 void handle_invalid_sa_file(int fd, struct file_magic *file_magic, char *file,
333 fprintf(stderr, _("Invalid system activity file: %s\n"), file);
335 if (n == FILE_MAGIC_SIZE) {
336 if ((file_magic->sysstat_magic == SYSSTAT_MAGIC) || (file_magic->sysstat_magic == SYSSTAT_MAGIC_SWAPPED)) {
337 /* This is a sysstat file, but this file has an old format */
338 display_sa_file_version(stderr, file_magic);
341 _("Current sysstat version cannot read the format of this file (%#x)\n"),
342 file_magic->sysstat_magic == SYSSTAT_MAGIC ?
343 file_magic->format_magic : __builtin_bswap16(file_magic->format_magic));
352 ***************************************************************************
353 * Display an error message then exit.
354 ***************************************************************************
356 void print_collect_error(void)
358 fprintf(stderr, _("Requested activities not available\n"));
363 ***************************************************************************
364 * Fill system activity file magic header.
367 * @file_magic System activity file magic header.
368 ***************************************************************************
370 void enum_version_nr(struct file_magic *fm)
375 fm->sysstat_extraversion = 0;
377 strcpy(version, VERSION);
379 /* Get version number */
380 if ((v = strtok(version, ".")) == NULL)
382 fm->sysstat_version = atoi(v) & 0xff;
384 /* Get patchlevel number */
385 if ((v = strtok(NULL, ".")) == NULL)
387 fm->sysstat_patchlevel = atoi(v) & 0xff;
389 /* Get sublevel number */
390 if ((v = strtok(NULL, ".")) == NULL)
392 fm->sysstat_sublevel = atoi(v) & 0xff;
394 /* Get extraversion number. Don't necessarily exist */
395 if ((v = strtok(NULL, ".")) == NULL)
397 fm->sysstat_extraversion = atoi(v) & 0xff;
401 ***************************************************************************
402 * Write data to file. If the write() call was interrupted by a signal, try
403 * again so that the whole buffer can be written.
406 * @fd Output file descriptor.
408 * @nr_bytes Number of bytes to write.
411 * Number of bytes written to file, or -1 on error.
412 ***************************************************************************
414 int write_all(int fd, const void *buf, int nr_bytes)
416 int block, offset = 0;
417 char *buffer = (char *) buf;
419 while (nr_bytes > 0) {
420 block = write(fd, &buffer[offset], nr_bytes);
439 ***************************************************************************
440 * Allocate structures.
443 * @act Array of activities.
444 ***************************************************************************
446 void allocate_structures(struct activity *act[])
450 for (i = 0; i < NR_ACT; i++) {
451 if (act[i]->nr_ini > 0) {
452 for (j = 0; j < 3; j++) {
453 SREALLOC(act[i]->buf[j], void,
454 (size_t) act[i]->msize * (size_t) act[i]->nr_ini * (size_t) act[i]->nr2);
456 act[i]->nr_allocated = act[i]->nr_ini;
462 ***************************************************************************
466 * @act Array of activities.
467 ***************************************************************************
469 void free_structures(struct activity *act[])
473 for (i = 0; i < NR_ACT; i++) {
474 if (act[i]->nr_allocated > 0) {
475 for (j = 0; j < 3; j++) {
476 if (act[i]->buf[j]) {
477 free(act[i]->buf[j]);
478 act[i]->buf[j] = NULL;
481 act[i]->nr_allocated = 0;
487 ***************************************************************************
488 * Reallocate all the buffers for a given activity.
491 * @a Activity whose buffers need to be reallocated.
492 * @nr_min Minimum number of items that the new buffers should be able
494 ***************************************************************************
496 void reallocate_all_buffers(struct activity *a, __nr_t nr_min)
504 if (!a->nr_allocated) {
508 nr_realloc = a->nr_allocated;
510 nr_realloc = nr_realloc * 2;
512 while (nr_realloc < nr_min);
515 for (j = 0; j < 3; j++) {
516 SREALLOC(a->buf[j], void,
517 (size_t) a->msize * nr_realloc * (size_t) a->nr2);
518 /* Init additional space which has been allocated */
519 if (a->nr_allocated) {
520 memset(a->buf[j] + a->msize * a->nr_allocated * a->nr2, 0,
521 (size_t) a->msize * (size_t) (nr_realloc - a->nr_allocated) * (size_t) a->nr2);
525 a->nr_allocated = nr_realloc;
529 ***************************************************************************
530 * Check if we are close enough to desired interval.
533 * @uptime_ref Uptime used as reference. This is the system uptime for the
534 * first sample statistics, or the first system uptime after a
535 * LINUX RESTART (in 1/100th of a second).
536 * @uptime Current system uptime (in 1/100th of a second).
537 * @reset TRUE if @last_uptime should be reset with @uptime_ref.
538 * @interval Interval of time.
541 * TRUE if we are actually close enough to desired interval, FALSE otherwise.
542 ***************************************************************************
544 int next_slice(unsigned long long uptime_ref, unsigned long long uptime,
545 int reset, long interval)
547 unsigned long file_interval, entry;
548 static unsigned long long last_uptime = 0;
549 int min, max, pt1, pt2;
552 /* uptime is expressed in 1/100th of a second */
553 if (!last_uptime || reset) {
554 last_uptime = uptime_ref;
557 /* Interval cannot be greater than 0xffffffff here */
558 f = ((double) ((uptime - last_uptime) & 0xffffffff)) / 100;
559 file_interval = (unsigned long) f;
560 if ((f * 10) - (file_interval * 10) >= 5) {
561 file_interval++; /* Rounding to correct value */
564 last_uptime = uptime;
567 /* Smallest time interval: Always close enough to desired interval */
571 * A few notes about the "algorithm" used here to display selected entries
572 * from the system activity file (option -f with -i flag):
573 * Let Iu be the interval value given by the user on the command line,
574 * In the interval between current and previous sample,
575 * and En the current sample (identified by its time stamp) in the file.
576 * En will ne displayed if there is an integer p so that:
577 * p * Iu belongs to [En - In/2, En + In/2[.
579 f = ((double) ((uptime - uptime_ref) & 0xffffffff)) / 100;
580 entry = (unsigned long) f;
581 if ((f * 10) - (entry * 10) >= 5) {
585 min = entry - (file_interval / 2);
586 max = entry + (file_interval / 2) + (file_interval & 0x1);
587 pt1 = (entry / interval) * interval;
588 pt2 = ((entry / interval) + 1) * interval;
590 return (((pt1 >= min) && (pt1 < max)) || ((pt2 >= min) && (pt2 < max)));
594 ***************************************************************************
595 * Use time stamp to fill tstamp structure.
598 * @timestamp Timestamp to decode (format: HH:MM:SS).
601 * @tse Structure containing the decoded timestamp.
604 * 0 if the timestamp has been successfully decoded, 1 otherwise.
605 ***************************************************************************
607 int decode_timestamp(char timestamp[], struct tstamp *tse)
609 timestamp[2] = timestamp[5] = '\0';
610 tse->tm_sec = atoi(×tamp[6]);
611 tse->tm_min = atoi(×tamp[3]);
612 tse->tm_hour = atoi(timestamp);
614 if ((tse->tm_sec < 0) || (tse->tm_sec > 59) ||
615 (tse->tm_min < 0) || (tse->tm_min > 59) ||
616 (tse->tm_hour < 0) || (tse->tm_hour > 23))
625 ***************************************************************************
626 * Compare two timestamps.
629 * @rectime Date and time for current sample.
630 * @tse Timestamp used as reference.
631 * @cross_day TRUE if a new day has been started.
634 * A positive value if @rectime is greater than @tse,
635 * a negative one otherwise.
636 ***************************************************************************
638 int datecmp(struct tm *rectime, struct tstamp *tse, int cross_day)
640 int tm_hour = rectime->tm_hour;
644 * This is necessary if we want to properly handle something like:
645 * sar -s time_start -e time_end with
646 * time_start(day D) > time_end(day D+1)
651 if (tm_hour == tse->tm_hour) {
652 if (rectime->tm_min == tse->tm_min)
653 return (rectime->tm_sec - tse->tm_sec);
655 return (rectime->tm_min - tse->tm_min);
658 return (tm_hour - tse->tm_hour);
662 ***************************************************************************
663 * Parse a timestamp entered on the command line (hh:mm[:ss]) and decode it.
666 * @argv Arguments list.
667 * @opt Index in the arguments list.
668 * @def_timestamp Default timestamp to use.
671 * @tse Structure containing the decoded timestamp.
674 * 0 if the timestamp has been successfully decoded, 1 otherwise.
675 ***************************************************************************
677 int parse_timestamp(char *argv[], int *opt, struct tstamp *tse,
678 const char *def_timestamp)
682 if (argv[++(*opt)]) {
683 switch (strlen(argv[*opt])) {
686 strncpy(timestamp, argv[(*opt)++], 5);
688 strcat(timestamp, ":00");
692 strncpy(timestamp, argv[(*opt)++], 8);
696 strncpy(timestamp, def_timestamp, 8);
700 strncpy(timestamp, def_timestamp, 8);
704 return decode_timestamp(timestamp, tse);
708 ***************************************************************************
709 * Set interval value.
712 * @record_hdr_curr Record with current sample statistics.
713 * @record_hdr_prev Record with previous sample statistics.
716 * @itv Interval of time in 1/100th of a second.
717 ***************************************************************************
719 void get_itv_value(struct record_header *record_hdr_curr,
720 struct record_header *record_hdr_prev,
721 unsigned long long *itv)
723 /* Interval value in jiffies */
724 *itv = get_interval(record_hdr_prev->uptime_cs,
725 record_hdr_curr->uptime_cs);
729 ***************************************************************************
730 * Fill the rectime structure with the file's creation date, based on file's
731 * time data saved in file header.
732 * The resulting timestamp is expressed in the locale of the file creator or
733 * in the user's own locale, depending on whether option -t has been used
737 * @flags Flags for common options and system state.
738 * @file_hdr System activity file standard header.
741 * @rectime Date (and possibly time) from file header. Only the date,
742 * not the time, should be used by the caller.
743 ***************************************************************************
745 void get_file_timestamp_struct(uint64_t flags, struct tm *rectime,
746 struct file_header *file_hdr)
748 if (PRINT_TRUE_TIME(flags)) {
749 /* Get local time. This is just to fill fields with a default value. */
750 get_time(rectime, 0);
752 rectime->tm_mday = file_hdr->sa_day;
753 rectime->tm_mon = file_hdr->sa_month;
754 rectime->tm_year = file_hdr->sa_year;
756 * Call mktime() to set DST (Daylight Saving Time) flag.
757 * Has anyone a better way to do it?
759 rectime->tm_hour = rectime->tm_min = rectime->tm_sec = 0;
763 localtime_r((const time_t *) &file_hdr->sa_ust_time, rectime);
768 ***************************************************************************
769 * Print report header.
772 * @flags Flags for common options and system state.
773 * @file_hdr System activity file standard header.
776 * @rectime Date and time from file header.
777 ***************************************************************************
779 void print_report_hdr(uint64_t flags, struct tm *rectime,
780 struct file_header *file_hdr)
783 /* Get date of file creation */
784 get_file_timestamp_struct(flags, rectime, file_hdr);
787 * Display the header.
788 * NB: Number of CPU (value in [1, NR_CPUS + 1]).
789 * 1 means that there is only one proc and non SMP kernel.
790 * 2 means one proc and SMP kernel. Etc.
792 print_gal_header(rectime, file_hdr->sa_sysname, file_hdr->sa_release,
793 file_hdr->sa_nodename, file_hdr->sa_machine,
794 file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1,
799 ***************************************************************************
800 * Network interfaces may now be registered (and unregistered) dynamically.
801 * This is what we try to guess here.
804 * @a Activity structure with statistics.
805 * @curr Index in array for current sample statistics.
806 * @ref Index in array for sample statistics used as reference.
807 * @pos Index on current network interface.
810 * Position of current network interface in array of sample statistics used
812 * -1 if it is a new interface (it was not present in array of stats used
814 * -2 if it is a known interface but which has been unregistered then
815 * registered again on the interval.
816 ***************************************************************************
818 int check_net_dev_reg(struct activity *a, int curr, int ref, int pos)
820 struct stats_net_dev *sndc, *sndp;
825 * No items found in previous iteration:
826 * Current interface is necessarily new.
830 if (j >= a->nr[ref]) {
835 sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + pos * a->msize);
838 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + j * a->msize);
840 if (!strcmp(sndc->interface, sndp->interface)) {
842 * Network interface found.
843 * If a counter has decreased, then we may assume that the
844 * corresponding interface was unregistered, then registered again.
846 if ((sndc->rx_packets < sndp->rx_packets) ||
847 (sndc->tx_packets < sndp->tx_packets) ||
848 (sndc->rx_bytes < sndp->rx_bytes) ||
849 (sndc->tx_bytes < sndp->tx_bytes) ||
850 (sndc->rx_compressed < sndp->rx_compressed) ||
851 (sndc->tx_compressed < sndp->tx_compressed) ||
852 (sndc->multicast < sndp->multicast)) {
855 * Special processing for rx_bytes (_packets) and
856 * tx_bytes (_packets) counters: If the number of
857 * bytes (packets) has decreased, whereas the number of
858 * packets (bytes) has increased, then assume that the
859 * relevant counter has met an overflow condition, and that
860 * the interface was not unregistered, which is all the
861 * more plausible that the previous value for the counter
862 * was > ULLONG_MAX/2.
863 * NB: the average value displayed will be wrong in this case...
865 * If such an overflow is detected, just set the flag. There is no
866 * need to handle this in a special way: the difference is still
867 * properly calculated if the result is of the same type (i.e.
868 * unsigned long) as the two values.
872 if ((sndc->rx_bytes < sndp->rx_bytes) &&
873 (sndc->rx_packets > sndp->rx_packets) &&
874 (sndp->rx_bytes > (~0ULL >> 1))) {
877 if ((sndc->tx_bytes < sndp->tx_bytes) &&
878 (sndc->tx_packets > sndp->tx_packets) &&
879 (sndp->tx_bytes > (~0ULL >> 1))) {
882 if ((sndc->rx_packets < sndp->rx_packets) &&
883 (sndc->rx_bytes > sndp->rx_bytes) &&
884 (sndp->rx_packets > (~0ULL >> 1))) {
887 if ((sndc->tx_packets < sndp->tx_packets) &&
888 (sndc->tx_bytes > sndp->tx_bytes) &&
889 (sndp->tx_packets > (~0ULL >> 1))) {
895 * OK: Assume here that the device was
896 * actually unregistered.
902 if (++j >= a->nr[ref]) {
908 /* This is a newly registered interface */
913 ***************************************************************************
914 * Network interfaces may now be registered (and unregistered) dynamically.
915 * This is what we try to guess here.
918 * @a Activity structure with statistics.
919 * @curr Index in array for current sample statistics.
920 * @ref Index in array for sample statistics used as reference.
921 * @pos Index on current network interface.
924 * Position of current network interface in array of sample statistics used
926 * -1 if it is a newly registered interface.
927 * -2 if it is a known interface but which has been unregistered then
928 * registered again on the interval.
929 ***************************************************************************
931 int check_net_edev_reg(struct activity *a, int curr, int ref, int pos)
933 struct stats_net_edev *snedc, *snedp;
938 * No items found in previous iteration:
939 * Current interface is necessarily new.
943 if (j >= a->nr[ref]) {
948 snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + pos * a->msize);
951 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + j * a->msize);
953 if (!strcmp(snedc->interface, snedp->interface)) {
955 * Network interface found.
956 * If a counter has decreased, then we may assume that the
957 * corresponding interface was unregistered, then registered again.
959 if ((snedc->tx_errors < snedp->tx_errors) ||
960 (snedc->collisions < snedp->collisions) ||
961 (snedc->rx_dropped < snedp->rx_dropped) ||
962 (snedc->tx_dropped < snedp->tx_dropped) ||
963 (snedc->tx_carrier_errors < snedp->tx_carrier_errors) ||
964 (snedc->rx_frame_errors < snedp->rx_frame_errors) ||
965 (snedc->rx_fifo_errors < snedp->rx_fifo_errors) ||
966 (snedc->tx_fifo_errors < snedp->tx_fifo_errors))
968 * OK: assume here that the device was
969 * actually unregistered.
975 if (++j >= a->nr[ref]) {
981 /* This is a newly registered interface */
986 ***************************************************************************
987 * Disks may be registered dynamically (true in /proc/diskstats file).
988 * This is what we try to guess here.
991 * @a Activity structure with statistics.
992 * @curr Index in array for current sample statistics.
993 * @ref Index in array for sample statistics used as reference.
994 * @pos Index on current disk.
997 * Position of current disk in array of sample statistics used as reference
998 * -1 if it is a newly registered device.
999 * -2 if it is a known device but which has been unregistered then registered
1000 * again on the interval.
1001 ***************************************************************************
1003 int check_disk_reg(struct activity *a, int curr, int ref, int pos)
1005 struct stats_disk *sdc, *sdp;
1010 * No items found in previous iteration:
1011 * Current interface is necessarily new.
1015 if (j >= a->nr[ref]) {
1020 sdc = (struct stats_disk *) ((char *) a->buf[curr] + pos * a->msize);
1023 sdp = (struct stats_disk *) ((char *) a->buf[ref] + j * a->msize);
1025 if ((sdc->major == sdp->major) &&
1026 (sdc->minor == sdp->minor)) {
1029 * If all the counters have decreased then the likelyhood
1030 * is that the disk has been unregistered and a new disk inserted.
1031 * If only one or two have decreased then the likelyhood
1032 * is that the counter has simply wrapped.
1033 * Don't take into account a counter if its previous value was 0
1034 * (this may be a read-only device, or a kernel that doesn't
1035 * support discard stats yet...)
1037 if ((sdc->nr_ios < sdp->nr_ios) &&
1038 (!sdp->rd_sect || (sdc->rd_sect < sdp->rd_sect)) &&
1039 (!sdp->wr_sect || (sdc->wr_sect < sdp->wr_sect)) &&
1040 (!sdp->dc_sect || (sdc->dc_sect < sdp->dc_sect)))
1041 /* Same device registered again */
1046 if (++j >= a->nr[ref]) {
1052 /* This is a newly registered device */
1057 ***************************************************************************
1058 * Allocate bitmaps for activities that have one.
1061 * @act Array of activities.
1062 ***************************************************************************
1064 void allocate_bitmaps(struct activity *act[])
1068 for (i = 0; i < NR_ACT; i++) {
1070 * If current activity has a bitmap which has not already
1071 * been allocated, then allocate it.
1072 * Note that a same bitmap may be used by several activities.
1074 if (act[i]->bitmap && !act[i]->bitmap->b_array) {
1075 SREALLOC(act[i]->bitmap->b_array, unsigned char,
1076 BITMAP_SIZE(act[i]->bitmap->b_size));
1082 ***************************************************************************
1083 * Free bitmaps for activities that have one.
1086 * @act Array of activities.
1087 ***************************************************************************
1089 void free_bitmaps(struct activity *act[])
1093 for (i = 0; i < NR_ACT; i++) {
1094 if (act[i]->bitmap && act[i]->bitmap->b_array) {
1095 free(act[i]->bitmap->b_array);
1096 /* Set pointer to NULL to prevent it from being freed again */
1097 act[i]->bitmap->b_array = NULL;
1103 ***************************************************************************
1104 * Select all activities, even if they have no associated items.
1107 * @act Array of activities.
1110 * @act Array of activities, all of the being selected.
1111 ***************************************************************************
1113 void select_all_activities(struct activity *act[])
1117 for (i = 0; i < NR_ACT; i++) {
1118 act[i]->options |= AO_SELECTED;
1123 ***************************************************************************
1124 * Select CPU activity if no other activities have been explicitly selected.
1125 * Also select CPU "all" if no other CPU has been selected.
1128 * @act Array of activities.
1131 * @act Array of activities with CPU activity selected if needed.
1132 ***************************************************************************
1134 void select_default_activity(struct activity *act[])
1138 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1140 /* Default is CPU activity... */
1141 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1143 * Yet A_CPU activity may not be available in file
1144 * since the user can choose not to collect it.
1146 act[p]->options |= AO_SELECTED;
1150 * If no CPU's have been selected then select CPU "all".
1151 * cpu_bitmap bitmap may be used by several activities (A_CPU, A_PWR_CPU...)
1153 if (!count_bits(cpu_bitmap.b_array, BITMAP_SIZE(cpu_bitmap.b_size))) {
1154 cpu_bitmap.b_array[0] |= 0x01;
1159 ***************************************************************************
1160 * Swap bytes for every numerical field in structure. Used to convert from
1161 * one endianness type (big-endian or little-endian) to the other.
1164 * @types_nr Number of fields in structure for each following types:
1165 * unsigned long long, unsigned long and int.
1166 * @ps Pointer on structure.
1167 * @is64bit TRUE if data come from a 64-bit machine.
1168 ***************************************************************************
1170 void swap_struct(unsigned int types_nr[], void *ps, int is64bit)
1176 x = (uint64_t *) ps;
1177 /* For each field of type long long (or double) */
1178 for (i = 0; i < types_nr[0]; i++) {
1179 *x = __builtin_bswap64(*x);
1180 x = (uint64_t *) ((char *) x + ULL_ALIGNMENT_WIDTH);
1184 /* For each field of type long */
1185 for (i = 0; i < types_nr[1]; i++) {
1187 *x = __builtin_bswap64(*x);
1188 x = (uint64_t *) ((char *) x + UL_ALIGNMENT_WIDTH);
1191 *y = __builtin_bswap32(*y);
1192 y = (uint32_t *) ((char *) y + UL_ALIGNMENT_WIDTH);
1199 /* For each field of type int */
1200 for (i = 0; i < types_nr[2]; i++) {
1201 *y = __builtin_bswap32(*y);
1202 y = (uint32_t *) ((char *) y + U_ALIGNMENT_WIDTH);
1207 ***************************************************************************
1208 * Map the fields of a structure containing statistics read from a file to
1209 * those of the structure known by current sysstat version.
1210 * Each structure (either read from file or from current sysstat version)
1211 * is described by 3 values: The number of [unsigned] long long integers,
1212 * the number of [unsigned] long integers following in the structure, and
1213 * last the number of [unsigned] integers.
1214 * We assume that those numbers will *never* decrease with newer sysstat
1218 * @gtypes_nr Structure description as expected for current sysstat version.
1219 * @ftypes_nr Structure description as read from file.
1220 * @ps Pointer on structure containing statistics.
1221 * @f_size Size of the structure containing statistics. This is the
1222 * size of the structure *read from file*.
1223 * @g_size Size of the structure expected by current sysstat version.
1224 * @b_size Size of the buffer pointed by @ps.
1227 * -1 if an error has been encountered, or 0 otherwise.
1228 ***************************************************************************
1230 int remap_struct(unsigned int gtypes_nr[], unsigned int ftypes_nr[],
1231 void *ps, unsigned int f_size, unsigned int g_size, size_t b_size)
1237 if (MAP_SIZE(ftypes_nr) > f_size)
1240 /* Remap [unsigned] long fields */
1241 d = gtypes_nr[0] - ftypes_nr[0];
1243 if (ftypes_nr[0] * ULL_ALIGNMENT_WIDTH < ftypes_nr[0])
1247 n = MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH,
1248 g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH);
1249 if ((ftypes_nr[0] * ULL_ALIGNMENT_WIDTH >= b_size) ||
1250 (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH + n > b_size) ||
1251 (ftypes_nr[0] * ULL_ALIGNMENT_WIDTH + n > b_size))
1254 memmove(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH,
1255 ((char *) ps) + ftypes_nr[0] * ULL_ALIGNMENT_WIDTH, n);
1257 memset(((char *) ps) + ftypes_nr[0] * ULL_ALIGNMENT_WIDTH,
1258 0, d * ULL_ALIGNMENT_WIDTH);
1261 /* Remap [unsigned] int fields */
1262 d = gtypes_nr[1] - ftypes_nr[1];
1264 if (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1265 ftypes_nr[1] * UL_ALIGNMENT_WIDTH < ftypes_nr[1])
1269 n = MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH
1270 - ftypes_nr[1] * UL_ALIGNMENT_WIDTH,
1271 g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1272 - gtypes_nr[1] * UL_ALIGNMENT_WIDTH);
1273 if ((gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1274 ftypes_nr[1] * UL_ALIGNMENT_WIDTH >= b_size) ||
1275 (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1276 gtypes_nr[1] * UL_ALIGNMENT_WIDTH + n > b_size) ||
1277 (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1278 ftypes_nr[1] * UL_ALIGNMENT_WIDTH + n > b_size))
1281 memmove(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1282 + gtypes_nr[1] * UL_ALIGNMENT_WIDTH,
1283 ((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1284 + ftypes_nr[1] * UL_ALIGNMENT_WIDTH, n);
1286 memset(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1287 + ftypes_nr[1] * UL_ALIGNMENT_WIDTH,
1288 0, d * UL_ALIGNMENT_WIDTH);
1291 /* Remap possible fields (like strings of chars) following int fields */
1292 d = gtypes_nr[2] - ftypes_nr[2];
1294 if (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1295 gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
1296 ftypes_nr[2] * U_ALIGNMENT_WIDTH < ftypes_nr[2])
1300 n = MINIMUM(f_size - ftypes_nr[0] * ULL_ALIGNMENT_WIDTH
1301 - ftypes_nr[1] * UL_ALIGNMENT_WIDTH
1302 - ftypes_nr[2] * U_ALIGNMENT_WIDTH,
1303 g_size - gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1304 - gtypes_nr[1] * UL_ALIGNMENT_WIDTH
1305 - gtypes_nr[2] * U_ALIGNMENT_WIDTH);
1306 if ((gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1307 gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
1308 ftypes_nr[2] * U_ALIGNMENT_WIDTH >= b_size) ||
1309 (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1310 gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
1311 gtypes_nr[2] * U_ALIGNMENT_WIDTH + n > b_size) ||
1312 (gtypes_nr[0] * ULL_ALIGNMENT_WIDTH +
1313 gtypes_nr[1] * UL_ALIGNMENT_WIDTH +
1314 ftypes_nr[2] * U_ALIGNMENT_WIDTH + n > b_size))
1317 memmove(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1318 + gtypes_nr[1] * UL_ALIGNMENT_WIDTH
1319 + gtypes_nr[2] * U_ALIGNMENT_WIDTH,
1320 ((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1321 + gtypes_nr[1] * UL_ALIGNMENT_WIDTH
1322 + ftypes_nr[2] * U_ALIGNMENT_WIDTH, n);
1324 memset(((char *) ps) + gtypes_nr[0] * ULL_ALIGNMENT_WIDTH
1325 + gtypes_nr[1] * UL_ALIGNMENT_WIDTH
1326 + ftypes_nr[2] * U_ALIGNMENT_WIDTH,
1327 0, d * U_ALIGNMENT_WIDTH);
1334 ***************************************************************************
1335 * Read data from a system activity data file.
1338 * @ifd Input file descriptor.
1339 * @buffer Buffer where data are read.
1340 * @size Number of bytes to read.
1341 * @mode If set to HARD_SIZE, indicate that an EOF should be considered
1343 * @oneof Set to UEOF_CONT if an unexpected end of file should not make
1344 * sadf stop. Default behavior is to stop on unexpected EOF.
1347 * 1 if EOF has been reached,
1348 * 2 if an unexpected EOF has been reached (and sadf was told to continue),
1350 ***************************************************************************
1352 int sa_fread(int ifd, void *buffer, size_t size, int mode, int oneof)
1356 if ((n = read(ifd, buffer, size)) < 0) {
1357 fprintf(stderr, _("Error while reading system activity file: %s\n"),
1363 if (!n && (mode == SOFT_SIZE))
1367 fprintf(stderr, _("End of system activity file unexpected\n"));
1368 if (oneof == UEOF_CONT)
1378 ***************************************************************************
1379 * Skip unknown extra structures present in file.
1382 * @ifd System activity data file descriptor.
1384 * TRUE if file's data don't match current machine's endianness.
1385 * @arch_64 TRUE if file's data come from a 64 bit machine.
1388 * -1 on error, 0 otherwise.
1389 ***************************************************************************
1391 int skip_extra_struct(int ifd, int endian_mismatch, int arch_64)
1394 struct extra_desc xtra_d;
1397 /* Read extra structure description */
1398 sa_fread(ifd, &xtra_d, EXTRA_DESC_SIZE, HARD_SIZE, UEOF_STOP);
1401 * We don't need to remap as the extra_desc structure won't change,
1402 * but we may need to normalize endianness anyway.
1404 if (endian_mismatch) {
1405 swap_struct(extra_desc_types_nr, &xtra_d, arch_64);
1408 /* Check values consistency */
1409 if (MAP_SIZE(xtra_d.extra_types_nr) > xtra_d.extra_size) {
1411 fprintf(stderr, "%s: extra_size=%u types=%d,%d,%d\n",
1412 __FUNCTION__, xtra_d.extra_size,
1413 xtra_d.extra_types_nr[0], xtra_d.extra_types_nr[1], xtra_d.extra_types_nr[2]);
1418 if ((xtra_d.extra_nr > MAX_EXTRA_NR) || (xtra_d.extra_size > MAX_EXTRA_SIZE)) {
1420 fprintf(stderr, "%s: extra_size=%u extra_nr=%u\n",
1421 __FUNCTION__, xtra_d.extra_size, xtra_d.extra_size);
1426 /* Ignore current unknown extra structures */
1427 for (i = 0; i < xtra_d.extra_nr; i++) {
1428 if (lseek(ifd, xtra_d.extra_size, SEEK_CUR) < xtra_d.extra_size)
1432 while (xtra_d.extra_next);
1438 ***************************************************************************
1439 * Read the record header of current sample and process it.
1442 * @ifd Input file descriptor.
1443 * @buffer Buffer where data will be read.
1444 * @record_hdr Structure where record header will be saved.
1445 * @file_hdr file_hdr structure containing data read from file standard
1447 * @arch_64 TRUE if file's data come from a 64-bit machine.
1449 * TRUE if data read from file don't match current machine's
1451 * @oneof Set to EOF_CONT if an unexpected end of file should not make
1452 * sadf stop. Default behavior is to stop on unexpected EOF.
1453 * @b_size @buffer size.
1454 * @flags Flags for common options and system state.
1455 * @ofmt Pointer on report output format structure.
1458 * @record_hdr Record header for current sample.
1461 * 1 if EOF has been reached,
1462 * 2 if an error has been encountered (e.g. unexpected EOF),
1464 ***************************************************************************
1466 int read_record_hdr(int ifd, void *buffer, struct record_header *record_hdr,
1467 struct file_header *file_hdr, int arch_64, int endian_mismatch,
1468 int oneof, size_t b_size, uint64_t flags, struct report_format *ofmt)
1473 if ((rc = sa_fread(ifd, buffer, (size_t) file_hdr->rec_size, SOFT_SIZE, oneof)) != 0)
1474 /* End of sa data file */
1477 /* Remap record header structure to that expected by current version */
1478 if (remap_struct(rec_types_nr, file_hdr->rec_types_nr, buffer,
1479 file_hdr->rec_size, RECORD_HEADER_SIZE, b_size) < 0)
1481 memcpy(record_hdr, buffer, RECORD_HEADER_SIZE);
1483 /* Normalize endianness */
1484 if (endian_mismatch) {
1485 swap_struct(rec_types_nr, record_hdr, arch_64);
1488 /* Raw output in debug mode */
1489 if (DISPLAY_DEBUG_MODE(flags) && (ofmt->id == F_RAW_OUTPUT)) {
1490 printf("# uptime_cs; %llu; ust_time; %llu; extra_next; %u; record_type; %d; HH:MM:SS; %02d:%02d:%02d\n",
1491 record_hdr->uptime_cs, record_hdr->ust_time,
1492 record_hdr->extra_next, record_hdr->record_type,
1493 record_hdr->hour, record_hdr->minute, record_hdr->second);
1497 if ((record_hdr->record_type <= 0) || (record_hdr->record_type > R_EXTRA_MAX) ||
1498 (record_hdr->hour > 23) || (record_hdr->minute > 59) || (record_hdr->second > 60)) {
1500 fprintf(stderr, "%s: record_type=%d HH:MM:SS=%02d:%02d:%02d\n",
1501 __FUNCTION__, record_hdr->record_type,
1502 record_hdr->hour, record_hdr->minute, record_hdr->second);
1508 * Skip unknown extra structures if present.
1509 * This will be done later for R_COMMENT and R_RESTART records, as extra structures
1510 * are saved after the comment or the number of CPU.
1512 if ((record_hdr->record_type != R_COMMENT) && (record_hdr->record_type != R_RESTART) &&
1513 record_hdr->extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
1516 while ((record_hdr->record_type >= R_EXTRA_MIN) && (record_hdr->record_type <= R_EXTRA_MAX)) ;
1522 ***************************************************************************
1523 * Move structures data.
1526 * @act Array of activities.
1527 * @id_seq Activity sequence in file.
1528 * @record_hdr Current record header.
1529 * @dest Index in array where stats have to be copied to.
1530 * @src Index in array where stats to copy are.
1531 ***************************************************************************
1533 void copy_structures(struct activity *act[], unsigned int id_seq[],
1534 struct record_header record_hdr[], int dest, int src)
1538 memcpy(&record_hdr[dest], &record_hdr[src], RECORD_HEADER_SIZE);
1540 for (i = 0; i < NR_ACT; i++) {
1545 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1547 memcpy(act[p]->buf[dest], act[p]->buf[src],
1548 (size_t) act[p]->msize * (size_t) act[p]->nr[src] * (size_t) act[p]->nr2);
1549 act[p]->nr[dest] = act[p]->nr[src];
1554 ***************************************************************************
1555 * Read an __nr_t value from file.
1556 * Such a value can be the new number of CPU saved after a RESTART record,
1557 * or the number of structures to read saved before the structures containing
1558 * statistics for an activity with a varying number of items in file.
1561 * @ifd Input file descriptor.
1562 * @file Name of file being read.
1563 * @file_magic file_magic structure filled with file magic header data.
1565 * TRUE if file's data don't match current machine's endianness.
1566 * @arch_64 TRUE if file's data come from a 64 bit machine.
1567 * @non_zero TRUE if value should not be zero.
1570 * __nr_t value, as read from file.
1571 ***************************************************************************
1573 __nr_t read_nr_value(int ifd, char *file, struct file_magic *file_magic,
1574 int endian_mismatch, int arch_64, int non_zero)
1578 sa_fread(ifd, &value, sizeof(__nr_t), HARD_SIZE, UEOF_STOP);
1580 /* Normalize endianness for file_activity structures */
1581 if (endian_mismatch) {
1583 swap_struct(nr_types_nr, &value, arch_64);
1586 if ((non_zero && !value) || (value < 0)) {
1588 fprintf(stderr, "%s: Value=%d\n",
1589 __FUNCTION__, value);
1591 /* Value number cannot be zero or negative */
1592 handle_invalid_sa_file(ifd, file_magic, file, 0);
1599 ***************************************************************************
1600 * Read varying part of the statistics from a daily data file.
1603 * @act Array of activities.
1604 * @curr Index in array for current sample statistics.
1605 * @ifd Input file descriptor.
1606 * @act_nr Number of activities in file.
1607 * @file_actlst Activity list in file.
1609 * TRUE if file's data don't match current machine's endianness.
1610 * @arch_64 TRUE if file's data come from a 64 bit machine.
1611 * @dfile Name of system activity data file.
1612 * @file_magic file_magic structure containing data read from file magic
1614 * @oneof Set to UEOF_CONT if an unexpected end of file should not make
1615 * sadf stop. Default behavior is to stop on unexpected EOF.
1618 * 2 if an error has been encountered (e.g. unexpected EOF),
1620 ***************************************************************************
1622 int read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
1623 struct file_activity *file_actlst, int endian_mismatch,
1624 int arch_64, char *dfile, struct file_magic *file_magic,
1628 struct file_activity *fal = file_actlst;
1632 for (i = 0; i < act_nr; i++, fal++) {
1634 /* Read __nr_t value preceding statistics structures if it exists */
1636 nr_value = read_nr_value(ifd, dfile, file_magic,
1637 endian_mismatch, arch_64, FALSE);
1643 if (nr_value > NR_MAX) {
1645 fprintf(stderr, "%s: Value=%d Max=%d\n", __FUNCTION__, nr_value, NR_MAX);
1647 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1650 if (((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0) ||
1651 (act[p]->magic != fal->magic)) {
1653 * Ignore current activity in file, which is unknown to
1654 * current sysstat version or has an unknown format.
1657 offset = (off_t) fal->size * (off_t) nr_value * (off_t) fal->nr2;
1658 if (lseek(ifd, offset, SEEK_CUR) < offset) {
1661 if (oneof == UEOF_CONT)
1669 if (nr_value > act[p]->nr_max) {
1671 fprintf(stderr, "%s: %s: Value=%d Max=%d\n",
1672 __FUNCTION__, act[p]->name, nr_value, act[p]->nr_max);
1674 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1676 act[p]->nr[curr] = nr_value;
1678 /* Reallocate buffers if needed */
1679 if (nr_value > act[p]->nr_allocated) {
1680 reallocate_all_buffers(act[p], nr_value);
1684 * For persistent activities, we must make sure that no statistics
1685 * from a previous iteration remain, especially if the number
1686 * of structures read is smaller than @nr_ini.
1688 if (HAS_PERSISTENT_VALUES(act[p]->options)) {
1689 memset(act[p]->buf[curr], 0,
1690 (size_t) act[p]->msize * (size_t) act[p]->nr_ini * (size_t) act[p]->nr2);
1693 /* OK, this is a known activity: Read the stats structures */
1694 if ((nr_value > 0) &&
1695 ((nr_value > 1) || (act[p]->nr2 > 1)) &&
1696 (act[p]->msize > act[p]->fsize)) {
1698 for (j = 0; j < (nr_value * act[p]->nr2); j++) {
1699 if (sa_fread(ifd, (char *) act[p]->buf[curr] + j * act[p]->msize,
1700 (size_t) act[p]->fsize, HARD_SIZE, oneof) > 0)
1701 /* Unexpected EOF */
1705 else if (nr_value > 0) {
1707 * Note: If msize was smaller than fsize,
1708 * then it has been set to fsize in check_file_actlst().
1710 if (sa_fread(ifd, act[p]->buf[curr],
1711 (size_t) act[p]->fsize * (size_t) nr_value * (size_t) act[p]->nr2,
1712 HARD_SIZE, oneof) > 0)
1713 /* Unexpected EOF */
1717 /* nr_value == 0: Nothing to read */
1721 /* Normalize endianness for current activity's structures */
1722 if (endian_mismatch) {
1723 for (j = 0; j < (nr_value * act[p]->nr2); j++) {
1724 swap_struct(act[p]->ftypes_nr, (char *) act[p]->buf[curr] + j * act[p]->msize,
1729 /* Remap structure's fields to those known by current sysstat version */
1730 for (j = 0; j < (nr_value * act[p]->nr2); j++) {
1731 if (remap_struct(act[p]->gtypes_nr, act[p]->ftypes_nr,
1732 (char *) act[p]->buf[curr] + j * act[p]->msize,
1733 act[p]->fsize, act[p]->msize, act[p]->msize) < 0)
1742 ***************************************************************************
1743 * Open a sysstat activity data file and read its magic structure.
1746 * @dfile Name of system activity data file.
1747 * @ignore Set to 1 if a true sysstat activity file but with a bad
1748 * format should not yield an error message. Useful with
1749 * sadf -H and sadf -c.
1752 * @fd System activity data file descriptor.
1753 * @file_magic file_magic structure containing data read from file magic
1756 * TRUE if file's data don't match current machine's endianness.
1757 * @do_swap TRUE if endianness should be normalized for sysstat_magic
1758 * and format_magic numbers.
1761 * -1 if data file is a sysstat file with an old format (which we cannot
1762 * read), 0 otherwise.
1763 ***************************************************************************
1765 int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
1766 int ignore, int *endian_mismatch, int do_swap)
1769 unsigned int fm_types_nr[] = {FILE_MAGIC_ULL_NR, FILE_MAGIC_UL_NR, FILE_MAGIC_U_NR};
1771 /* Open sa data file */
1772 if ((*fd = open(dfile, O_RDONLY)) < 0) {
1773 int saved_errno = errno;
1775 fprintf(stderr, _("Cannot open %s: %s\n"), dfile, strerror(errno));
1777 if ((saved_errno == ENOENT) && default_file_used) {
1778 fprintf(stderr, _("Please check if data collecting is enabled\n"));
1783 /* Read file magic data */
1784 n = read(*fd, file_magic, FILE_MAGIC_SIZE);
1786 if ((n != FILE_MAGIC_SIZE) ||
1787 ((file_magic->sysstat_magic != SYSSTAT_MAGIC) && (file_magic->sysstat_magic != SYSSTAT_MAGIC_SWAPPED)) ||
1788 ((file_magic->format_magic != FORMAT_MAGIC) && (file_magic->format_magic != FORMAT_MAGIC_SWAPPED) && !ignore)) {
1790 fprintf(stderr, "%s: Bytes read=%d sysstat_magic=%x format_magic=%x\n",
1791 __FUNCTION__, n, file_magic->sysstat_magic, file_magic->format_magic);
1793 /* Display error message and exit */
1794 handle_invalid_sa_file(*fd, file_magic, dfile, n);
1797 *endian_mismatch = (file_magic->sysstat_magic != SYSSTAT_MAGIC);
1798 if (*endian_mismatch) {
1800 /* Swap bytes for file_magic fields */
1801 file_magic->sysstat_magic = SYSSTAT_MAGIC;
1802 file_magic->format_magic = __builtin_bswap16(file_magic->format_magic);
1805 * Start swapping at field "header_size" position.
1806 * May not exist for older versions but in this case, it won't be used.
1808 swap_struct(fm_types_nr, &file_magic->header_size, 0);
1811 if ((file_magic->sysstat_version > 10) ||
1812 ((file_magic->sysstat_version == 10) && (file_magic->sysstat_patchlevel >= 3))) {
1813 /* header_size field exists only for sysstat versions 10.3.1 and later */
1814 if ((file_magic->header_size <= MIN_FILE_HEADER_SIZE) ||
1815 (file_magic->header_size > MAX_FILE_HEADER_SIZE)) {
1817 fprintf(stderr, "%s: header_size=%u\n",
1818 __FUNCTION__, file_magic->header_size);
1820 /* Display error message and exit */
1821 handle_invalid_sa_file(*fd, file_magic, dfile, n);
1824 if ((file_magic->sysstat_version > 11) ||
1825 ((file_magic->sysstat_version == 11) && (file_magic->sysstat_patchlevel >= 7))) {
1826 /* hdr_types_nr field exists only for sysstat versions 11.7.1 and later */
1827 if (MAP_SIZE(file_magic->hdr_types_nr) > file_magic->header_size) {
1829 fprintf(stderr, "%s: map_size=%u header_size=%u\n",
1830 __FUNCTION__, MAP_SIZE(file_magic->hdr_types_nr), file_magic->header_size);
1832 handle_invalid_sa_file(*fd, file_magic, dfile, n);
1836 if ((file_magic->format_magic != FORMAT_MAGIC) &&
1837 (file_magic->format_magic != FORMAT_MAGIC_SWAPPED))
1839 * This is an old (or new) sa datafile format to
1840 * be read by sadf (since @ignore was set to TRUE).
1848 ***************************************************************************
1849 * Open a data file, and perform various checks before reading.
1850 * NB: This is called only when reading a datafile (sar and sadf), never
1851 * when writing or appending data to a datafile.
1854 * @dfile Name of system activity data file.
1855 * @act Array of activities.
1856 * @flags Flags for common options and system state.
1859 * @ifd System activity data file descriptor.
1860 * @file_magic file_magic structure containing data read from file magic
1862 * @file_hdr file_hdr structure containing data read from file standard
1864 * @file_actlst Acvtivity list in file.
1865 * @id_seq Activity sequence.
1867 * TRUE if file's data don't match current machine's endianness.
1868 * @arch_64 TRUE if file's data come from a 64 bit machine.
1869 ***************************************************************************
1871 void check_file_actlst(int *ifd, char *dfile, struct activity *act[], uint64_t flags,
1872 struct file_magic *file_magic, struct file_header *file_hdr,
1873 struct file_activity **file_actlst, unsigned int id_seq[],
1874 int *endian_mismatch, int *arch_64)
1876 int i, j, k, p, skip;
1877 struct file_activity *fal;
1878 void *buffer = NULL;
1879 size_t bh_size = FILE_HEADER_SIZE;
1880 size_t ba_size = FILE_ACTIVITY_SIZE;
1882 /* Open sa data file and read its magic structure */
1883 if (sa_open_read_magic(ifd, dfile, file_magic,
1884 DISPLAY_HDR_ONLY(flags), endian_mismatch, TRUE) < 0)
1886 * Not current sysstat's format.
1887 * Return now so that sadf -H can display at least
1888 * file's version and magic number.
1893 * We know now that we have a *compatible* sysstat datafile format
1894 * (correct FORMAT_MAGIC value), and in this case, we should have
1895 * checked header_size value. Anyway, with a corrupted datafile,
1896 * this may not be the case. So check again.
1898 if ((file_magic->header_size <= MIN_FILE_HEADER_SIZE) ||
1899 (file_magic->header_size > MAX_FILE_HEADER_SIZE)) {
1901 fprintf(stderr, "%s: header_size=%u\n",
1902 __FUNCTION__, file_magic->header_size);
1907 /* Allocate buffer for file_header structure */
1908 if (file_magic->header_size > FILE_HEADER_SIZE) {
1909 bh_size = file_magic->header_size;
1911 SREALLOC(buffer, char, bh_size);
1913 /* Read sa data file standard header and allocate activity list */
1914 sa_fread(*ifd, buffer, (size_t) file_magic->header_size, HARD_SIZE, UEOF_STOP);
1916 * Data file header size (file_magic->header_size) may be greater or
1917 * smaller than FILE_HEADER_SIZE. Remap the fields of the file header
1918 * then copy its contents to the expected structure.
1920 if (remap_struct(hdr_types_nr, file_magic->hdr_types_nr, buffer,
1921 file_magic->header_size, FILE_HEADER_SIZE, bh_size) < 0)
1924 memcpy(file_hdr, buffer, FILE_HEADER_SIZE);
1928 /* Tell that data come from a 64 bit machine */
1929 *arch_64 = (file_hdr->sa_sizeof_long == SIZEOF_LONG_64BIT);
1931 /* Normalize endianness for file_hdr structure */
1932 if (*endian_mismatch) {
1933 swap_struct(hdr_types_nr, file_hdr, *arch_64);
1938 * NB: Compare against MAX_NR_ACT and not NR_ACT because
1939 * we are maybe reading a datafile from a future sysstat version
1940 * with more activities than known today.
1942 if ((file_hdr->sa_act_nr > MAX_NR_ACT) ||
1943 (file_hdr->act_size > MAX_FILE_ACTIVITY_SIZE) ||
1944 (file_hdr->rec_size > MAX_RECORD_HEADER_SIZE) ||
1945 (MAP_SIZE(file_hdr->act_types_nr) > file_hdr->act_size) ||
1946 (MAP_SIZE(file_hdr->rec_types_nr) > file_hdr->rec_size)) {
1948 fprintf(stderr, "%s: sa_act_nr=%d act_size=%u rec_size=%u map_size(act)=%u map_size(rec)=%u\n",
1949 __FUNCTION__, file_hdr->sa_act_nr, file_hdr->act_size, file_hdr->rec_size,
1950 MAP_SIZE(file_hdr->act_types_nr), MAP_SIZE(file_hdr->rec_types_nr));
1952 /* Maybe a "false positive" sysstat datafile? */
1956 /* Allocate buffer for file_activity structures */
1957 if (file_hdr->act_size > FILE_ACTIVITY_SIZE) {
1958 ba_size = file_hdr->act_size;
1960 SREALLOC(buffer, char, ba_size);
1961 SREALLOC(*file_actlst, struct file_activity, FILE_ACTIVITY_SIZE * file_hdr->sa_act_nr);
1964 /* Read activity list */
1966 for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
1968 /* Read current file_activity structure from file */
1969 sa_fread(*ifd, buffer, (size_t) file_hdr->act_size, HARD_SIZE, UEOF_STOP);
1972 * Data file_activity size (file_hdr->act_size) may be greater or
1973 * smaller than FILE_ACTIVITY_SIZE. Remap the fields of the file's structure
1974 * then copy its contents to the expected structure.
1976 if (remap_struct(act_types_nr, file_hdr->act_types_nr, buffer,
1977 file_hdr->act_size, FILE_ACTIVITY_SIZE, ba_size) < 0)
1979 memcpy(fal, buffer, FILE_ACTIVITY_SIZE);
1981 /* Normalize endianness for file_activity structures */
1982 if (*endian_mismatch) {
1983 swap_struct(act_types_nr, fal, *arch_64);
1987 * Every activity, known or unknown, should have
1988 * at least one item and sub-item, and a size value in
1990 * Also check that the number of items and sub-items
1991 * doesn't exceed a max value. This is necessary
1992 * because we will use @nr and @nr2 to
1993 * allocate memory to read the file contents. So we
1994 * must make sure the file is not corrupted.
1995 * NB: Another check will be made below for known
1996 * activities which have each a specific max value.
1998 if ((fal->nr < 1) || (fal->nr2 < 1) ||
1999 (fal->nr > NR_MAX) || (fal->nr2 > NR2_MAX) ||
2000 (fal->size <= 0) || (fal->size > MAX_ITEM_STRUCT_SIZE)) {
2002 fprintf(stderr, "%s: id=%d nr=%d nr2=%d size=%d\n",
2003 __FUNCTION__, fal->id, fal->nr, fal->nr2, fal->size);
2008 if ((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0)
2009 /* Unknown activity */
2013 if (fal->magic != act[p]->magic) {
2014 /* Bad magical number */
2015 if (DISPLAY_HDR_ONLY(flags)) {
2017 * This is how sadf -H knows that this
2018 * activity has an unknown format.
2020 act[p]->magic = ACTIVITY_MAGIC_UNKNOWN;
2027 /* Check max value for known activities */
2028 if (fal->nr > act[p]->nr_max) {
2030 fprintf(stderr, "%s: id=%d nr=%d nr_max=%d\n",
2031 __FUNCTION__, fal->id, fal->nr, act[p]->nr_max);
2037 * Number of fields of each type ("long long", or "long"
2038 * or "int") composing the structure with statistics may
2039 * only increase with new sysstat versions. Here, we may
2040 * be reading a file created by current sysstat version,
2041 * or by an older or a newer version.
2043 if (!(((fal->types_nr[0] >= act[p]->gtypes_nr[0]) &&
2044 (fal->types_nr[1] >= act[p]->gtypes_nr[1]) &&
2045 (fal->types_nr[2] >= act[p]->gtypes_nr[2]))
2047 ((fal->types_nr[0] <= act[p]->gtypes_nr[0]) &&
2048 (fal->types_nr[1] <= act[p]->gtypes_nr[1]) &&
2049 (fal->types_nr[2] <= act[p]->gtypes_nr[2]))) &&
2050 (act[p]->magic != ACTIVITY_MAGIC_UNKNOWN) && !DISPLAY_HDR_ONLY(flags)) {
2052 * This may not be an error (that's actually why we may have changed
2053 * the magic number for this activity above).
2054 * So, if the activity magic number has changed (e.g.: ACTIVITY_MAGIC_UNKNOWN)
2055 * and we want to display only the header, then ignore the error.
2056 * If we want to also display the stats then we must stop here because
2057 * we won't know how to map the contents of the stats structure.
2060 fprintf(stderr, "%s: id=%d file=%d,%d,%d activity=%d,%d,%d\n",
2061 __FUNCTION__, fal->id, fal->types_nr[0], fal->types_nr[1], fal->types_nr[2],
2062 act[p]->gtypes_nr[0], act[p]->gtypes_nr[1], act[p]->gtypes_nr[2]);
2067 if (MAP_SIZE(fal->types_nr) > fal->size) {
2069 fprintf(stderr, "%s: id=%d size=%u map_size=%u\n",
2070 __FUNCTION__, fal->id, fal->size, MAP_SIZE(fal->types_nr));
2077 * This is an unknown activity and we want stats about it:
2078 * This is not possible so skip it.
2082 for (k = 0; k < 3; k++) {
2083 act[p]->ftypes_nr[k] = fal->types_nr[k];
2086 if (fal->size > act[p]->msize) {
2087 act[p]->msize = fal->size;
2090 act[p]->nr_ini = fal->nr;
2091 act[p]->nr2 = fal->nr2;
2092 act[p]->fsize = fal->size;
2094 * This is a known activity with a known format
2095 * (magical number). Only such activities will be displayed.
2096 * (Well, this may also be an unknown format if we have entered sadf -H.)
2098 id_seq[j++] = fal->id;
2101 while (j < NR_ACT) {
2108 /* Check that at least one activity selected by the user is available in file */
2109 for (i = 0; i < NR_ACT; i++) {
2111 if (!IS_SELECTED(act[i]->options))
2114 /* Here is a selected activity: Does it exist in file? */
2116 for (j = 0; j < file_hdr->sa_act_nr; j++, fal++) {
2117 if (act[i]->id == fal->id)
2120 if (j == file_hdr->sa_act_nr) {
2121 /* No: Unselect it */
2122 act[i]->options &= ~AO_SELECTED;
2127 * None of selected activities exist in file: Abort.
2128 * NB: Error is ignored if we only want to display
2129 * datafile header (sadf -H).
2131 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES) && !DISPLAY_HDR_ONLY(flags)) {
2132 fprintf(stderr, _("Requested activities not available in file %s\n"),
2139 * Check if there are some extra structures.
2140 * We will just skip them as they are unknown for now.
2142 if (file_hdr->extra_next && (skip_extra_struct(*ifd, *endian_mismatch, *arch_64) < 0))
2151 handle_invalid_sa_file(*ifd, file_magic, dfile, 0);
2155 ***************************************************************************
2156 * Parse sar activities options (also used by sadf).
2159 * @argv Arguments list.
2160 * @opt Index in list of arguments.
2161 * @caller Indicate whether it's sar or sadf that called this function.
2164 * @act Array of selected activities.
2165 * @flags Common flags and system state.
2169 ***************************************************************************
2171 int parse_sar_opt(char *argv[], int *opt, struct activity *act[],
2172 uint64_t *flags, int caller)
2176 for (i = 1; *(argv[*opt] + i); i++) {
2178 * Note: argv[*opt] contains something like "-BruW"
2179 * *(argv[*opt] + i) will contain 'B', 'r', etc.
2182 switch (*(argv[*opt] + i)) {
2185 select_all_activities(act);
2186 *flags |= S_F_OPTION_A;
2189 * Force '-r ALL -u ALL -F'.
2190 * Setting -F is compulsory because corresponding activity
2191 * has AO_MULTIPLE_OUTPUTS flag set.
2192 * -P ALL / -I ALL will be set only if corresponding option has
2193 * not been exlicitly entered on the command line.
2195 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
2196 act[p]->opt_flags |= AO_F_MEMORY + AO_F_SWAP + AO_F_MEM_ALL;
2198 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
2199 act[p]->opt_flags = AO_F_CPU_ALL;
2201 p = get_activity_position(act, A_FS, EXIT_IF_NOT_FOUND);
2202 act[p]->opt_flags = AO_F_FILESYSTEM;
2206 SELECT_ACTIVITY(A_PAGE);
2210 SELECT_ACTIVITY(A_IO);
2214 *flags |= S_F_COMMENT;
2218 SELECT_ACTIVITY(A_DISK);
2222 p = get_activity_position(act, A_FS, EXIT_IF_NOT_FOUND);
2223 act[p]->options |= AO_SELECTED;
2224 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_MOUNT)) {
2226 act[p]->opt_flags |= AO_F_MOUNT;
2230 act[p]->opt_flags |= AO_F_FILESYSTEM;
2235 SELECT_ACTIVITY(A_HUGE);
2239 /* Option -h is equivalent to --pretty --human */
2240 *flags |= S_F_PRETTY + S_F_UNIT;
2244 if (!argv[*opt + 1]) {
2248 if (!strcmp(argv[*opt], K_SID)) {
2249 *flags |= S_F_DEV_SID + S_F_PRETTY;
2253 if (strnlen(argv[*opt], sizeof(persistent_name_type)) >= sizeof(persistent_name_type) - 1)
2256 strncpy(persistent_name_type, argv[*opt], sizeof(persistent_name_type) - 1);
2257 persistent_name_type[sizeof(persistent_name_type) - 1] = '\0';
2258 strtolower(persistent_name_type);
2259 if (!get_persistent_type_dir(persistent_name_type)) {
2260 fprintf(stderr, _("Invalid type of persistent device name\n"));
2263 /* Pretty print report (option -j implies option -p) */
2264 *flags |= S_F_PERSIST_NAME + S_F_PRETTY;
2269 *flags |= S_F_PRETTY;
2273 /* Option -q grouped with other ones */
2274 SELECT_ACTIVITY(A_QUEUE);
2278 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
2279 act[p]->options |= AO_SELECTED;
2280 act[p]->opt_flags |= AO_F_MEMORY;
2281 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
2283 act[p]->opt_flags |= AO_F_MEM_ALL;
2289 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
2290 act[p]->options |= AO_SELECTED;
2291 act[p]->opt_flags |= AO_F_SWAP;
2296 * Check sar option -t here (as it can be combined
2297 * with other ones, eg. "sar -rtu ..."
2298 * But sadf option -t is checked in sadf.c as it won't
2299 * be entered as a sar option after "--".
2301 if (caller != C_SAR) {
2304 *flags |= S_F_TRUE_TIME;
2308 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
2309 act[p]->options |= AO_SELECTED;
2310 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
2312 act[p]->opt_flags = AO_F_CPU_ALL;
2316 act[p]->opt_flags = AO_F_CPU_DEF;
2321 SELECT_ACTIVITY(A_KTABLES);
2325 SELECT_ACTIVITY(A_PCSW);
2329 SELECT_ACTIVITY(A_SWAP);
2333 SELECT_ACTIVITY(A_SERIAL);
2337 *flags |= S_F_ZERO_OMIT;
2352 ***************************************************************************
2353 * Parse sar "-m" option.
2356 * @argv Arguments list.
2357 * @opt Index in list of arguments.
2360 * @act Array of selected activities.
2363 * 0 on success, 1 otherwise.
2364 ***************************************************************************
2366 int parse_sar_m_opt(char *argv[], int *opt, struct activity *act[])
2370 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
2371 if (!strcmp(t, K_CPU)) {
2372 SELECT_ACTIVITY(A_PWR_CPU);
2374 else if (!strcmp(t, K_FAN)) {
2375 SELECT_ACTIVITY(A_PWR_FAN);
2377 else if (!strcmp(t, K_IN)) {
2378 SELECT_ACTIVITY(A_PWR_IN);
2380 else if (!strcmp(t, K_TEMP)) {
2381 SELECT_ACTIVITY(A_PWR_TEMP);
2383 else if (!strcmp(t, K_FREQ)) {
2384 SELECT_ACTIVITY(A_PWR_FREQ);
2386 else if (!strcmp(t, K_USB)) {
2387 SELECT_ACTIVITY(A_PWR_USB);
2389 else if (!strcmp(t, K_ALL)) {
2390 SELECT_ACTIVITY(A_PWR_CPU);
2391 SELECT_ACTIVITY(A_PWR_FAN);
2392 SELECT_ACTIVITY(A_PWR_IN);
2393 SELECT_ACTIVITY(A_PWR_TEMP);
2394 SELECT_ACTIVITY(A_PWR_FREQ);
2395 SELECT_ACTIVITY(A_PWR_USB);
2406 ***************************************************************************
2407 * Parse sar "-n" option.
2410 * @argv Arguments list.
2411 * @opt Index in list of arguments.
2414 * @act Array of selected activities.
2417 * 0 on success, 1 otherwise.
2418 ***************************************************************************
2420 int parse_sar_n_opt(char *argv[], int *opt, struct activity *act[])
2424 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
2425 if (!strcmp(t, K_DEV)) {
2426 SELECT_ACTIVITY(A_NET_DEV);
2428 else if (!strcmp(t, K_EDEV)) {
2429 SELECT_ACTIVITY(A_NET_EDEV);
2431 else if (!strcmp(t, K_SOCK)) {
2432 SELECT_ACTIVITY(A_NET_SOCK);
2434 else if (!strcmp(t, K_NFS)) {
2435 SELECT_ACTIVITY(A_NET_NFS);
2437 else if (!strcmp(t, K_NFSD)) {
2438 SELECT_ACTIVITY(A_NET_NFSD);
2440 else if (!strcmp(t, K_IP)) {
2441 SELECT_ACTIVITY(A_NET_IP);
2443 else if (!strcmp(t, K_EIP)) {
2444 SELECT_ACTIVITY(A_NET_EIP);
2446 else if (!strcmp(t, K_ICMP)) {
2447 SELECT_ACTIVITY(A_NET_ICMP);
2449 else if (!strcmp(t, K_EICMP)) {
2450 SELECT_ACTIVITY(A_NET_EICMP);
2452 else if (!strcmp(t, K_TCP)) {
2453 SELECT_ACTIVITY(A_NET_TCP);
2455 else if (!strcmp(t, K_ETCP)) {
2456 SELECT_ACTIVITY(A_NET_ETCP);
2458 else if (!strcmp(t, K_UDP)) {
2459 SELECT_ACTIVITY(A_NET_UDP);
2461 else if (!strcmp(t, K_SOCK6)) {
2462 SELECT_ACTIVITY(A_NET_SOCK6);
2464 else if (!strcmp(t, K_IP6)) {
2465 SELECT_ACTIVITY(A_NET_IP6);
2467 else if (!strcmp(t, K_EIP6)) {
2468 SELECT_ACTIVITY(A_NET_EIP6);
2470 else if (!strcmp(t, K_ICMP6)) {
2471 SELECT_ACTIVITY(A_NET_ICMP6);
2473 else if (!strcmp(t, K_EICMP6)) {
2474 SELECT_ACTIVITY(A_NET_EICMP6);
2476 else if (!strcmp(t, K_UDP6)) {
2477 SELECT_ACTIVITY(A_NET_UDP6);
2479 else if (!strcmp(t, K_FC)) {
2480 SELECT_ACTIVITY(A_NET_FC);
2482 else if (!strcmp(t, K_SOFT)) {
2483 SELECT_ACTIVITY(A_NET_SOFT);
2485 else if (!strcmp(t, K_ALL)) {
2486 SELECT_ACTIVITY(A_NET_DEV);
2487 SELECT_ACTIVITY(A_NET_EDEV);
2488 SELECT_ACTIVITY(A_NET_SOCK);
2489 SELECT_ACTIVITY(A_NET_NFS);
2490 SELECT_ACTIVITY(A_NET_NFSD);
2491 SELECT_ACTIVITY(A_NET_IP);
2492 SELECT_ACTIVITY(A_NET_EIP);
2493 SELECT_ACTIVITY(A_NET_ICMP);
2494 SELECT_ACTIVITY(A_NET_EICMP);
2495 SELECT_ACTIVITY(A_NET_TCP);
2496 SELECT_ACTIVITY(A_NET_ETCP);
2497 SELECT_ACTIVITY(A_NET_UDP);
2498 SELECT_ACTIVITY(A_NET_SOCK6);
2499 SELECT_ACTIVITY(A_NET_IP6);
2500 SELECT_ACTIVITY(A_NET_EIP6);
2501 SELECT_ACTIVITY(A_NET_ICMP6);
2502 SELECT_ACTIVITY(A_NET_EICMP6);
2503 SELECT_ACTIVITY(A_NET_UDP6);
2504 SELECT_ACTIVITY(A_NET_FC);
2505 SELECT_ACTIVITY(A_NET_SOFT);
2516 ***************************************************************************
2517 * Parse sar "-q" option.
2520 * @argv Arguments list.
2521 * @opt Index in list of arguments.
2524 * @act Array of selected activities.
2527 * 0 on success, 1 otherwise.
2528 ***************************************************************************
2530 int parse_sar_q_opt(char *argv[], int *opt, struct activity *act[])
2534 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
2535 if (!strcmp(t, K_LOAD)) {
2536 SELECT_ACTIVITY(A_QUEUE);
2538 else if (!strcmp(t, K_PSI_CPU)) {
2539 SELECT_ACTIVITY(A_PSI_CPU);
2541 else if (!strcmp(t, K_PSI_IO)) {
2542 SELECT_ACTIVITY(A_PSI_IO);
2544 else if (!strcmp(t, K_PSI_MEM)) {
2545 SELECT_ACTIVITY(A_PSI_MEM);
2547 else if (!strcmp(t, K_PSI)) {
2548 SELECT_ACTIVITY(A_PSI_CPU);
2549 SELECT_ACTIVITY(A_PSI_IO);
2550 SELECT_ACTIVITY(A_PSI_MEM);
2552 else if (!strcmp(t, K_ALL)) {
2553 SELECT_ACTIVITY(A_QUEUE);
2554 SELECT_ACTIVITY(A_PSI_CPU);
2555 SELECT_ACTIVITY(A_PSI_IO);
2556 SELECT_ACTIVITY(A_PSI_MEM);
2567 ***************************************************************************
2568 * Parse sar "-I" option.
2571 * @argv Arguments list.
2572 * @opt Index in list of arguments.
2573 * @act Array of activities.
2576 * @flags Common flags and system state.
2577 * @act Array of activities, with interrupts activity selected.
2580 * 0 on success, 1 otherwise.
2581 ***************************************************************************
2583 int parse_sar_I_opt(char *argv[], int *opt, uint64_t *flags, struct activity *act[])
2587 /* Select interrupt activity */
2588 p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
2589 act[p]->options |= AO_SELECTED;
2591 if (argv[++(*opt)]) {
2592 if (parse_values(argv[*opt], act[p]->bitmap->b_array,
2593 act[p]->bitmap->b_size, K_SUM))
2596 *flags |= S_F_OPTION_I;
2604 ***************************************************************************
2605 * Parse sar and sadf "-P" option.
2608 * @argv Arguments list.
2609 * @opt Index in list of arguments.
2610 * @act Array of activities.
2613 * @flags Common flags and system state.
2614 * @act Array of activities, with CPUs selected.
2617 * 0 on success, 1 otherwise.
2618 ***************************************************************************
2620 int parse_sa_P_opt(char *argv[], int *opt, uint64_t *flags, struct activity *act[])
2624 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
2626 if (argv[++(*opt)]) {
2627 if (parse_values(argv[*opt], act[p]->bitmap->b_array,
2628 act[p]->bitmap->b_size, K_LOWERALL))
2631 *flags |= S_F_OPTION_P;
2639 ***************************************************************************
2640 * If option -A has been used, force -P ALL -I ALL only if corresponding
2641 * option has not been explicitly entered on the command line.
2644 * @flags Common flags and system state.
2647 * @act Array of selected activities.
2648 ***************************************************************************
2650 void set_bitmaps(struct activity *act[], uint64_t *flags)
2654 if (!USE_OPTION_P(*flags)) {
2656 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
2657 memset(act[p]->bitmap->b_array, ~0,
2658 BITMAP_SIZE(act[p]->bitmap->b_size));
2661 if (!USE_OPTION_I(*flags)) {
2663 p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
2664 memset(act[p]->bitmap->b_array, ~0,
2665 BITMAP_SIZE(act[p]->bitmap->b_size));
2670 ***************************************************************************
2671 * Look for item in list.
2674 * @list Pointer on the start of the linked list.
2675 * @item_name Item name to look for.
2678 * 1 if item found in list, 0 otherwise.
2679 ***************************************************************************
2681 int search_list_item(struct sa_item *list, char *item_name)
2683 while (list != NULL) {
2684 if (!strcmp(list->item_name, item_name))
2685 return 1; /* Item found in list */
2689 /* Item not found */
2694 ***************************************************************************
2695 * Add item to the list.
2698 * @list Address of pointer on the start of the linked list.
2699 * @item_name Name of the item.
2700 * @max_len Max length of an item.
2703 * 1 if item has been added to the list (since it was not previously there),
2704 * and 0 otherwise (item already in list or item name too long).
2705 ***************************************************************************
2707 int add_list_item(struct sa_item **list, char *item_name, int max_len)
2712 if ((len = strnlen(item_name, max_len)) == max_len)
2716 while (*list != NULL) {
2718 if (!strcmp(e->item_name, item_name))
2719 return 0; /* Item found in list */
2723 /* Item not found: Add it to the list */
2724 SREALLOC(*list, struct sa_item, sizeof(struct sa_item));
2726 if ((e->item_name = (char *) malloc(len + 1)) == NULL) {
2730 strcpy(e->item_name, item_name);
2736 ***************************************************************************
2737 * Parse devices entered on the command line and save them in activity's
2741 * @argv Argument with list of devices.
2742 * @a Activity for which devices are entered on the command line.
2743 * @max_len Max length of a device name.
2744 * @opt Index in list of arguments.
2745 * @pos Position is string where is located the first device.
2748 * @opt Index on next argument.
2749 ***************************************************************************
2751 void parse_sa_devices(char *argv, struct activity *a, int max_len, int *opt, int pos)
2755 for (t = strtok(argv + pos, ","); t; t = strtok(NULL, ",")) {
2756 a->item_list_sz += add_list_item(&(a->item_list), t, max_len);
2758 if (a->item_list_sz) {
2759 a->options |= AO_LIST_ON_CMDLINE;
2765 ***************************************************************************
2766 * Compute network interface utilization.
2769 * @st_net_dev Structure with network interface stats.
2770 * @rx Number of bytes received per second.
2771 * @tx Number of bytes transmitted per second.
2774 * NIC utilization (0-100%).
2775 ***************************************************************************
2777 double compute_ifutil(struct stats_net_dev *st_net_dev, double rx, double tx)
2779 unsigned long long speed;
2781 if (st_net_dev->speed) {
2783 speed = (unsigned long long) st_net_dev->speed * 1000000;
2785 if (st_net_dev->duplex == C_DUPLEX_FULL) {
2788 return (rx * 800 / speed);
2791 return (tx * 800 / speed);
2796 return ((rx + tx) * 800 / speed);
2804 ***************************************************************************
2805 * Read and replace unprintable characters in comment with ".".
2808 * @ifd Input file descriptor.
2810 ***************************************************************************
2812 void replace_nonprintable_char(int ifd, char *comment)
2817 sa_fread(ifd, comment, MAX_COMMENT_LEN, HARD_SIZE, UEOF_STOP);
2818 comment[MAX_COMMENT_LEN - 1] = '\0';
2820 /* Replace non printable chars */
2821 for (i = 0; i < strlen(comment); i++) {
2822 if (!isprint(comment[i]))
2828 ***************************************************************************
2829 * Fill the rectime and loctime structures with current record's date and
2830 * time, based on current record's "number of seconds since the epoch" saved
2832 * For loctime (if given): The timestamp is expressed in local time.
2833 * For rectime: The timestamp is expressed in UTC, in local time, or in the
2834 * time of the file's creator depending on options entered by the user on the
2838 * @l_flags Flags indicating the type of time expected by the user.
2839 * S_F_LOCAL_TIME means time should be expressed in local time.
2840 * S_F_TRUE_TIME means time should be expressed in time of
2842 * Default is time expressed in UTC (except for sar, where it
2844 * @record_hdr Record header containing the number of seconds since the
2845 * epoch, and the HH:MM:SS of the file's creator.
2848 * @rectime Structure where timestamp for current record has been saved
2849 * (in local time, in UTC or in time of file's creator
2850 * depending on options used).
2853 * 1 if an error was detected, or 0 otherwise.
2854 ***************************************************************************
2856 int sa_get_record_timestamp_struct(uint64_t l_flags, struct record_header *record_hdr,
2863 * Fill generic rectime structure in local time.
2864 * Done so that we have some default values.
2866 ltm = localtime_r((const time_t *) &(record_hdr->ust_time), rectime);
2868 if (!PRINT_LOCAL_TIME(l_flags) && !PRINT_TRUE_TIME(l_flags)) {
2871 * (the user doesn't want local time nor time of file's creator).
2873 ltm = gmtime_r((const time_t *) &(record_hdr->ust_time), rectime);
2880 if (PRINT_TRUE_TIME(l_flags)) {
2881 /* Time of file's creator */
2882 rectime->tm_hour = record_hdr->hour;
2883 rectime->tm_min = record_hdr->minute;
2884 rectime->tm_sec = record_hdr->second;
2891 ***************************************************************************
2892 * Set current record's timestamp strings (date and time) using the time
2893 * data saved in @rectime structure. The string may be the number of seconds
2894 * since the epoch if flag S_F_SEC_EPOCH has been set.
2897 * @l_flags Flags indicating the type of time expected by the user.
2898 * S_F_SEC_EPOCH means the time should be expressed in seconds
2899 * since the epoch (01/01/1970).
2900 * @record_hdr Record header containing the number of seconds since the
2902 * @cur_date String where timestamp's date will be saved. May be NULL.
2903 * @cur_time String where timestamp's time will be saved.
2904 * @len Maximum length of timestamp strings.
2905 * @rectime Structure with current timestamp (expressed in local time or
2906 * in UTC depending on whether options -T or -t have been used
2907 * or not) that should be broken down in date and time strings.
2910 * @cur_date Timestamp's date string (if expected).
2911 * @cur_time Timestamp's time string. May contain the number of seconds
2912 * since the epoch (01-01-1970) if corresponding option has
2914 ***************************************************************************
2916 void set_record_timestamp_string(uint64_t l_flags, struct record_header *record_hdr,
2917 char *cur_date, char *cur_time, int len, struct tm *rectime)
2919 /* Set cur_time date value */
2920 if (PRINT_SEC_EPOCH(l_flags) && cur_date) {
2921 sprintf(cur_time, "%llu", record_hdr->ust_time);
2922 strcpy(cur_date, "");
2926 * If options -T or -t have been used then cur_time is
2927 * expressed in local time. Else it is expressed in UTC.
2930 strftime(cur_date, len, "%Y-%m-%d", rectime);
2932 if (USE_PREFD_TIME_OUTPUT(l_flags)) {
2933 strftime(cur_time, len, "%X", rectime);
2936 strftime(cur_time, len, "%H:%M:%S", rectime);
2942 ***************************************************************************
2943 * Print contents of a special (RESTART or COMMENT) record.
2944 * Note: This function is called only when reading a file.
2947 * @record_hdr Current record header.
2948 * @l_flags Flags for common options.
2949 * @tm_start Structure filled when option -s has been used.
2950 * @tm_end Structure filled when option -e has been used.
2951 * @rtype Record type (R_RESTART or R_COMMENT).
2952 * @ifd Input file descriptor.
2953 * @rectime Structure where timestamp (expressed in local time or in UTC
2954 * depending on whether options -T/-t have been used or not) can
2955 * be saved for current record.
2956 * @file Name of file being read.
2957 * @tab Number of tabulations to print.
2958 * @file_magic file_magic structure filled with file magic header data.
2959 * @file_hdr System activity file standard header.
2960 * @act Array of activities.
2961 * @ofmt Pointer on report output format structure.
2963 * TRUE if file's data don't match current machine's endianness.
2964 * @arch_64 TRUE if file's data come from a 64 bit machine.
2967 * @rectime Structure where timestamp (expressed in local time or in UTC)
2971 * 1 if the record has been successfully displayed, and 0 otherwise.
2972 ***************************************************************************
2974 int print_special_record(struct record_header *record_hdr, uint64_t l_flags,
2975 struct tstamp *tm_start, struct tstamp *tm_end, int rtype, int ifd,
2976 struct tm *rectime, char *file, int tab,
2977 struct file_magic *file_magic, struct file_header *file_hdr,
2978 struct activity *act[], struct report_format *ofmt,
2979 int endian_mismatch, int arch_64)
2981 char cur_date[TIMESTAMP_LEN], cur_time[TIMESTAMP_LEN];
2985 /* Fill timestamp structure (rectime) for current record */
2986 if (sa_get_record_timestamp_struct(l_flags, record_hdr, rectime))
2989 /* The record must be in the interval specified by -s/-e options */
2990 if ((tm_start->use && (datecmp(rectime, tm_start, FALSE) < 0)) ||
2991 (tm_end->use && (datecmp(rectime, tm_end, FALSE) > 0))) {
2992 /* Will not display the special record */
2996 /* Set date and time strings to be displayed for current record */
2997 set_record_timestamp_string(l_flags, record_hdr,
2998 cur_date, cur_time, TIMESTAMP_LEN, rectime);
3001 if (rtype == R_RESTART) {
3002 /* Read new cpu number following RESTART record */
3003 file_hdr->sa_cpu_nr = read_nr_value(ifd, file, file_magic,
3004 endian_mismatch, arch_64, TRUE);
3007 * We don't know if CPU related activities will be displayed or not.
3008 * But if it is the case, @nr_ini will be used in the loop
3009 * to process all CPUs. So update their value here and
3010 * reallocate buffers if needed.
3011 * NB: We may have nr_allocated=0 here if the activity has
3012 * not been collected in file (or if it has an unknown format).
3014 for (p = 0; p < NR_ACT; p++) {
3015 if (HAS_PERSISTENT_VALUES(act[p]->options)) {
3016 act[p]->nr_ini = file_hdr->sa_cpu_nr;
3017 if (act[p]->nr_ini > act[p]->nr_allocated) {
3018 reallocate_all_buffers(act[p], act[p]->nr_ini);
3023 /* Ignore unknown extra structures if present */
3024 if (record_hdr->extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
3030 if (*ofmt->f_restart) {
3031 (*ofmt->f_restart)(&tab, F_MAIN, cur_date, cur_time,
3032 !PRINT_LOCAL_TIME(l_flags) &&
3033 !PRINT_TRUE_TIME(l_flags), file_hdr, record_hdr);
3036 else if (rtype == R_COMMENT) {
3037 char file_comment[MAX_COMMENT_LEN];
3039 /* Read and replace non printable chars in comment */
3040 replace_nonprintable_char(ifd, file_comment);
3042 /* Ignore unknown extra structures if present */
3043 if (record_hdr->extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
3046 if (!dp || !DISPLAY_COMMENT(l_flags))
3049 if (*ofmt->f_comment) {
3050 (*ofmt->f_comment)(&tab, F_MAIN, cur_date, cur_time,
3051 !PRINT_LOCAL_TIME(l_flags) &&
3052 !PRINT_TRUE_TIME(l_flags), file_comment,
3053 file_hdr, record_hdr);
3061 ***************************************************************************
3062 * Compute global CPU statistics as the sum of individual CPU ones, and
3063 * calculate interval for global CPU.
3064 * Also identify offline CPU.
3067 * @a Activity structure with statistics.
3068 * @prev Index in array where stats used as reference are.
3069 * @curr Index in array for current sample statistics.
3070 * @flags Flags for common options and system state.
3071 * @offline_cpu_bitmap
3072 * CPU bitmap for offline CPU.
3075 * @a Activity structure with updated statistics (those for global
3076 * CPU, and also those for offline CPU).
3077 * @offline_cpu_bitmap
3078 * CPU bitmap with offline CPU.
3081 * Interval for global CPU.
3082 ***************************************************************************
3084 unsigned long long get_global_cpu_statistics(struct activity *a, int prev, int curr,
3085 uint64_t flags, unsigned char offline_cpu_bitmap[])
3088 unsigned long long tot_jiffies_c, tot_jiffies_p;
3089 unsigned long long deltot_jiffies = 0;
3090 struct stats_cpu *scc, *scp;
3091 struct stats_cpu *scc_all = (struct stats_cpu *) ((char *) a->buf[curr]);
3092 struct stats_cpu *scp_all = (struct stats_cpu *) ((char *) a->buf[prev]);
3095 * Initial processing.
3096 * Compute CPU "all" as sum of all individual CPU. Done only on SMP machines (a->nr_ini > 1).
3097 * For UP machines we keep the values read from global CPU line in /proc/stat.
3098 * Also look for offline CPU: They won't be displayed, and some of their values may
3099 * have to be modified.
3101 if (a->nr_ini > 1) {
3102 memset(scc_all, 0, sizeof(struct stats_cpu));
3103 memset(scp_all, 0, sizeof(struct stats_cpu));
3106 for (i = 1; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
3109 * The size of a->buf[...] CPU structure may be different from the default
3110 * sizeof(struct stats_cpu) value if data have been read from a file!
3111 * That's why we don't use a syntax like:
3112 * scc = (struct stats_cpu *) a->buf[...] + i;
3114 scc = (struct stats_cpu *) ((char *) a->buf[curr] + i * a->msize);
3115 scp = (struct stats_cpu *) ((char *) a->buf[prev] + i * a->msize);
3118 * Compute the total number of jiffies spent by current processor.
3119 * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
3120 * already include them.
3122 tot_jiffies_c = scc->cpu_user + scc->cpu_nice +
3123 scc->cpu_sys + scc->cpu_idle +
3124 scc->cpu_iowait + scc->cpu_hardirq +
3125 scc->cpu_steal + scc->cpu_softirq;
3126 tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
3127 scp->cpu_sys + scp->cpu_idle +
3128 scp->cpu_iowait + scp->cpu_hardirq +
3129 scp->cpu_steal + scp->cpu_softirq;
3132 * If the CPU is offline then it is omited from /proc/stat:
3133 * All the fields couldn't have been read and the sum of them is zero.
3135 if (tot_jiffies_c == 0) {
3137 * CPU is currently offline.
3138 * Set current struct fields (which have been set to zero)
3139 * to values from previous iteration. Hence their values won't
3140 * jump from zero when the CPU comes back online.
3141 * Note that this workaround no longer fully applies with recent kernels,
3142 * as I have noticed that when a CPU comes back online, some fields
3143 * restart from their previous value (e.g. user, nice, system)
3144 * whereas others restart from zero (idle, iowait)! To deal with this,
3145 * the get_per_cpu_interval() function will set these previous values
3146 * to zero if necessary.
3151 * Mark CPU as offline to not display it
3152 * (and thus it will not be confused with a tickless CPU).
3154 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3157 if ((tot_jiffies_p == 0) && !WANT_SINCE_BOOT(flags)) {
3159 * CPU has just come back online.
3160 * Unfortunately, no reference values are available
3161 * from a previous iteration, probably because it was
3162 * already offline when the first sample has been taken.
3163 * So don't display that CPU to prevent "jump-from-zero"
3164 * output syndrome, and don't take it into account for CPU "all".
3166 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3171 * Get interval for current CPU and add it to global CPU.
3172 * Note: Previous idle and iowait values (saved in scp) may be modified here.
3174 deltot_jiffies += get_per_cpu_interval(scc, scp);
3176 scc_all->cpu_user += scc->cpu_user;
3177 scp_all->cpu_user += scp->cpu_user;
3179 scc_all->cpu_nice += scc->cpu_nice;
3180 scp_all->cpu_nice += scp->cpu_nice;
3182 scc_all->cpu_sys += scc->cpu_sys;
3183 scp_all->cpu_sys += scp->cpu_sys;
3185 scc_all->cpu_idle += scc->cpu_idle;
3186 scp_all->cpu_idle += scp->cpu_idle;
3188 scc_all->cpu_iowait += scc->cpu_iowait;
3189 scp_all->cpu_iowait += scp->cpu_iowait;
3191 scc_all->cpu_hardirq += scc->cpu_hardirq;
3192 scp_all->cpu_hardirq += scp->cpu_hardirq;
3194 scc_all->cpu_steal += scc->cpu_steal;
3195 scp_all->cpu_steal += scp->cpu_steal;
3197 scc_all->cpu_softirq += scc->cpu_softirq;
3198 scp_all->cpu_softirq += scp->cpu_softirq;
3200 scc_all->cpu_guest += scc->cpu_guest;
3201 scp_all->cpu_guest += scp->cpu_guest;
3203 scc_all->cpu_guest_nice += scc->cpu_guest_nice;
3204 scp_all->cpu_guest_nice += scp->cpu_guest_nice;
3207 return deltot_jiffies;
3211 ***************************************************************************
3212 * Compute softnet statistics for CPU "all" as the sum of individual CPU
3214 * Also identify offline CPU.
3217 * @a Activity structure with statistics.
3218 * @prev Index in array where stats used as reference are.
3219 * @curr Index in array for current sample statistics.
3220 * @flags Flags for common options and system state.
3221 * @offline_cpu_bitmap
3222 * CPU bitmap for offline CPU.
3225 * @a Activity structure with updated statistics (those for global
3226 * CPU, and also those for offline CPU).
3227 * @offline_cpu_bitmap
3228 * CPU bitmap with offline CPU.
3229 ***************************************************************************
3231 void get_global_soft_statistics(struct activity *a, int prev, int curr,
3232 uint64_t flags, unsigned char offline_cpu_bitmap[])
3235 struct stats_softnet *ssnc, *ssnp;
3236 struct stats_softnet *ssnc_all = (struct stats_softnet *) ((char *) a->buf[curr]);
3237 struct stats_softnet *ssnp_all = (struct stats_softnet *) ((char *) a->buf[prev]);
3240 * Init structures that will contain values for CPU "all".
3241 * CPU "all" doesn't exist in /proc/net/softnet_stat file, so
3242 * we compute its values as the sum of the values of each CPU.
3244 memset(ssnc_all, 0, sizeof(struct stats_softnet));
3245 memset(ssnp_all, 0, sizeof(struct stats_softnet));
3247 for (i = 1; (i < a->nr_ini) && (i < a->bitmap->b_size + 1); i++) {
3250 * The size of a->buf[...] CPU structure may be different from the default
3251 * sizeof(struct stats_pwr_cpufreq) value if data have been read from a file!
3252 * That's why we don't use a syntax like:
3253 * ssnc = (struct stats_softnet *) a->buf[...] + i;
3255 ssnc = (struct stats_softnet *) ((char *) a->buf[curr] + i * a->msize);
3256 ssnp = (struct stats_softnet *) ((char *) a->buf[prev] + i * a->msize);
3258 if (ssnc->processed + ssnc->dropped + ssnc->time_squeeze +
3259 ssnc->received_rps + ssnc->flow_limit == 0) {
3260 /* Assume current CPU is offline */
3262 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3265 if ((ssnp->processed + ssnp->dropped + ssnp->time_squeeze +
3266 ssnp->received_rps + ssnp->flow_limit == 0) && !WANT_SINCE_BOOT(flags)) {
3267 /* Current CPU back online but no previous sample for it */
3268 offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
3272 ssnc_all->processed += ssnc->processed;
3273 ssnc_all->dropped += ssnc->dropped;
3274 ssnc_all->time_squeeze += ssnc->time_squeeze;
3275 ssnc_all->received_rps += ssnc->received_rps;
3276 ssnc_all->flow_limit += ssnc->flow_limit;
3278 ssnp_all->processed += ssnp->processed;
3279 ssnp_all->dropped += ssnp->dropped;
3280 ssnp_all->time_squeeze += ssnp->time_squeeze;
3281 ssnp_all->received_rps += ssnp->received_rps;
3282 ssnp_all->flow_limit += ssnp->flow_limit;
3287 ***************************************************************************
3288 * Get filesystem name to display. This may be either the persistent name
3289 * if requested by the user, the standard filesystem name (e.g. /dev/sda1,
3290 * /dev/sdb3, etc.) or the mount point. This is used when displaying
3291 * filesystem statistics: sar -F or sadf -- -F).
3294 * @a Activity structure.
3295 * @flags Flags for common options and system state.
3296 * @st_fs Statistics for current filesystem.
3299 * Filesystem name to display.
3300 ***************************************************************************
3302 char *get_fs_name_to_display(struct activity *a, uint64_t flags, struct stats_filesystem *st_fs)
3304 char *pname = NULL, *persist_dev_name;
3305 char fname[MAX_FS_LEN];
3307 if (DISPLAY_PERSIST_NAME_S(flags) && !DISPLAY_MOUNT(a->opt_flags)) {
3308 strncpy(fname, st_fs->fs_name, sizeof(fname));
3309 fname[sizeof(fname) - 1] = '\0';
3310 if ((persist_dev_name = get_persistent_name_from_pretty(basename(fname))) != NULL) {
3311 pname = persist_dev_name;
3315 pname = DISPLAY_MOUNT(a->opt_flags) ? st_fs->mountp : st_fs->fs_name;
3319 #endif /* SOURCE_SADC undefined */