* |
* |-- --|
* | |
- * | file_activity structure | * sa_act_nr
+ * | file_activity structure | x file_header:sa_act_nr
* | |
- * |-- --|
+ * |--------- --|
+ * |
+ * | extra_desc structure (exists only if file_header:extra_next != 0)
+ * |
+ * |-- --|
+ * | |
+ * | unknown extra structure(s) | x extra_desc:extra_nr
+ * | |
+ * |-- --|
+ * |
+ * | (extra_desc structure (exists only if previous extra_desc:extra_next != 0))
+ * |
+ * |--
+ * |
+ * | (...)
+ * |
+ * |--------- --|
* | |
* | record_header structure |
* | |
- * |-- |
+ * |--------- --|
+ * |
+ * | extra_desc structure (exists only if record_header:extra_next != 0)
+ * |
+ * |-- --|
+ * | |
+ * | unknown extra structure(s) | x extra_desc:extra_nr
+ * | |
+ * |-- --|
+ * |
+ * | (extra_desc structure (exists only if previous extra_desc:extra_next != 0))
+ * |
+ * |--
+ * |
+ * | (...)
+ * |
+ * |--------- --|
* |(__nr_t) |
* |-- |
* | |
- * | Statistics structure(s) | * <count>
+ * | Statistics structure(s) | x <count>
* | |
* |-- |
* |(__nr_t) |
* 2 for 1 CPU and SMP kernel (CPU "all" and CPU 0), etc.
* Of course we display the real number of CPU (e.g. "1" for 1 CPU and SMP
* kernel) with the LINUX RESTART message.
+ *
+ * If the record_header's type is R_EXTRA then we find only a list of extra
+ * structures following the record_header structure but no statistics ones.
+ * Note that extra structures may exist for all record_header types
+ * (R_STATS, R_COMMENT, R_RESTART...). For R_COMMENT and R_RESTART records,
+ * the extra structures will be found after the comment or the number of CPU.
***************************************************************************
*/
*/
unsigned int act_size;
unsigned int rec_size;
+ /*
+ * TRUE if an extra_desc structure exists.
+ */
+ unsigned int extra_next;
/*
* Current day and month.
* No need to save DST (Daylight Saving Time) flag, since it is not taken
#define FILE_HEADER_SIZE (sizeof(struct file_header))
#define FILE_HEADER_ULL_NR 1 /* Nr of unsigned long long in file_header structure */
#define FILE_HEADER_UL_NR 1 /* Nr of unsigned long in file_header structure */
-#define FILE_HEADER_U_NR 11 /* Nr of [unsigned] int in file_header structure */
+#define FILE_HEADER_U_NR 12 /* Nr of [unsigned] int in file_header structure */
/* The values below are used for sanity check */
#define MIN_FILE_HEADER_SIZE 0
#define MAX_FILE_HEADER_SIZE 8192
#define FILE_ACTIVITY_UL_NR 0 /* Nr of unsigned long in file_activity structure */
#define FILE_ACTIVITY_U_NR 9 /* Nr of [unsigned] int in file_activity structure */
+/*
+ * Description of an extra structure.
+ * The composition of this structure should not change in time.
+ */
+struct extra_desc {
+ /*
+ * Number of extra structures to read.
+ */
+ unsigned int extra_nr;
+ /*
+ * Size of an extra structure.
+ */
+ unsigned int extra_size;
+ /*
+ * TRUE if another extra_desc structure exists after
+ * all the extra structures.
+ */
+ unsigned int extra_next;
+ /*
+ * Description of an extra structure
+ * (nr of "long long", nr of "long" and nr of "int").
+ */
+ unsigned int extra_types_nr[3];
+};
+
+#define EXTRA_DESC_SIZE (sizeof(struct extra_desc))
+#define EXTRA_DESC_ULL_NR 0 /* Nr of unsigned long long in extra_desc structure */
+#define EXTRA_DESC_UL_NR 0 /* Nr of unsigned long in extra_desc structure */
+#define EXTRA_DESC_U_NR 6 /* Nr of [unsigned] int in extra_desc structure */
/* Record type */
/*
* a comment.
*/
#define R_COMMENT 4
+/*
+ * R_EXTRA means that extra structures are following current
+ * record_header structure, but no statistics structures.
+ */
+#define R_EXTRA 5
/* Maximum length of a comment */
#define MAX_COMMENT_LEN 64
* Timestamp (number of seconds since the epoch).
*/
unsigned long long ust_time;
+ /*
+ * TRUE if an extra_desc structure exists.
+ */
+ unsigned int extra_next;
/*
* Record type: R_STATS, R_RESTART,...
*/
#define MAX_RECORD_HEADER_SIZE 512 /* Used for sanity check */
#define RECORD_HEADER_ULL_NR 2 /* Nr of unsigned long long in record_header structure */
#define RECORD_HEADER_UL_NR 0 /* Nr of unsigned long in record_header structure */
-#define RECORD_HEADER_U_NR 0 /* Nr of unsigned int in record_header structure */
+#define RECORD_HEADER_U_NR 1 /* Nr of unsigned int in record_header structure */
/*
(void);
int set_default_file
(char *, int, int);
+int skip_extra_struct
+ (int, int, int);
int write_all
(int, const void *, int);
unsigned int hdr_types_nr[] = {FILE_HEADER_ULL_NR, FILE_HEADER_UL_NR, FILE_HEADER_U_NR};
unsigned int act_types_nr[] = {FILE_ACTIVITY_ULL_NR, FILE_ACTIVITY_UL_NR, FILE_ACTIVITY_U_NR};
unsigned int rec_types_nr[] = {RECORD_HEADER_ULL_NR, RECORD_HEADER_UL_NR, RECORD_HEADER_U_NR};
+unsigned int extra_desc_types_nr[] = {EXTRA_DESC_ULL_NR, EXTRA_DESC_UL_NR, EXTRA_DESC_U_NR};
unsigned int nr_types_nr[] = {0, 0, 1};
/*
return 0;
}
+/*
+ ***************************************************************************
+ * Skip unknown extra structures present in file.
+ *
+ * IN:
+ * @ifd System activity data file descriptor.
+ * @endian_mismatch
+ * TRUE if file's data don't match current machine's endianness.
+ * @arch_64 TRUE if file's data come from a 64 bit machine.
+ *
+ * RETURNS:
+ * -1 on error, 0 otherwise.
+ ***************************************************************************
+ */
+int skip_extra_struct(int ifd, int endian_mismatch, int arch_64)
+{
+ int i;
+ struct extra_desc xtra_d;
+
+ do {
+ /* Read extra structure description */
+ sa_fread(ifd, &xtra_d, EXTRA_DESC_SIZE, HARD_SIZE, UEOF_STOP);
+
+ /*
+ * We don't need to remap as the extra_desc structure won't change,
+ * but we may need to normalize endianness anyway.
+ */
+ if (endian_mismatch) {
+ swap_struct(extra_desc_types_nr, &xtra_d, arch_64);
+ }
+
+ /* Check values consistency */
+ if (MAP_SIZE(xtra_d.extra_types_nr) > xtra_d.extra_size) {
+#ifdef DEBUG
+ fprintf(stderr, "%s: extra_size=%u types=%d,%d,%d\n",
+ __FUNCTION__, xtra_d.extra_size,
+ xtra_d.extra_types_nr[0], xtra_d.extra_types_nr[1], xtra_d.extra_types_nr[2]);
+#endif
+ return -1;
+ }
+
+ /* Ignore current unknown extra structures */
+ for (i = 0; i < xtra_d.extra_nr; i++) {
+ if (lseek(ifd, xtra_d.extra_size, SEEK_CUR) < xtra_d.extra_size)
+ return -1;
+ }
+ }
+ while (xtra_d.extra_next);
+
+ return 0;
+}
+
/*
***************************************************************************
* Read the record header of current sample and process it.
{
int rc;
- if ((rc = sa_fread(ifd, buffer, (size_t) file_hdr->rec_size, SOFT_SIZE, oneof)) != 0)
- /* End of sa data file */
- return rc;
+ do {
+ if ((rc = sa_fread(ifd, buffer, (size_t) file_hdr->rec_size, SOFT_SIZE, oneof)) != 0)
+ /* End of sa data file */
+ return rc;
- /* Remap record header structure to that expected by current version */
- if (remap_struct(rec_types_nr, file_hdr->rec_types_nr, buffer,
- file_hdr->rec_size, RECORD_HEADER_SIZE, b_size) < 0)
- return 2;
- memcpy(record_hdr, buffer, RECORD_HEADER_SIZE);
+ /* Remap record header structure to that expected by current version */
+ if (remap_struct(rec_types_nr, file_hdr->rec_types_nr, buffer,
+ file_hdr->rec_size, RECORD_HEADER_SIZE, b_size) < 0)
+ return 2;
+ memcpy(record_hdr, buffer, RECORD_HEADER_SIZE);
- /* Normalize endianness */
- if (endian_mismatch) {
- swap_struct(rec_types_nr, record_hdr, arch_64);
+ /* Normalize endianness */
+ if (endian_mismatch) {
+ swap_struct(rec_types_nr, record_hdr, arch_64);
+ }
+
+ /*
+ * Skip unknown extra structures if present.
+ * This will be done later for R_COMMENT and R_RESTART records, as extra structures
+ * are saved after the comment or the number of CPU.
+ */
+ if ((record_hdr->record_type != R_COMMENT) && (record_hdr->record_type != R_RESTART) &&
+ record_hdr->extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
+ return 2;
}
+ while (record_hdr->record_type == R_EXTRA);
return 0;
}
exit(1);
}
+ /*
+ * Check if there are some extra structures.
+ * We will just skip them as they are unknown for now.
+ */
+ if (file_hdr->extra_next && (skip_extra_struct(*ifd, *endian_mismatch, *arch_64) < 0))
+ goto format_error;
+
return;
format_error:
}
}
+ /* Ignore unknown extra structures if present */
+ if (record_hdr->extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
+ return 0;
+
if (!dp)
return 0;
/* Read and replace non printable chars in comment */
replace_nonprintable_char(ifd, file_comment);
+ /* Ignore unknown extra structures if present */
+ if (record_hdr->extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
+ return 0;
+
if (!dp || !DISPLAY_COMMENT(l_flags))
return 0;
if (action & IGNORE_COMMENT) {
/* Ignore COMMENT record */
if (lseek(ifd, MAX_COMMENT_LEN, SEEK_CUR) < MAX_COMMENT_LEN) {
- perror("lseek");
if (oneof == UEOF_CONT)
return 2;
close(ifd);
exit(2);
}
+
+ /* Ignore unknown extra structures if present */
+ if (record_hdr[curr].extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
+ return 2;
+
if (action & SET_TIMESTAMPS) {
sa_get_record_timestamp_struct(flags, &record_hdr[curr],
rectime);
if (!(action & DONT_READ_CPU_NR)) {
file_hdr.sa_cpu_nr = read_nr_value(ifd, file, file_magic,
endian_mismatch, arch_64, TRUE);
+
+ /* Ignore unknown extra structures if present */
+ if (record_hdr[curr].extra_next && (skip_extra_struct(ifd, endian_mismatch, arch_64) < 0))
+ return 2;
}
if (action & SET_TIMESTAMPS) {
sa_get_record_timestamp_struct(flags, &record_hdr[curr], rectime);
}
while (*cnt && !*eosaf && (rtype != R_RESTART));
+ /*
+ * At this moment, if we had a R_RESTART record, we still haven't read
+ * the number of CPU following it (nor the possible extra structures).
+ * But in this case, we always have @cnt != 0.
+ */
+
if (davg) {
write_stats_avg(!*curr, USE_SA_FILE, act_id);
}
}
}
}
-
if (!cnt) {
- /* Go to next Linux restart, if possible */
+ /*
+ * Go to next Linux restart, if possible.
+ * Note: If we have @cnt == 0 then the last record we read was not a R_RESTART one
+ * (else we would have had @cnt != 0, i.e. we would have stopped reading previous activity
+ * because such a R_RESTART record would have been read, not because all the <count> lines
+ * had been printed).
+ * Remember @cnt is decremented only when a real line of stats have been displayed
+ * (not when a special record has been read).
+ */
do {
/* Read next record header */
eosaf = read_record_hdr(ifd, rec_hdr_tmp, &record_hdr[curr],