2 * sar and sadf common routines.
3 * (C) 1999-2016 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 ***************************************************************************
27 #include <unistd.h> /* For STDOUT_FILENO, among others */
31 #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;
53 ***************************************************************************
54 * Init a bitmap (CPU, IRQ, etc.).
57 * @value Value used to init bitmap.
58 * @sz Size of the bitmap in bytes.
61 * @bitmap Bitmap initialized.
62 ***************************************************************************
64 void set_bitmap(unsigned char bitmap[], unsigned char value, unsigned int sz)
68 for (i = 0; i < sz; i++) {
74 ***************************************************************************
75 * Allocate structures.
78 * @act Array of activities.
79 ***************************************************************************
81 void allocate_structures(struct activity *act[])
85 for (i = 0; i < NR_ACT; i++) {
87 for (j = 0; j < 3; j++) {
88 SREALLOC(act[i]->buf[j], void,
89 (size_t) act[i]->msize * (size_t) act[i]->nr * (size_t) act[i]->nr2);
96 ***************************************************************************
100 * @act Array of activities.
101 ***************************************************************************
103 void free_structures(struct activity *act[])
107 for (i = 0; i < NR_ACT; i++) {
108 if (act[i]->nr > 0) {
109 for (j = 0; j < 3; j++) {
110 if (act[i]->buf[j]) {
111 free(act[i]->buf[j]);
112 act[i]->buf[j] = NULL;
120 ***************************************************************************
121 * Try to get device real name from sysfs tree.
124 * @major Major number of the device.
125 * @minor Minor number of the device.
128 * The name of the device, which may be the real name (as it appears in /dev)
130 ***************************************************************************
132 char *get_devname_from_sysfs(unsigned int major, unsigned int minor)
134 static char link[32], target[PATH_MAX];
138 snprintf(link, 32, "%s/%u:%u", SYSFS_DEV_BLOCK, major, minor);
140 /* Get full path to device knowing its major and minor numbers */
141 r = readlink(link, target, PATH_MAX);
142 if (r <= 0 || r >= PATH_MAX) {
148 /* Get device name */
149 devname = basename(target);
150 if (!devname || strnlen(devname, FILENAME_MAX) == 0) {
158 ***************************************************************************
159 * Get device real name if possible.
160 * Warning: This routine may return a bad name on 2.4 kernels where
161 * disk activities are read from /proc/stat.
164 * @major Major number of the device.
165 * @minor Minor number of the device.
166 * @pretty TRUE if the real name of the device (as it appears in /dev)
167 * should be returned.
170 * The name of the device, which may be the real name (as it appears in /dev)
171 * or a string with the following format devM-n.
172 ***************************************************************************
174 char *get_devname(unsigned int major, unsigned int minor, int pretty)
179 snprintf(buf, 32, "dev%u-%u", major, minor);
184 name = get_devname_from_sysfs(major, minor);
188 name = ioc_name(major, minor);
189 if ((name != NULL) && strcmp(name, K_NODEV))
196 ***************************************************************************
197 * Check if we are close enough to desired interval.
200 * @uptime_ref Uptime used as reference. This is the system uptime for the
201 * first sample statistics, or the first system uptime after a
203 * @uptime Current system uptime.
204 * @reset TRUE if @last_uptime should be reset with @uptime_ref.
205 * @interval Interval of time.
208 * 1 if we are actually close enough to desired interval, 0 otherwise.
209 ***************************************************************************
211 int next_slice(unsigned long long uptime_ref, unsigned long long uptime,
212 int reset, long interval)
214 unsigned long file_interval, entry;
215 static unsigned long long last_uptime = 0;
216 int min, max, pt1, pt2;
219 /* uptime is expressed in jiffies (basis of 1 processor) */
220 if (!last_uptime || reset) {
221 last_uptime = uptime_ref;
224 /* Interval cannot be greater than 0xffffffff here */
225 f = ((double) ((uptime - last_uptime) & 0xffffffff)) / HZ;
226 file_interval = (unsigned long) f;
227 if ((f * 10) - (file_interval * 10) >= 5) {
228 file_interval++; /* Rounding to correct value */
231 last_uptime = uptime;
234 * A few notes about the "algorithm" used here to display selected entries
235 * from the system activity file (option -f with -i flag):
236 * Let 'Iu' be the interval value given by the user on the command line,
237 * 'If' the interval between current and previous line in the system
239 * and 'En' the nth entry (identified by its time stamp) of the file.
240 * We choose In = [ En - If/2, En + If/2 [ if If is even,
241 * or In = [ En - If/2, En + If/2 ] if not.
242 * En will be displayed if
243 * (Pn * Iu) or (P'n * Iu) belongs to In
244 * with Pn = En / Iu and P'n = En / Iu + 1
246 f = ((double) ((uptime - uptime_ref) & 0xffffffff)) / HZ;
247 entry = (unsigned long) f;
248 if ((f * 10) - (entry * 10) >= 5) {
252 min = entry - (file_interval / 2);
253 max = entry + (file_interval / 2) + (file_interval & 0x1);
254 pt1 = (entry / interval) * interval;
255 pt2 = ((entry / interval) + 1) * interval;
257 return (((pt1 >= min) && (pt1 < max)) || ((pt2 >= min) && (pt2 < max)));
261 ***************************************************************************
262 * Use time stamp to fill tstamp structure.
265 * @timestamp Timestamp to decode (format: HH:MM:SS).
268 * @tse Structure containing the decoded timestamp.
271 * 0 if the timestamp has been successfully decoded, 1 otherwise.
272 ***************************************************************************
274 int decode_timestamp(char timestamp[], struct tstamp *tse)
276 timestamp[2] = timestamp[5] = '\0';
277 tse->tm_sec = atoi(×tamp[6]);
278 tse->tm_min = atoi(×tamp[3]);
279 tse->tm_hour = atoi(timestamp);
281 if ((tse->tm_sec < 0) || (tse->tm_sec > 59) ||
282 (tse->tm_min < 0) || (tse->tm_min > 59) ||
283 (tse->tm_hour < 0) || (tse->tm_hour > 23))
292 ***************************************************************************
293 * Compare two timestamps.
296 * @rectime Date and time for current sample.
297 * @tse Timestamp used as reference.
300 * A positive value if @rectime is greater than @tse,
301 * a negative one otherwise.
302 ***************************************************************************
304 int datecmp(struct tm *rectime, struct tstamp *tse)
306 if (rectime->tm_hour == tse->tm_hour) {
307 if (rectime->tm_min == tse->tm_min)
308 return (rectime->tm_sec - tse->tm_sec);
310 return (rectime->tm_min - tse->tm_min);
313 return (rectime->tm_hour - tse->tm_hour);
317 ***************************************************************************
318 * Parse a timestamp entered on the command line (hh:mm[:ss]) and decode it.
321 * @argv Arguments list.
322 * @opt Index in the arguments list.
323 * @def_timestamp Default timestamp to use.
326 * @tse Structure containing the decoded timestamp.
329 * 0 if the timestamp has been successfully decoded, 1 otherwise.
330 ***************************************************************************
332 int parse_timestamp(char *argv[], int *opt, struct tstamp *tse,
333 const char *def_timestamp)
337 if (argv[++(*opt)]) {
338 switch (strlen(argv[*opt])) {
341 strncpy(timestamp, argv[(*opt)++], 5);
342 strcat(timestamp,":00");
346 strncpy(timestamp, argv[(*opt)++], 8);
350 strncpy(timestamp, def_timestamp, 8);
354 strncpy(timestamp, def_timestamp, 8);
358 return decode_timestamp(timestamp, tse);
362 ***************************************************************************
363 * Look for the most recent of saDD and saYYYYMMDD to decide which one to
364 * use. If neither exists then use saDD by default.
367 * @sa_dir Directory where standard daily data files are saved.
368 * @rectime Structure containing the current date.
371 * @sa_name 0 to use saDD data files,
372 * 1 to use saYYYYMMDD data files.
373 ***************************************************************************
375 void guess_sa_name(char *sa_dir, struct tm *rectime, int *sa_name)
377 char filename[MAX_FILE_LEN];
381 /* Use saDD by default */
384 /* Look for saYYYYMMDD */
385 snprintf(filename, MAX_FILE_LEN,
386 "%s/sa%04d%02d%02d", sa_dir,
387 rectime->tm_year + 1900,
390 filename[MAX_FILE_LEN - 1] = '\0';
392 if (stat(filename, &sb) < 0)
393 /* Cannot find or access saYYYYMMDD, so use saDD */
395 sa_mtime = sb.st_mtime;
398 snprintf(filename, MAX_FILE_LEN,
401 filename[MAX_FILE_LEN - 1] = '\0';
403 if (stat(filename, &sb) < 0) {
404 /* Cannot find or access saDD, so use saYYYYMMDD */
409 if (sa_mtime > sb.st_mtime) {
410 /* saYYYYMMDD is more recent than saDD, so use it */
416 ***************************************************************************
417 * Set current daily data file name.
420 * @datafile If not an empty string then this is the alternate directory
421 * location where daily data files will be saved.
422 * @d_off Day offset (number of days to go back in the past).
423 * @sa_name 0 for saDD data files,
424 * 1 for saYYYYMMDD data files,
425 * -1 if unknown. In this case, will look for the most recent
426 * of saDD and saYYYYMMDD and use it.
429 * @datafile Name of daily data file.
430 ***************************************************************************
432 void set_default_file(char *datafile, int d_off, int sa_name)
434 char sa_dir[MAX_FILE_LEN];
435 struct tm rectime = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL};
437 /* Set directory where daily data files will be saved */
439 strncpy(sa_dir, datafile, MAX_FILE_LEN);
442 strncpy(sa_dir, SA_DIR, MAX_FILE_LEN);
444 sa_dir[MAX_FILE_LEN - 1] = '\0';
446 get_time(&rectime, d_off);
449 * Look for the most recent of saDD and saYYYYMMDD
450 * and use it. If neither exists then use saDD.
451 * sa_name is set accordingly.
453 guess_sa_name(sa_dir, &rectime, &sa_name);
456 /* Using saYYYYMMDD data files */
457 snprintf(datafile, MAX_FILE_LEN,
458 "%s/sa%04d%02d%02d", sa_dir,
459 rectime.tm_year + 1900,
464 /* Using saDD data files */
465 snprintf(datafile, MAX_FILE_LEN,
469 datafile[MAX_FILE_LEN - 1] = '\0';
470 default_file_used = TRUE;
474 ***************************************************************************
475 * Check data file type. If it is a directory then this is the alternate
476 * location where daily data files will be saved.
479 * @datafile Name of the daily data file. May be a directory.
480 * @d_off Day offset (number of days to go back in the past).
481 * @sa_name 0 for saDD data files,
482 * 1 for saYYYYMMDD data files,
483 * -1 if unknown. In this case, will look for the most recent
484 * of saDD and saYYYYMMDD and use it.
488 * @datafile Name of the daily data file. This is now a plain file, not
492 * 1 if @datafile was a directory, and 0 otherwise.
493 ***************************************************************************
495 int check_alt_sa_dir(char *datafile, int d_off, int sa_name)
499 if (stat(datafile, &sb) == 0) {
500 if (S_ISDIR(sb.st_mode)) {
502 * This is a directory: So append
503 * the default file name to it.
505 set_default_file(datafile, d_off, sa_name);
514 ***************************************************************************
515 * Set interval value.
518 * @record_hdr_curr Record with current sample statistics.
519 * @record_hdr_prev Record with previous sample statistics.
520 * @nr_proc Number of CPU, including CPU "all".
523 * @itv Interval in jiffies.
524 * @g_itv Interval in jiffies multiplied by the # of proc.
525 ***************************************************************************
527 void get_itv_value(struct record_header *record_hdr_curr,
528 struct record_header *record_hdr_prev,
529 unsigned int nr_proc,
530 unsigned long long *itv, unsigned long long *g_itv)
532 /* Interval value in jiffies */
533 *g_itv = get_interval(record_hdr_prev->uptime,
534 record_hdr_curr->uptime);
537 *itv = get_interval(record_hdr_prev->uptime0,
538 record_hdr_curr->uptime0);
546 ***************************************************************************
547 * Fill the rectime structure with the file's creation date, based on file's
548 * time data saved in file header.
549 * The resulting timestamp is expressed in the locale of the file creator or
550 * in the user's own locale, depending on whether option -t has been used
554 * @flags Flags for common options and system state.
555 * @file_hdr System activity file standard header.
558 * @rectime Date (and possibly time) from file header. Only the date,
559 * not the time, should be used by the caller.
560 ***************************************************************************
562 void get_file_timestamp_struct(unsigned int flags, struct tm *rectime,
563 struct file_header *file_hdr)
567 if (PRINT_TRUE_TIME(flags)) {
568 /* Get local time. This is just to fill fields with a default value. */
569 get_time(rectime, 0);
571 rectime->tm_mday = file_hdr->sa_day;
572 rectime->tm_mon = file_hdr->sa_month;
573 rectime->tm_year = file_hdr->sa_year;
575 * Call mktime() to set DST (Daylight Saving Time) flag.
576 * Has anyone a better way to do it?
578 rectime->tm_hour = rectime->tm_min = rectime->tm_sec = 0;
582 if ((loc_t = localtime((const time_t *) &file_hdr->sa_ust_time)) != NULL) {
589 ***************************************************************************
590 * Print report header.
593 * @flags Flags for common options and system state.
594 * @file_hdr System activity file standard header.
595 * @cpu_nr Number of CPU (value in [1, NR_CPUS + 1]).
596 * 1 means that there is only one proc and non SMP kernel.
597 * 2 means one proc and SMP kernel.
601 * @rectime Date and time from file header.
602 ***************************************************************************
604 void print_report_hdr(unsigned int flags, struct tm *rectime,
605 struct file_header *file_hdr, int cpu_nr)
608 /* Get date of file creation */
609 get_file_timestamp_struct(flags, rectime, file_hdr);
611 /* Display the header */
612 print_gal_header(rectime, file_hdr->sa_sysname, file_hdr->sa_release,
613 file_hdr->sa_nodename, file_hdr->sa_machine,
614 cpu_nr > 1 ? cpu_nr - 1 : 1,
619 ***************************************************************************
620 * Network interfaces may now be registered (and unregistered) dynamically.
621 * This is what we try to guess here.
624 * @a Activity structure with statistics.
625 * @curr Index in array for current sample statistics.
626 * @ref Index in array for sample statistics used as reference.
627 * @pos Index on current network interface.
630 * Position of current network interface in array of sample statistics used
632 ***************************************************************************
634 unsigned int check_net_dev_reg(struct activity *a, int curr, int ref,
637 struct stats_net_dev *sndc, *sndp;
638 unsigned int index = 0;
640 sndc = (struct stats_net_dev *) ((char *) a->buf[curr] + pos * a->msize);
642 while (index < a->nr) {
643 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
644 if (!strcmp(sndc->interface, sndp->interface)) {
646 * Network interface found.
647 * If a counter has decreased, then we may assume that the
648 * corresponding interface was unregistered, then registered again.
650 if ((sndc->rx_packets < sndp->rx_packets) ||
651 (sndc->tx_packets < sndp->tx_packets) ||
652 (sndc->rx_bytes < sndp->rx_bytes) ||
653 (sndc->tx_bytes < sndp->tx_bytes) ||
654 (sndc->rx_compressed < sndp->rx_compressed) ||
655 (sndc->tx_compressed < sndp->tx_compressed) ||
656 (sndc->multicast < sndp->multicast)) {
659 * Special processing for rx_bytes (_packets) and
660 * tx_bytes (_packets) counters: If the number of
661 * bytes (packets) has decreased, whereas the number of
662 * packets (bytes) has increased, then assume that the
663 * relevant counter has met an overflow condition, and that
664 * the interface was not unregistered, which is all the
665 * more plausible that the previous value for the counter
667 * NB: the average value displayed will be wrong in this case...
669 * If such an overflow is detected, just set the flag. There is no
670 * need to handle this in a special way: the difference is still
671 * properly calculated if the result is of the same type (i.e.
672 * unsigned long) as the two values.
676 if ((sndc->rx_bytes < sndp->rx_bytes) &&
677 (sndc->rx_packets > sndp->rx_packets) &&
678 (sndp->rx_bytes > (~0UL >> 1))) {
681 if ((sndc->tx_bytes < sndp->tx_bytes) &&
682 (sndc->tx_packets > sndp->tx_packets) &&
683 (sndp->tx_bytes > (~0UL >> 1))) {
686 if ((sndc->rx_packets < sndp->rx_packets) &&
687 (sndc->rx_bytes > sndp->rx_bytes) &&
688 (sndp->rx_packets > (~0UL >> 1))) {
691 if ((sndc->tx_packets < sndp->tx_packets) &&
692 (sndc->tx_bytes > sndp->tx_bytes) &&
693 (sndp->tx_packets > (~0UL >> 1))) {
699 * OK: assume here that the device was
700 * actually unregistered.
702 memset(sndp, 0, STATS_NET_DEV_SIZE);
703 strncpy(sndp->interface, sndc->interface, MAX_IFACE_LEN - 1);
711 /* Network interface not found: Look for the first free structure */
712 for (index = 0; index < a->nr; index++) {
713 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
714 if (!strcmp(sndp->interface, ""))
717 if (index >= a->nr) {
718 /* No free structure: Default is structure of same rank */
722 sndp = (struct stats_net_dev *) ((char *) a->buf[ref] + index * a->msize);
723 /* Since the name is not the same, reset all the structure */
724 memset(sndp, 0, STATS_NET_DEV_SIZE);
725 strncpy(sndp->interface, sndc->interface, MAX_IFACE_LEN - 1);
731 ***************************************************************************
732 * Network interfaces may now be registered (and unregistered) dynamically.
733 * This is what we try to guess here.
736 * @a Activity structure with statistics.
737 * @curr Index in array for current sample statistics.
738 * @ref Index in array for sample statistics used as reference.
739 * @pos Index on current network interface.
742 * Position of current network interface in array of sample statistics used
744 ***************************************************************************
746 unsigned int check_net_edev_reg(struct activity *a, int curr, int ref,
749 struct stats_net_edev *snedc, *snedp;
750 unsigned int index = 0;
752 snedc = (struct stats_net_edev *) ((char *) a->buf[curr] + pos * a->msize);
754 while (index < a->nr) {
755 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
756 if (!strcmp(snedc->interface, snedp->interface)) {
758 * Network interface found.
759 * If a counter has decreased, then we may assume that the
760 * corresponding interface was unregistered, then registered again.
762 if ((snedc->tx_errors < snedp->tx_errors) ||
763 (snedc->collisions < snedp->collisions) ||
764 (snedc->rx_dropped < snedp->rx_dropped) ||
765 (snedc->tx_dropped < snedp->tx_dropped) ||
766 (snedc->tx_carrier_errors < snedp->tx_carrier_errors) ||
767 (snedc->rx_frame_errors < snedp->rx_frame_errors) ||
768 (snedc->rx_fifo_errors < snedp->rx_fifo_errors) ||
769 (snedc->tx_fifo_errors < snedp->tx_fifo_errors)) {
772 * OK: assume here that the device was
773 * actually unregistered.
775 memset(snedp, 0, STATS_NET_EDEV_SIZE);
776 strncpy(snedp->interface, snedc->interface, MAX_IFACE_LEN - 1);
783 /* Network interface not found: Look for the first free structure */
784 for (index = 0; index < a->nr; index++) {
785 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
786 if (!strcmp(snedp->interface, ""))
789 if (index >= a->nr) {
790 /* No free structure: Default is structure of same rank */
794 snedp = (struct stats_net_edev *) ((char *) a->buf[ref] + index * a->msize);
795 /* Since the name is not the same, reset all the structure */
796 memset(snedp, 0, STATS_NET_EDEV_SIZE);
797 strncpy(snedp->interface, snedc->interface, MAX_IFACE_LEN - 1);
803 ***************************************************************************
804 * Disks may be registered dynamically (true in /proc/stat file).
805 * This is what we try to guess here.
808 * @a Activity structure with statistics.
809 * @curr Index in array for current sample statistics.
810 * @ref Index in array for sample statistics used as reference.
811 * @pos Index on current disk.
814 * Position of current disk in array of sample statistics used as reference.
815 ***************************************************************************
817 int check_disk_reg(struct activity *a, int curr, int ref, int pos)
819 struct stats_disk *sdc, *sdp;
822 sdc = (struct stats_disk *) ((char *) a->buf[curr] + pos * a->msize);
824 while (index < a->nr) {
825 sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
826 if ((sdc->major == sdp->major) &&
827 (sdc->minor == sdp->minor)) {
830 * If all the counters have decreased then the likelyhood
831 * is that the disk has been unregistered and a new disk inserted.
832 * If only one or two have decreased then the likelyhood
833 * is that the counter has simply wrapped.
835 if ((sdc->nr_ios < sdp->nr_ios) &&
836 (sdc->rd_sect < sdp->rd_sect) &&
837 (sdc->wr_sect < sdp->wr_sect)) {
839 memset(sdp, 0, STATS_DISK_SIZE);
840 sdp->major = sdc->major;
841 sdp->minor = sdc->minor;
848 /* Disk not found: Look for the first free structure */
849 for (index = 0; index < a->nr; index++) {
850 sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
851 if (!(sdp->major + sdp->minor))
854 if (index >= a->nr) {
855 /* No free structure found: Default is structure of same rank */
859 sdp = (struct stats_disk *) ((char *) a->buf[ref] + index * a->msize);
860 /* Since the device is not the same, reset all the structure */
861 memset(sdp, 0, STATS_DISK_SIZE);
862 sdp->major = sdc->major;
863 sdp->minor = sdc->minor;
869 ***************************************************************************
870 * Allocate bitmaps for activities that have one.
873 * @act Array of activities.
874 ***************************************************************************
876 void allocate_bitmaps(struct activity *act[])
880 for (i = 0; i < NR_ACT; i++) {
882 * If current activity has a bitmap which has not already
883 * been allocated, then allocate it.
884 * Note that a same bitmap may be used by several activities.
886 if (act[i]->bitmap && !act[i]->bitmap->b_array) {
887 SREALLOC(act[i]->bitmap->b_array, unsigned char,
888 BITMAP_SIZE(act[i]->bitmap->b_size));
894 ***************************************************************************
895 * Free bitmaps for activities that have one.
898 * @act Array of activities.
899 ***************************************************************************
901 void free_bitmaps(struct activity *act[])
905 for (i = 0; i < NR_ACT; i++) {
906 if (act[i]->bitmap && act[i]->bitmap->b_array) {
907 free(act[i]->bitmap->b_array);
908 /* Set pointer to NULL to prevent it from being freed again */
909 act[i]->bitmap->b_array = NULL;
915 ***************************************************************************
916 * Look for activity in array.
919 * @act Array of activities.
920 * @act_flag Activity flag to look for.
921 * @stop TRUE if sysstat should exit when activity is not found.
924 * Position of activity in array, or -1 if not found (this may happen when
925 * reading data from a system activity file created by another version of
927 ***************************************************************************
929 int get_activity_position(struct activity *act[], unsigned int act_flag, int stop)
933 for (i = 0; i < NR_ACT; i++) {
934 if (act[i]->id == act_flag)
939 PANIC((int) act_flag);
946 ***************************************************************************
947 * Count number of activities with given option.
950 * @act Array of activities.
951 * @option Option that activities should have to be counted
952 * (eg. AO_COLLECTED...)
953 * @count_outputs TRUE if each output should be counted for activities with
957 * Number of selected activities
958 ***************************************************************************
960 int get_activity_nr(struct activity *act[], unsigned int option, int count_outputs)
965 for (i = 0; i < NR_ACT; i++) {
966 if ((act[i]->options & option) == option) {
968 if (HAS_MULTIPLE_OUTPUTS(act[i]->options) && count_outputs) {
969 for (msk = 1; msk < 0x100; msk <<= 1) {
970 if ((act[i]->opt_flags & 0xff) & msk) {
985 ***************************************************************************
986 * Select all activities, even if they have no associated items.
989 * @act Array of activities.
992 * @act Array of activities, all of the being selected.
993 ***************************************************************************
995 void select_all_activities(struct activity *act[])
999 for (i = 0; i < NR_ACT; i++) {
1000 act[i]->options |= AO_SELECTED;
1005 ***************************************************************************
1006 * Select CPU activity if no other activities have been explicitly selected.
1007 * Also select CPU "all" if no other CPU has been selected.
1010 * @act Array of activities.
1013 * @act Array of activities with CPU activity selected if needed.
1014 ***************************************************************************
1016 void select_default_activity(struct activity *act[])
1020 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1022 /* Default is CPU activity... */
1023 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1025 * Still OK even when reading stats from a file
1026 * since A_CPU activity is always recorded.
1028 act[p]->options |= AO_SELECTED;
1032 * If no CPU's have been selected then select CPU "all".
1033 * cpu_bitmap bitmap may be used by several activities (A_CPU, A_PWR_CPUFREQ...)
1035 if (!count_bits(cpu_bitmap.b_array, BITMAP_SIZE(cpu_bitmap.b_size))) {
1036 cpu_bitmap.b_array[0] |= 0x01;
1041 ***************************************************************************
1042 * Read data from a system activity data file.
1045 * @ifd Input file descriptor.
1046 * @buffer Buffer where data are read.
1047 * @size Number of bytes to read.
1048 * @mode If set to HARD_SIZE, indicate that an EOF should be considered
1052 * 1 if EOF has been reached, 0 otherwise.
1053 ***************************************************************************
1055 int sa_fread(int ifd, void *buffer, int size, int mode)
1059 if ((n = read(ifd, buffer, size)) < 0) {
1060 fprintf(stderr, _("Error while reading system activity file: %s\n"),
1066 if (!n && (mode == SOFT_SIZE))
1070 fprintf(stderr, _("End of system activity file unexpected\n"));
1079 ***************************************************************************
1080 * Display sysstat version used to create system activity data file.
1083 * @st Output stream (stderr or stdout).
1084 * @file_magic File magic header.
1085 ***************************************************************************
1087 void display_sa_file_version(FILE *st, struct file_magic *file_magic)
1089 fprintf(st, _("File created by sar/sadc from sysstat version %d.%d.%d"),
1090 file_magic->sysstat_version,
1091 file_magic->sysstat_patchlevel,
1092 file_magic->sysstat_sublevel);
1094 if (file_magic->sysstat_extraversion) {
1095 fprintf(st, ".%d", file_magic->sysstat_extraversion);
1101 ***************************************************************************
1102 * An invalid system activity file has been opened for reading.
1103 * If this file was created by an old version of sysstat, tell it to the
1107 * @fd Descriptor of the file that has been opened.
1108 * @file_magic file_magic structure filled with file magic header data.
1109 * May contain invalid data.
1110 * @file Name of the file being read.
1111 * @n Number of bytes read while reading file magic header.
1112 * This function may also be called after failing to read file
1113 * standard header, or if CPU activity has not been found in
1114 * file. In this case, n is set to 0.
1115 ***************************************************************************
1117 void handle_invalid_sa_file(int *fd, struct file_magic *file_magic, char *file,
1122 fprintf(stderr, _("Invalid system activity file: %s\n"), file);
1124 if (n == FILE_MAGIC_SIZE) {
1125 sm = (file_magic->sysstat_magic << 8) | (file_magic->sysstat_magic >> 8);
1126 if ((file_magic->sysstat_magic == SYSSTAT_MAGIC) || (sm == SYSSTAT_MAGIC)) {
1128 * This is a sysstat file, but this file has an old format
1129 * or its internal endian format doesn't match.
1131 display_sa_file_version(stderr, file_magic);
1133 if (sm == SYSSTAT_MAGIC) {
1134 fprintf(stderr, _("Endian format mismatch\n"));
1138 _("Current sysstat version cannot read the format of this file (%#x)\n"),
1139 file_magic->format_magic);
1149 ***************************************************************************
1150 * Move structures data.
1153 * @act Array of activities.
1154 * @id_seq Activity sequence in file.
1155 * @record_hdr Current record header.
1156 * @dest Index in array where stats have to be copied to.
1157 * @src Index in array where stats to copy are.
1158 ***************************************************************************
1160 void copy_structures(struct activity *act[], unsigned int id_seq[],
1161 struct record_header record_hdr[], int dest, int src)
1165 memcpy(&record_hdr[dest], &record_hdr[src], RECORD_HEADER_SIZE);
1167 for (i = 0; i < NR_ACT; i++) {
1172 p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND);
1173 if ((act[p]->nr < 1) || (act[p]->nr2 < 1)) {
1177 memcpy(act[p]->buf[dest], act[p]->buf[src],
1178 (size_t) act[p]->msize * (size_t) act[p]->nr * (size_t) act[p]->nr2);
1183 ***************************************************************************
1184 * Read varying part of the statistics from a daily data file.
1187 * @act Array of activities.
1188 * @curr Index in array for current sample statistics.
1189 * @ifd Input file descriptor.
1190 * @act_nr Number of activities in file.
1191 * @file_actlst Activity list in file.
1192 ***************************************************************************
1194 void read_file_stat_bunch(struct activity *act[], int curr, int ifd, int act_nr,
1195 struct file_activity *file_actlst)
1198 struct file_activity *fal = file_actlst;
1201 for (i = 0; i < act_nr; i++, fal++) {
1203 if (((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0) ||
1204 (act[p]->magic != fal->magic)) {
1206 * Ignore current activity in file, which is unknown to
1207 * current sysstat version or has an unknown format.
1209 offset = (off_t) fal->size * (off_t) fal->nr * (off_t) fal->nr2;
1210 if (lseek(ifd, offset, SEEK_CUR) < offset) {
1216 else if ((act[p]->nr > 0) &&
1217 ((act[p]->nr > 1) || (act[p]->nr2 > 1)) &&
1218 (act[p]->msize > act[p]->fsize)) {
1219 for (j = 0; j < act[p]->nr; j++) {
1220 for (k = 0; k < act[p]->nr2; k++) {
1222 (char *) act[p]->buf[curr] + (j * act[p]->nr2 + k) * act[p]->msize,
1223 act[p]->fsize, HARD_SIZE);
1227 else if (act[p]->nr > 0) {
1228 sa_fread(ifd, act[p]->buf[curr], act[p]->fsize * act[p]->nr * act[p]->nr2, HARD_SIZE);
1237 ***************************************************************************
1238 * Open a sysstat activity data file and read its magic structure.
1241 * @dfile Name of system activity data file.
1242 * @ignore Set to 1 if a true sysstat activity file but with a bad
1243 * format should not yield an error message. Useful with
1244 * sadf -H and sadf -c.
1247 * @fd System activity data file descriptor.
1248 * @file_magic file_magic structure containing data read from file magic
1252 * -1 if data file is a sysstat file with an old format, 0 otherwise.
1253 ***************************************************************************
1255 int sa_open_read_magic(int *fd, char *dfile, struct file_magic *file_magic,
1260 /* Open sa data file */
1261 if ((*fd = open(dfile, O_RDONLY)) < 0) {
1262 int saved_errno = errno;
1264 fprintf(stderr, _("Cannot open %s: %s\n"), dfile, strerror(errno));
1266 if ((saved_errno == ENOENT) && default_file_used) {
1267 fprintf(stderr, _("Please check if data collecting is enabled\n"));
1272 /* Read file magic data */
1273 n = read(*fd, file_magic, FILE_MAGIC_SIZE);
1275 if ((n != FILE_MAGIC_SIZE) ||
1276 (file_magic->sysstat_magic != SYSSTAT_MAGIC) ||
1277 ((file_magic->format_magic != FORMAT_MAGIC) && !ignore)) {
1278 /* Display error message and exit */
1279 handle_invalid_sa_file(fd, file_magic, dfile, n);
1281 if ((file_magic->sysstat_version > 10) ||
1282 ((file_magic->sysstat_version == 10) && (file_magic->sysstat_patchlevel >= 3))) {
1283 /* header_size field exists only for sysstat versions 10.3.1 and later */
1284 if ((file_magic->header_size <= MIN_FILE_HEADER_SIZE) ||
1285 (file_magic->header_size > MAX_FILE_HEADER_SIZE) ||
1286 ((file_magic->header_size < FILE_HEADER_SIZE) && !ignore)) {
1287 /* Display error message and exit */
1288 handle_invalid_sa_file(fd, file_magic, dfile, n);
1291 if (file_magic->format_magic != FORMAT_MAGIC)
1292 /* This is an old sa datafile format */
1299 ***************************************************************************
1300 * Open a data file, and perform various checks before reading.
1303 * @dfile Name of system activity data file.
1304 * @act Array of activities.
1305 * @ignore Set to 1 if a true sysstat activity file but with a bad
1306 * format should not yield an error message. Useful with
1307 * sadf -H and sadf -c.
1310 * @ifd System activity data file descriptor.
1311 * @file_magic file_magic structure containing data read from file magic
1313 * @file_hdr file_hdr structure containing data read from file standard
1315 * @file_actlst Acvtivity list in file.
1316 * @id_seq Activity sequence.
1317 ***************************************************************************
1319 void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
1320 struct file_magic *file_magic, struct file_header *file_hdr,
1321 struct file_activity **file_actlst, unsigned int id_seq[],
1325 unsigned int a_cpu = FALSE;
1326 struct file_activity *fal;
1327 void *buffer = NULL;
1329 /* Open sa data file and read its magic structure */
1330 if (sa_open_read_magic(ifd, dfile, file_magic, ignore) < 0)
1333 SREALLOC(buffer, char, file_magic->header_size);
1335 /* Read sa data file standard header and allocate activity list */
1336 sa_fread(*ifd, buffer, file_magic->header_size, HARD_SIZE);
1338 * Data file header size may be greater than FILE_HEADER_SIZE, but
1339 * anyway only the first FILE_HEADER_SIZE bytes can be interpreted.
1341 memcpy(file_hdr, buffer, FILE_HEADER_SIZE);
1346 * Compare against MAX_NR_ACT and not NR_ACT because
1347 * we are maybe reading a datafile from a future sysstat version
1348 * with more activities than known today.
1350 if (file_hdr->sa_act_nr > MAX_NR_ACT) {
1351 /* Maybe a "false positive" sysstat datafile? */
1352 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1355 SREALLOC(*file_actlst, struct file_activity, FILE_ACTIVITY_SIZE * file_hdr->sa_act_nr);
1358 /* Read activity list */
1360 for (i = 0; i < file_hdr->sa_act_nr; i++, fal++) {
1362 sa_fread(*ifd, fal, FILE_ACTIVITY_SIZE, HARD_SIZE);
1365 * Every activity, known or unknown, should have
1366 * at least one item and sub-item.
1367 * Also check that the number of items and sub-items
1368 * doesn't exceed a max value. This is necessary
1369 * because we will use @nr and @nr2 to
1370 * allocate memory to read the file contents. So we
1371 * must make sure the file is not corrupted.
1372 * NB: Another check will be made below for known
1373 * activities which have each a specific max value.
1375 if ((fal->nr < 1) || (fal->nr2 < 1) ||
1376 (fal->nr > NR_MAX) || (fal->nr2 > NR2_MAX)) {
1377 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1380 if ((p = get_activity_position(act, fal->id, RESUME_IF_NOT_FOUND)) < 0)
1381 /* Unknown activity */
1384 if (act[p]->magic != fal->magic) {
1385 /* Bad magical number */
1388 * This is how sadf -H knows that this
1389 * activity has an unknown format.
1391 act[p]->magic = ACTIVITY_MAGIC_UNKNOWN;
1397 /* Check max value for known activities */
1398 if (fal->nr > act[p]->nr_max) {
1399 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1402 if (fal->id == A_CPU) {
1406 if (fal->size > act[p]->msize) {
1407 act[p]->msize = fal->size;
1411 * If current activity is a volatile one then fal->nr is the
1412 * number of items (CPU at the present time as only CPU related
1413 * activities are volatile today) for the statistics located
1414 * between the start of the data file and the first restart mark.
1415 * Volatile activities have a number of items which can vary
1416 * in file. In this case, a RESTART record is followed by the
1417 * volatile activity structures.
1419 act[p]->nr = fal->nr;
1420 act[p]->nr2 = fal->nr2;
1421 act[p]->fsize = fal->size;
1423 * This is a known activity with a known format
1424 * (magical number). Only such activities will be displayed.
1425 * (Well, this may also be an unknown format if we have entered sadf -H.)
1427 id_seq[j++] = fal->id;
1432 * CPU activity should always be in file
1433 * and have a known format (expected magical number).
1435 handle_invalid_sa_file(ifd, file_magic, dfile, 0);
1438 while (j < NR_ACT) {
1442 /* Check that at least one selected activity is available in file */
1443 for (i = 0; i < NR_ACT; i++) {
1445 if (!IS_SELECTED(act[i]->options))
1448 /* Here is a selected activity: Does it exist in file? */
1450 for (j = 0; j < file_hdr->sa_act_nr; j++, fal++) {
1451 if (act[i]->id == fal->id)
1454 if (j == file_hdr->sa_act_nr) {
1455 /* No: Unselect it */
1456 act[i]->options &= ~AO_SELECTED;
1459 if (!get_activity_nr(act, AO_SELECTED, COUNT_ACTIVITIES)) {
1460 fprintf(stderr, _("Requested activities not available in file %s\n"),
1468 ***************************************************************************
1469 * Set number of items for current volatile activity and reallocate its
1470 * structures accordingly.
1471 * NB: As only activities related to CPU can be volatile, the number of
1472 * items corresponds in fact to the number of CPU.
1475 * @act Array of activities.
1476 * @act_nr Number of items for current volatile activity.
1477 * @act_id Activity identification for current volatile activity.
1480 * -1 if unknown activity and 0 otherwise.
1481 ***************************************************************************
1483 int reallocate_vol_act_structures(struct activity *act[], unsigned int act_nr,
1484 unsigned int act_id)
1488 if ((p = get_activity_position(act, act_id, RESUME_IF_NOT_FOUND)) < 0)
1489 /* Ignore unknown activity */
1492 act[p]->nr = act_nr;
1494 for (j = 0; j < 3; j++) {
1495 SREALLOC(act[p]->buf[j], void,
1496 (size_t) act[p]->msize * (size_t) act[p]->nr * (size_t) act[p]->nr2);
1503 ***************************************************************************
1504 * Read the volatile activities structures following a RESTART record.
1505 * Then set number of items for each corresponding activity and reallocate
1509 * @ifd Input file descriptor.
1510 * @act Array of activities.
1511 * @file Name of file being read.
1512 * @file_magic file_magic structure filled with file magic header data.
1513 * @vol_act_nr Number of volatile activities structures to read.
1516 * New number of items.
1518 * NB: As only activities related to CPU can be volatile, the new number of
1519 * items corresponds in fact to the new number of CPU.
1520 ***************************************************************************
1522 __nr_t read_vol_act_structures(int ifd, struct activity *act[], char *file,
1523 struct file_magic *file_magic,
1524 unsigned int vol_act_nr)
1526 struct file_activity file_act;
1530 for (i = 0; i < vol_act_nr; i++) {
1532 sa_fread(ifd, &file_act, FILE_ACTIVITY_SIZE, HARD_SIZE);
1535 rc = reallocate_vol_act_structures(act, file_act.nr, file_act.id);
1536 if ((rc == 0) && !item_nr) {
1537 item_nr = file_act.nr;
1540 /* else ignore empty structures that may exist */
1544 /* All volatile activities structures cannot be empty */
1545 handle_invalid_sa_file(&ifd, file_magic, file, 0);
1552 ***************************************************************************
1553 * Parse sar activities options (also used by sadf).
1556 * @argv Arguments list.
1557 * @opt Index in list of arguments.
1558 * @caller Indicate whether it's sar or sadf that called this function.
1561 * @act Array of selected activities.
1562 * @flags Common flags and system state.
1566 ***************************************************************************
1568 int parse_sar_opt(char *argv[], int *opt, struct activity *act[],
1569 unsigned int *flags, int caller)
1573 for (i = 1; *(argv[*opt] + i); i++) {
1575 * Note: argv[*opt] contains something like "-BruW"
1576 * *(argv[*opt] + i) will contain 'B', 'r', etc.
1579 switch (*(argv[*opt] + i)) {
1582 select_all_activities(act);
1585 * Force '-P ALL -I XALL -r ALL -u ALL -F'.
1586 * Setting -F is compulsory because corresponding activity
1587 * has AO_MULTIPLE_OUTPUTS flag set.
1589 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1590 act[p]->opt_flags |= AO_F_MEM_AMT + AO_F_MEM_DIA +
1591 AO_F_MEM_SWAP + AO_F_MEM_ALL;
1593 p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
1594 set_bitmap(act[p]->bitmap->b_array, ~0,
1595 BITMAP_SIZE(act[p]->bitmap->b_size));
1597 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1598 set_bitmap(act[p]->bitmap->b_array, ~0,
1599 BITMAP_SIZE(act[p]->bitmap->b_size));
1600 act[p]->opt_flags = AO_F_CPU_ALL;
1602 p = get_activity_position(act, A_FILESYSTEM, EXIT_IF_NOT_FOUND);
1603 act[p]->opt_flags = AO_F_FILESYSTEM;
1607 SELECT_ACTIVITY(A_PAGE);
1611 SELECT_ACTIVITY(A_IO);
1615 *flags |= S_F_COMMENT;
1619 SELECT_ACTIVITY(A_DISK);
1623 p = get_activity_position(act, A_FILESYSTEM, EXIT_IF_NOT_FOUND);
1624 act[p]->options |= AO_SELECTED;
1625 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_MOUNT)) {
1627 act[p]->opt_flags |= AO_F_MOUNT;
1631 act[p]->opt_flags |= AO_F_FILESYSTEM;
1636 p = get_activity_position(act, A_HUGE, EXIT_IF_NOT_FOUND);
1637 act[p]->options |= AO_SELECTED;
1641 if (argv[*opt + 1]) {
1643 if (strnlen(argv[*opt], MAX_FILE_LEN) >= MAX_FILE_LEN - 1)
1646 strncpy(persistent_name_type, argv[*opt], MAX_FILE_LEN - 1);
1647 persistent_name_type[MAX_FILE_LEN - 1] = '\0';
1648 strtolower(persistent_name_type);
1649 if (!get_persistent_type_dir(persistent_name_type)) {
1650 fprintf(stderr, _("Invalid type of persistent device name\n"));
1654 * If persistent device name doesn't exist for device, use
1657 *flags |= S_F_PERSIST_NAME + S_F_DEV_PRETTY;
1666 *flags |= S_F_DEV_PRETTY;
1670 SELECT_ACTIVITY(A_QUEUE);
1674 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1675 act[p]->options |= AO_SELECTED;
1676 act[p]->opt_flags |= AO_F_MEM_AMT;
1677 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
1679 act[p]->opt_flags |= AO_F_MEM_ALL;
1685 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1686 act[p]->options |= AO_SELECTED;
1687 act[p]->opt_flags |= AO_F_MEM_DIA;
1691 p = get_activity_position(act, A_MEMORY, EXIT_IF_NOT_FOUND);
1692 act[p]->options |= AO_SELECTED;
1693 act[p]->opt_flags |= AO_F_MEM_SWAP;
1698 * Check sar option -t here (as it can be combined
1699 * with other ones, eg. "sar -rtu ..."
1700 * But sadf option -t is checked in sadf.c as it won't
1701 * be entered as a sar option after "--".
1703 if (caller == C_SAR) {
1704 *flags |= S_F_TRUE_TIME;
1711 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1712 act[p]->options |= AO_SELECTED;
1713 if (!*(argv[*opt] + i + 1) && argv[*opt + 1] && !strcmp(argv[*opt + 1], K_ALL)) {
1715 act[p]->opt_flags = AO_F_CPU_ALL;
1719 act[p]->opt_flags = AO_F_CPU_DEF;
1724 SELECT_ACTIVITY(A_KTABLES);
1728 SELECT_ACTIVITY(A_PCSW);
1732 SELECT_ACTIVITY(A_SWAP);
1736 SELECT_ACTIVITY(A_SERIAL);
1751 ***************************************************************************
1752 * Parse sar "-m" option.
1755 * @argv Arguments list.
1756 * @opt Index in list of arguments.
1759 * @act Array of selected activities.
1762 * 0 on success, 1 otherwise.
1763 ***************************************************************************
1765 int parse_sar_m_opt(char *argv[], int *opt, struct activity *act[])
1769 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1770 if (!strcmp(t, K_CPU)) {
1771 SELECT_ACTIVITY(A_PWR_CPUFREQ);
1773 else if (!strcmp(t, K_FAN)) {
1774 SELECT_ACTIVITY(A_PWR_FAN);
1776 else if (!strcmp(t, K_IN)) {
1777 SELECT_ACTIVITY(A_PWR_IN);
1779 else if (!strcmp(t, K_TEMP)) {
1780 SELECT_ACTIVITY(A_PWR_TEMP);
1782 else if (!strcmp(t, K_FREQ)) {
1783 SELECT_ACTIVITY(A_PWR_WGHFREQ);
1785 else if (!strcmp(t, K_USB)) {
1786 SELECT_ACTIVITY(A_PWR_USB);
1788 else if (!strcmp(t, K_ALL)) {
1789 SELECT_ACTIVITY(A_PWR_CPUFREQ);
1790 SELECT_ACTIVITY(A_PWR_FAN);
1791 SELECT_ACTIVITY(A_PWR_IN);
1792 SELECT_ACTIVITY(A_PWR_TEMP);
1793 SELECT_ACTIVITY(A_PWR_WGHFREQ);
1794 SELECT_ACTIVITY(A_PWR_USB);
1805 ***************************************************************************
1806 * Parse sar "-n" option.
1809 * @argv Arguments list.
1810 * @opt Index in list of arguments.
1813 * @act Array of selected activities.
1816 * 0 on success, 1 otherwise.
1817 ***************************************************************************
1819 int parse_sar_n_opt(char *argv[], int *opt, struct activity *act[])
1823 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1824 if (!strcmp(t, K_DEV)) {
1825 SELECT_ACTIVITY(A_NET_DEV);
1827 else if (!strcmp(t, K_EDEV)) {
1828 SELECT_ACTIVITY(A_NET_EDEV);
1830 else if (!strcmp(t, K_SOCK)) {
1831 SELECT_ACTIVITY(A_NET_SOCK);
1833 else if (!strcmp(t, K_NFS)) {
1834 SELECT_ACTIVITY(A_NET_NFS);
1836 else if (!strcmp(t, K_NFSD)) {
1837 SELECT_ACTIVITY(A_NET_NFSD);
1839 else if (!strcmp(t, K_IP)) {
1840 SELECT_ACTIVITY(A_NET_IP);
1842 else if (!strcmp(t, K_EIP)) {
1843 SELECT_ACTIVITY(A_NET_EIP);
1845 else if (!strcmp(t, K_ICMP)) {
1846 SELECT_ACTIVITY(A_NET_ICMP);
1848 else if (!strcmp(t, K_EICMP)) {
1849 SELECT_ACTIVITY(A_NET_EICMP);
1851 else if (!strcmp(t, K_TCP)) {
1852 SELECT_ACTIVITY(A_NET_TCP);
1854 else if (!strcmp(t, K_ETCP)) {
1855 SELECT_ACTIVITY(A_NET_ETCP);
1857 else if (!strcmp(t, K_UDP)) {
1858 SELECT_ACTIVITY(A_NET_UDP);
1860 else if (!strcmp(t, K_SOCK6)) {
1861 SELECT_ACTIVITY(A_NET_SOCK6);
1863 else if (!strcmp(t, K_IP6)) {
1864 SELECT_ACTIVITY(A_NET_IP6);
1866 else if (!strcmp(t, K_EIP6)) {
1867 SELECT_ACTIVITY(A_NET_EIP6);
1869 else if (!strcmp(t, K_ICMP6)) {
1870 SELECT_ACTIVITY(A_NET_ICMP6);
1872 else if (!strcmp(t, K_EICMP6)) {
1873 SELECT_ACTIVITY(A_NET_EICMP6);
1875 else if (!strcmp(t, K_UDP6)) {
1876 SELECT_ACTIVITY(A_NET_UDP6);
1878 else if (!strcmp(t, K_FC)) {
1879 SELECT_ACTIVITY(A_NET_FC);
1881 else if (!strcmp(t, K_ALL)) {
1882 SELECT_ACTIVITY(A_NET_DEV);
1883 SELECT_ACTIVITY(A_NET_EDEV);
1884 SELECT_ACTIVITY(A_NET_SOCK);
1885 SELECT_ACTIVITY(A_NET_NFS);
1886 SELECT_ACTIVITY(A_NET_NFSD);
1887 SELECT_ACTIVITY(A_NET_IP);
1888 SELECT_ACTIVITY(A_NET_EIP);
1889 SELECT_ACTIVITY(A_NET_ICMP);
1890 SELECT_ACTIVITY(A_NET_EICMP);
1891 SELECT_ACTIVITY(A_NET_TCP);
1892 SELECT_ACTIVITY(A_NET_ETCP);
1893 SELECT_ACTIVITY(A_NET_UDP);
1894 SELECT_ACTIVITY(A_NET_SOCK6);
1895 SELECT_ACTIVITY(A_NET_IP6);
1896 SELECT_ACTIVITY(A_NET_EIP6);
1897 SELECT_ACTIVITY(A_NET_ICMP6);
1898 SELECT_ACTIVITY(A_NET_EICMP6);
1899 SELECT_ACTIVITY(A_NET_UDP6);
1900 SELECT_ACTIVITY(A_NET_FC);
1911 ***************************************************************************
1912 * Parse sar "-I" option.
1915 * @argv Arguments list.
1916 * @opt Index in list of arguments.
1917 * @act Array of activities.
1920 * @act Array of activities, with interrupts activity selected.
1923 * 0 on success, 1 otherwise.
1924 ***************************************************************************
1926 int parse_sar_I_opt(char *argv[], int *opt, struct activity *act[])
1932 /* Select interrupt activity */
1933 p = get_activity_position(act, A_IRQ, EXIT_IF_NOT_FOUND);
1934 act[p]->options |= AO_SELECTED;
1936 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1937 if (!strcmp(t, K_SUM)) {
1938 /* Select total number of interrupts */
1939 act[p]->bitmap->b_array[0] |= 0x01;
1941 else if (!strcmp(t, K_ALL)) {
1942 /* Set bit for the first 16 individual interrupts */
1943 act[p]->bitmap->b_array[0] |= 0xfe;
1944 act[p]->bitmap->b_array[1] |= 0xff;
1945 act[p]->bitmap->b_array[2] |= 0x01;
1947 else if (!strcmp(t, K_XALL)) {
1948 /* Set every bit except for total number of interrupts */
1949 c = act[p]->bitmap->b_array[0];
1950 set_bitmap(act[p]->bitmap->b_array, ~0,
1951 BITMAP_SIZE(act[p]->bitmap->b_size));
1952 act[p]->bitmap->b_array[0] = 0xfe | c;
1955 /* Get irq number */
1956 if (strspn(t, DIGITS) != strlen(t))
1959 if ((i < 0) || (i >= act[p]->bitmap->b_size))
1961 act[p]->bitmap->b_array[(i + 1) >> 3] |= 1 << ((i + 1) & 0x07);
1970 ***************************************************************************
1971 * Parse sar and sadf "-P" option.
1974 * @argv Arguments list.
1975 * @opt Index in list of arguments.
1976 * @act Array of activities.
1979 * @flags Common flags and system state.
1980 * @act Array of activities, with CPUs selected.
1983 * 0 on success, 1 otherwise.
1984 ***************************************************************************
1986 int parse_sa_P_opt(char *argv[], int *opt, unsigned int *flags, struct activity *act[])
1991 p = get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND);
1993 if (argv[++(*opt)]) {
1995 for (t = strtok(argv[*opt], ","); t; t = strtok(NULL, ",")) {
1996 if (!strcmp(t, K_ALL)) {
1998 * Set bit for every processor.
1999 * We still don't know if we are going to read stats
2000 * from a file or not...
2002 set_bitmap(act[p]->bitmap->b_array, ~0,
2003 BITMAP_SIZE(act[p]->bitmap->b_size));
2006 /* Get cpu number */
2007 if (strspn(t, DIGITS) != strlen(t))
2010 if ((i < 0) || (i >= act[p]->bitmap->b_size))
2012 act[p]->bitmap->b_array[(i + 1) >> 3] |= 1 << ((i + 1) & 0x07);
2024 ***************************************************************************
2025 * Compute network interface utilization.
2028 * @st_net_dev Structure with network interface stats.
2029 * @rx Number of bytes received per second.
2030 * @tx Number of bytes transmitted per second.
2033 * NIC utilization (0-100%).
2034 ***************************************************************************
2036 double compute_ifutil(struct stats_net_dev *st_net_dev, double rx, double tx)
2038 unsigned long long speed;
2040 if (st_net_dev->speed) {
2042 speed = (unsigned long long) st_net_dev->speed * 1000000;
2044 if (st_net_dev->duplex == C_DUPLEX_FULL) {
2047 return (rx * 800 / speed);
2050 return (tx * 800 / speed);
2055 return ((rx + tx) * 800 / speed);
2063 ***************************************************************************
2064 * Fill system activity file magic header.
2067 * @file_magic System activity file magic header.
2068 ***************************************************************************
2070 void enum_version_nr(struct file_magic *fm)
2075 fm->sysstat_extraversion = 0;
2077 strcpy(version, VERSION);
2079 /* Get version number */
2080 if ((v = strtok(version, ".")) == NULL)
2082 fm->sysstat_version = atoi(v) & 0xff;
2084 /* Get patchlevel number */
2085 if ((v = strtok(NULL, ".")) == NULL)
2087 fm->sysstat_patchlevel = atoi(v) & 0xff;
2089 /* Get sublevel number */
2090 if ((v = strtok(NULL, ".")) == NULL)
2092 fm->sysstat_sublevel = atoi(v) & 0xff;
2094 /* Get extraversion number. Don't necessarily exist */
2095 if ((v = strtok(NULL, ".")) == NULL)
2097 fm->sysstat_extraversion = atoi(v) & 0xff;
2101 ***************************************************************************
2102 * Read and replace unprintable characters in comment with ".".
2105 * @ifd Input file descriptor.
2107 ***************************************************************************
2109 void replace_nonprintable_char(int ifd, char *comment)
2114 sa_fread(ifd, comment, MAX_COMMENT_LEN, HARD_SIZE);
2115 comment[MAX_COMMENT_LEN - 1] = '\0';
2117 /* Replace non printable chars */
2118 for (i = 0; i < strlen(comment); i++) {
2119 if (!isprint(comment[i]))
2125 ***************************************************************************
2126 * Fill the rectime and loctime structures with current record's date and
2127 * time, based on current record's "number of seconds since the epoch" saved
2129 * For loctime (if given): The timestamp is expressed in local time.
2130 * For rectime: The timestamp is expressed in UTC, in local time, or in the
2131 * time of the file's creator depending on options entered by the user on the
2135 * @l_flags Flags indicating the type of time expected by the user.
2136 * S_F_LOCAL_TIME means time should be expressed in local time.
2137 * S_F_TRUE_TIME means time should be expressed in time of
2139 * Default is time expressed in UTC (except for sar, where it
2141 * @record_hdr Record header containing the number of seconds since the
2142 * epoch, and the HH:MM:SS of the file's creator.
2145 * @rectime Structure where timestamp for current record has been saved
2146 * (in local time or in UTC depending on options used).
2147 * @loctime If given, structure where timestamp for current record has
2148 * been saved (expressed in local time). This field will be used
2149 * for time comparison if options -s and/or -e have been used.
2152 * 1 if an error was detected, or 0 otherwise.
2153 ***************************************************************************
2155 int sa_get_record_timestamp_struct(unsigned int l_flags, struct record_header *record_hdr,
2156 struct tm *rectime, struct tm *loctime)
2158 struct tm *ltm = NULL;
2161 /* Fill localtime structure if given */
2163 if ((ltm = localtime((const time_t *) &(record_hdr->ust_time))) != NULL) {
2171 /* Fill generic rectime structure */
2172 if (PRINT_LOCAL_TIME(l_flags) && !ltm) {
2173 /* Get local time if not already done */
2174 ltm = localtime((const time_t *) &(record_hdr->ust_time));
2177 if (!PRINT_LOCAL_TIME(l_flags) && !PRINT_TRUE_TIME(l_flags)) {
2180 * (the user doesn't want local time nor time of file's creator).
2182 ltm = gmtime((const time_t *) &(record_hdr->ust_time));
2186 /* Done even in true time mode so that we have some default values */
2193 if (PRINT_TRUE_TIME(l_flags)) {
2194 /* Time of file's creator */
2195 rectime->tm_hour = record_hdr->hour;
2196 rectime->tm_min = record_hdr->minute;
2197 rectime->tm_sec = record_hdr->second;
2204 ***************************************************************************
2205 * Set current record's timestamp strings (date and time) using the time
2206 * data saved in @rectime structure. The string may be the number of seconds
2207 * since the epoch if flag S_F_SEC_EPOCH has been set.
2210 * @l_flags Flags indicating the type of time expected by the user.
2211 * S_F_SEC_EPOCH means the time should be expressed in seconds
2212 * since the epoch (01/01/1970).
2213 * @record_hdr Record header containing the number of seconds since the
2215 * @cur_date String where timestamp's date will be saved. May be NULL.
2216 * @cur_time String where timestamp's time will be saved.
2217 * @len Maximum length of timestamp strings.
2218 * @rectime Structure with current timestamp (expressed in local time or
2219 * in UTC depending on whether options -T or -t have been used
2220 * or not) that should be broken down in date and time strings.
2223 * @cur_date Timestamp's date string (if expected).
2224 * @cur_time Timestamp's time string. May contain the number of seconds
2225 * since the epoch (01-01-1970) if corresponding option has
2227 ***************************************************************************
2229 void set_record_timestamp_string(unsigned int l_flags, struct record_header *record_hdr,
2230 char *cur_date, char *cur_time, int len, struct tm *rectime)
2232 /* Set cur_time date value */
2233 if (PRINT_SEC_EPOCH(l_flags) && cur_date) {
2234 sprintf(cur_time, "%ld", record_hdr->ust_time);
2235 strcpy(cur_date, "");
2239 * If options -T or -t have been used then cur_time is
2240 * expressed in local time. Else it is expressed in UTC.
2243 strftime(cur_date, len, "%Y-%m-%d", rectime);
2245 if (USE_PREFD_TIME_OUTPUT(l_flags)) {
2246 strftime(cur_time, len, "%X", rectime);
2249 strftime(cur_time, len, "%H:%M:%S", rectime);
2255 ***************************************************************************
2256 * Print contents of a special (RESTART or COMMENT) record.
2259 * @record_hdr Current record header.
2260 * @l_flags Flags for common options.
2261 * @tm_start Structure filled when option -s has been used.
2262 * @tm_end Structure filled when option -e has been used.
2263 * @rtype Record type (R_RESTART or R_COMMENT).
2264 * @ifd Input file descriptor.
2265 * @rectime Structure where timestamp (expressed in local time or in UTC
2266 * depending on whether options -T/-t have been used or not) can
2267 * be saved for current record.
2268 * @loctime Structure where timestamp (expressed in local time) can be
2269 * saved for current record. May be NULL.
2270 * @file Name of file being read.
2271 * @tab Number of tabulations to print.
2272 * @file_magic file_magic structure filled with file magic header data.
2273 * @file_hdr System activity file standard header.
2274 * @act Array of activities.
2275 * @ofmt Pointer on report output format structure.
2278 * @rectime Structure where timestamp (expressed in local time
2279 * or in UTC) has been saved.
2280 * @loctime Structure where timestamp (expressed in local time)
2281 * has been saved (if requested).
2284 * 1 if the record has been successfully displayed, and 0 otherwise.
2285 ***************************************************************************
2287 int print_special_record(struct record_header *record_hdr, unsigned int l_flags,
2288 struct tstamp *tm_start, struct tstamp *tm_end, int rtype, int ifd,
2289 struct tm *rectime, struct tm *loctime, char *file, int tab,
2290 struct file_magic *file_magic, struct file_header *file_hdr,
2291 struct activity *act[], struct report_format *ofmt)
2293 char cur_date[32], cur_time[32];
2295 unsigned int new_cpu_nr;
2297 /* Fill timestamp structure (rectime) for current record */
2298 if (sa_get_record_timestamp_struct(l_flags, record_hdr, rectime, loctime))
2301 /* If loctime is NULL, then use rectime for comparison */
2306 /* The record must be in the interval specified by -s/-e options */
2307 if ((tm_start->use && (datecmp(loctime, tm_start) < 0)) ||
2308 (tm_end->use && (datecmp(loctime, tm_end) > 0))) {
2309 /* Will not display the special record */
2313 /* Set date and time strings to be displayed for current record */
2314 set_record_timestamp_string(l_flags, record_hdr,
2315 cur_date, cur_time, 32, rectime);
2318 if (rtype == R_RESTART) {
2319 /* Don't forget to read the volatile activities structures */
2320 new_cpu_nr = read_vol_act_structures(ifd, act, file, file_magic,
2321 file_hdr->sa_vol_act_nr);
2326 if (*ofmt->f_restart) {
2327 (*ofmt->f_restart)(&tab, F_MAIN, cur_date, cur_time,
2328 !PRINT_LOCAL_TIME(l_flags) &&
2329 !PRINT_TRUE_TIME(l_flags), file_hdr,
2333 else if (rtype == R_COMMENT) {
2334 char file_comment[MAX_COMMENT_LEN];
2336 /* Read and replace non printable chars in comment */
2337 replace_nonprintable_char(ifd, file_comment);
2339 if (!dp || !DISPLAY_COMMENT(l_flags))
2342 if (*ofmt->f_comment) {
2343 (*ofmt->f_comment)(&tab, F_MAIN, cur_date, cur_time,
2344 !PRINT_LOCAL_TIME(l_flags) &&
2345 !PRINT_TRUE_TIME(l_flags), file_comment,