*/
struct activity cpu_act = {
.id = A_CPU,
- .options = AO_COLLECTED + AO_REMANENT + AO_GLOBAL_ITV + AO_MULTIPLE_OUTPUTS,
+ .options = AO_COLLECTED + AO_VOLATILE + AO_GLOBAL_ITV + AO_MULTIPLE_OUTPUTS,
.magic = ACTIVITY_MAGIC_BASE,
.group = G_DEFAULT,
#ifdef SOURCE_SADC
/* CPU frequency */
struct activity pwr_cpufreq_act = {
.id = A_PWR_CPUFREQ,
- .options = AO_NULL,
+ .options = AO_VOLATILE,
.magic = ACTIVITY_MAGIC_BASE,
.group = G_POWER,
#ifdef SOURCE_SADC
/* CPU weighted frequency */
struct activity pwr_wghfreq_act = {
.id = A_PWR_WGHFREQ,
- .options = AO_NULL,
+ .options = AO_VOLATILE,
.magic = ACTIVITY_MAGIC_BASE,
.group = G_POWER,
#ifdef SOURCE_SADC
#define AO_SELECTED 0x02
/*
* When appending data to a file, the number of items (for every activity)
- * is forced to that of the file (number of network interfaces, serial lines, etc.)
- * Except for remanent activities like A_CPU: If current
- * machine has a different number of CPU than that of the file (but is
- * equal to last_cpu_nr) then data will be appended with a number of items
- * equal to that of the machine.
+ * is forced to that of the file (number of network interfaces, serial lines,
+ * etc.) Exceptions are volatile activities (like A_CPU) whose number of items
+ * is related to the number of CPUs: If current machine has a different number
+ * of CPU than that of the file (but is equal to sa_last_cpu_nr) then data
+ * will be appended with a number of items equal to that of the machine.
*/
-#define AO_REMANENT 0x04
+#define AO_VOLATILE 0x04
/*
* Indicate that the interval of time, given to f_print() function
* displaying statistics, should be the interval of time in jiffies
#define IS_COLLECTED(m) (((m) & AO_COLLECTED) == AO_COLLECTED)
#define IS_SELECTED(m) (((m) & AO_SELECTED) == AO_SELECTED)
-#define IS_REMANENT(m) (((m) & AO_REMANENT) == AO_REMANENT)
+#define IS_VOLATILE(m) (((m) & AO_VOLATILE) == AO_VOLATILE)
#define NEED_GLOBAL_ITV(m) (((m) & AO_GLOBAL_ITV) == AO_GLOBAL_ITV)
#define CLOSE_MARKUP(m) (((m) & AO_CLOSE_MARKUP) == AO_CLOSE_MARKUP)
#define HAS_MULTIPLE_OUTPUTS(m) (((m) & AO_MULTIPLE_OUTPUTS) == AO_MULTIPLE_OUTPUTS)
* |-- --|
*
* (*)Note: If it's a special record, we may find a comment instead of
- * statistics (R_COMMENT record type) or the number of CPU items (R_RESTART
- * record type).
+ * statistics (R_COMMENT record type) or, if it's a R_RESTART record type,
+ * <sa_nr_vol_act> structures (of type file_activity) for the volatile
+ * activities.
***************************************************************************
*/
* Modified to indicate that the format of the file is
* no longer compatible with that of previous sysstat versions.
*/
-#define FORMAT_MAGIC 0x2172
+#define FORMAT_MAGIC 0x2173
/* Structure for file magic header data */
struct file_magic {
/*
* Number of CPU items (1 .. CPU_NR + 1) for the last sample in file.
*/
- unsigned int last_cpu_nr;
+ unsigned int sa_last_cpu_nr __attribute__ ((aligned (8)));
/*
* Number of activities saved in the file
*/
- unsigned int sa_nr_act __attribute__ ((aligned (8)));
+ unsigned int sa_nr_act;
+ /*
+ * Number of volatile activities in file. This is the number of
+ * file_activity structures saved after each restart mark in file.
+ */
+ unsigned int sa_vol_act_nr;
/*
* Current day, month and year.
* No need to save DST (Daylight Saving Time) flag, since it is not taken
}
/*
* NOTA BENE:
- * If current activity is A_CPU, we are setting
- * act[p]->nr to fal->nr, which is the number of CPU for the
- * statistics located between the start of the data file and the
- * first restart mark. Remember that the number of CPU can vary
+ * If current activity is a volatile one then fal->nr is the
+ * number of items (CPU at the present time as only CPU related
+ * activities are volatile today) for the statistics located
+ * between the start of the data file and the first restart mark.
+ * Volatile activities have a number of items which can vary
* in file. In this case, a RESTART record is followed by the
- * new number of CPU.
+ * volatile activity structures.
*/
act[p]->nr = fal->nr;
act[p]->nr2 = fal->nr2;
/*
***************************************************************************
- * Set number of CPU items and reallocate CPU structures accordingly.
+ * Set number of items for current volatile activity and reallocate its
+ * structures accordingly.
+ * NB: As only activities related to CPU can be volatile, the number of
+ * items corresponds in fact to the number of CPU.
*
* IN:
* @act Array of activities.
- * @cpu_nr Number of CPU items.
+ * @act_nr Number of items for current volatile activity.
+ * @act_id Activity identification for current volatile activity.
+ *
+ * RETURN:
+ * -1 if unknown activity and 0 otherwise.
***************************************************************************
*/
-void allocate_cpu_structures(struct activity *act[], unsigned int cpu_nr)
+int reallocate_vol_act_structures(struct activity *act[], unsigned int act_nr,
+ unsigned int act_id)
{
int j, p;
- /* Set new CPU count and reallocate structures */
- p = get_activity_position(act, A_CPU);
- act[p]->nr = cpu_nr;
+ if ((p = get_activity_position(act, act_id)) < 0)
+ /* Ignore unknown activity */
+ return -1;
+
+ act[p]->nr = act_nr;
for (j = 0; j < 3; j++) {
SREALLOC(act[p]->buf[j], void, act[p]->msize * act[p]->nr * act[p]->nr2);
}
+
+ return 0;
}
/*
***************************************************************************
- * Read the new CPU count following a RESTART record. Then set corresponding
- * number of items for A_CPU activity and reallocate structures.
+ * Read the volatile activities structures following a RESTART record.
+ * Then set number of items for each corresponding activity and reallocate
+ * structures.
*
* IN:
* @ifd Input file descriptor.
* @act Array of activities.
+ * @file Name of file being read.
+ * @file_magic file_magic structure filled with file magic header data.
+ * @vol_act_nr Number of volatile activities structures to read.
*
* RETURNS:
- * New number of CPU count.
+ * New number of items.
+ *
+ * NB: As only activities related to CPU can be volatile, the new number of
+ * items corresponds in fact to the new number of CPU.
***************************************************************************
*/
-unsigned int read_new_cpu_nr(int ifd, struct activity *act[])
+__nr_t read_vol_act_structures(int ifd, struct activity *act[], char *file,
+ struct file_magic *file_magic,
+ unsigned int vol_act_nr)
{
- unsigned int new_cpu_nr;
-
- /* Read new number of CPU following the RESTART record */
- sa_fread(ifd, &new_cpu_nr, sizeof(unsigned int), HARD_SIZE);
+ struct file_activity file_act;
+ int item_nr = 0;
+ int i, rc;
- if (!new_cpu_nr) {
- /* CPU number cannot be zero */
- fprintf(stderr, _("Bad CPU count saved in file\n"));
- close(ifd);
- exit(2);
+ for (i = 0; i < vol_act_nr; i++) {
+
+ sa_fread(ifd, &file_act, FILE_ACTIVITY_SIZE, HARD_SIZE);
+
+ if (file_act.id) {
+ rc = reallocate_vol_act_structures(act, file_act.nr, file_act.id);
+ if ((rc == 0) && !item_nr) {
+ item_nr = file_act.nr;
+ }
+ }
+ /* else ignore empty structures that may exist */
}
- /* Set new CPU count and reallocate structures */
- allocate_cpu_structures(act, new_cpu_nr);
-
- return new_cpu_nr;
+ if (!item_nr) {
+ /* All volatile activities structures cannot be empty */
+ handle_invalid_sa_file(&ifd, file_magic, file, 0);
+ }
+
+ return item_nr;
}
/*
struct file_header file_hdr;
struct record_header record_hdr;
+
char comment[MAX_COMMENT_LEN];
+
unsigned int id_seq[NR_ACT];
+unsigned int vol_id_seq[NR_ACT];
extern struct activity *act[];
/* OK, now fill the header */
file_hdr.sa_nr_act = get_activity_nr(act, AO_COLLECTED, COUNT_ACTIVITIES);
+ file_hdr.sa_vol_act_nr = get_activity_nr(act, AO_COLLECTED + AO_VOLATILE,
+ COUNT_ACTIVITIES);
file_hdr.sa_day = rectime.tm_mday;
file_hdr.sa_month = rectime.tm_mon;
file_hdr.sa_year = rectime.tm_year;
file_hdr.sa_sizeof_long = sizeof(long);
/*
- * This is a new file (or stdout): Field last_cpu_nr is set to the number
+ * This is a new file (or stdout): Field sa_last_cpu_nr is set to the number
* of CPU items of the machine (1 .. CPU_NR + 1).
* A_CPU activity is always collected, hence its number of items is
* always counted (in sa_sys_init()).
*/
- file_hdr.last_cpu_nr = act[get_activity_position(act, A_CPU)]->nr;
+ file_hdr.sa_last_cpu_nr = act[get_activity_position(act, A_CPU)]->nr;
/* Get system name, release number, hostname and machine architecture */
uname(&header);
if ((n = write_all(fd, &file_act, FILE_ACTIVITY_SIZE))
!= FILE_ACTIVITY_SIZE)
goto write_error;
+
+ /* Create sequence of volatile activities */
+ if (IS_VOLATILE(act[p]->options)) {
+ vol_id_seq[i] = act[p]->id;
+ }
}
}
exit(2);
}
+/*
+ ***************************************************************************
+ * Write the volatile activity structures following each restart mark.
+ * sa_vol_act_nr structures have to be written.
+ * Note that volatile activities written after the restart marks may be
+ * different within the same file if different versions of sysstat have been
+ * used to create the file and then to append data to it.
+ *
+ * IN:
+ * @ofd Output file descriptor.
+ ***************************************************************************
+ */
+void write_vol_act_structures(int ofd)
+{
+ struct file_activity file_act;
+ int i, p, n;
+
+ memset(&file_act, 0, FILE_ACTIVITY_SIZE);
+
+ for (i = 0; i < file_hdr.sa_vol_act_nr; i++) {
+
+ if (!vol_id_seq[i]) {
+ /*
+ * Write an empty structure when current sysstat
+ * version know fewer volatile activities than
+ * the number saved in file's header.
+ */
+ file_act.id = file_act.nr = 0;
+ }
+ else {
+ p = get_activity_position(act, vol_id_seq[i]);
+
+ /*
+ * All the fields in file_activity structure are not used.
+ * In particular, act[p]->nr2 is left unmodified.
+ */
+ file_act.id = act[p]->id;
+ file_act.nr = act[p]->nr;
+ }
+
+ if ((n = write_all(ofd, &file_act, FILE_ACTIVITY_SIZE)) != FILE_ACTIVITY_SIZE) {
+ p_write_error();
+ }
+ }
+}
+
/*
***************************************************************************
* sadc called with interval and count parameters not set:
}
if (rtype == R_RESTART) {
- /* Also write current number of CPU */
- if ((n = write_all(ofd, &file_hdr.last_cpu_nr, sizeof(unsigned int))) != sizeof(unsigned int)) {
- p_write_error();
- }
+ /* Also write the volatile activities structures */
+ write_vol_act_structures(ofd);
}
else if (rtype == R_COMMENT) {
/* Also write the comment */
void *buffer = NULL;
ssize_t sz, n;
off_t fpos;
- int i, p;
+ int i, j, p;
if (!ofile[0])
return;
SREALLOC(buffer, char, file_magic.header_size);
- /* Save current file position */
+ /*
+ * Save current file position.
+ * Needed later to update sa_last_cpu_nr.
+ */
if ((fpos = lseek(*ofd, 0, SEEK_CUR)) < 0) {
perror("lseek");
exit(2);
(act[p]->magic != file_act[i].magic))
/*
* Unknown activity in list or item size has changed or
- * unknown activity format.
+ * unknown activity format: Cannot append data to such a file.
*/
goto append_error;
id_seq[i] = 0;
}
+ j = 0;
+
for (i = 0; i < file_hdr.sa_nr_act; i++) {
p = get_activity_position(act, file_act[i].id);
- if (((act[p]->nr != file_act[i].nr) || (act[p]->nr2 != file_act[i].nr2)) &&
- !IS_REMANENT(act[p]->options)) {
- /*
- * Force number of items (serial lines, network interfaces...)
- * and sub-items to that of the file (except for remanent activities),
- * and reallocate structures.
- */
+ /*
+ * Force number of items (serial lines, network interfaces...)
+ * and sub-items to that of the file, and reallocate structures.
+ * Exceptions are volatile activities, for which number of items
+ * is kept unmodified unless its value was zero (in this case,
+ * it is also forced to the value of the file).
+ * Also keep in mind that the file cannot contain more than
+ * sa_vol_act_nr volatile activities.
+ */
+ if (!IS_VOLATILE(act[p]->options) || !act[p]->nr || (j >= file_hdr.sa_vol_act_nr)) {
act[p]->nr = file_act[i].nr;
- act[p]->nr2 = file_act[i].nr2;
- SREALLOC(act[p]->_buf0, void, act[p]->msize * act[p]->nr * act[p]->nr2);
}
+ else {
+ vol_id_seq[j++] = file_act[i].id;
+ }
+ act[p]->nr2 = file_act[i].nr2;
+ SREALLOC(act[p]->_buf0, void, act[p]->msize * act[p]->nr * act[p]->nr2);
/* Save activity sequence */
id_seq[i] = file_act[i].id;
act[p]->options |= AO_COLLECTED;
}
+
+ while (j < file_hdr.sa_vol_act_nr) {
+ vol_id_seq[j++] = 0;
+ }
p = get_activity_position(act, A_CPU);
if (!IS_COLLECTED(act[p]->options)) {
goto append_error;
}
- if (act[p]->nr != file_hdr.last_cpu_nr) {
- if (!restart_mark) {
- /*
- * Current number of cpu items (for current system) should match
- * number of cpu items of the last sample saved in file.
- * Yet, this number can be different if we are inserting a restart mark.
- */
- goto append_error;
- }
- else {
+ if (act[p]->nr != file_hdr.sa_last_cpu_nr) {
+ if (restart_mark) {
/*
* We are inserting a restart mark, and current machine
* has a different number of CPU than that saved in file,
- * so update last_cpu_nr in file's header and rewrite it.
+ * so update sa_last_cpu_nr in file's header and rewrite it.
*/
- file_hdr.last_cpu_nr = act[p]->nr;
+ file_hdr.sa_last_cpu_nr = act[p]->nr;
rewrite_file_hdr(ofd, fpos, &file_magic);
}
+ else {
+ /*
+ * Current number of cpu items (for current system)
+ * doesn't match number of cpu items of the last sample
+ * saved in file.
+ */
+ goto append_error;
+ }
}
}
* @use_tm_end Set to TRUE if option -e has been used.
* @rtype Record type to display.
* @ifd Input file descriptor.
+ * @file Name of file being read.
+ * @file_magic file_magic structure filled with file magic header
+ * data.
*
* RETURNS:
* 1 if the record has been successfully displayed, and 0 otherwise.
***************************************************************************
*/
-int sar_print_special(int curr, int use_tm_start, int use_tm_end, int rtype, int ifd)
+int sar_print_special(int curr, int use_tm_start, int use_tm_end, int rtype,
+ int ifd, char *file, struct file_magic *file_magic)
{
char cur_time[26];
int dp = 1;
}
if (rtype == R_RESTART) {
- /* Don't forget to read new number of CPU */
- new_cpu_nr = read_new_cpu_nr(ifd, act);
+ /* Don't forget to read the volatile activities structures */
+ new_cpu_nr = read_vol_act_structures(ifd, act, file, file_magic,
+ file_hdr.sa_vol_act_nr);
if (dp) {
printf("\n%-11s LINUX RESTART\t(%d CPU)\n",
* @rows Number of rows of screen.
* @act_id Activity to display.
* @file_actlst List of activities in file.
+ * @file Name of file being read.
+ * @file_magic file_magic structure filled with file magic header data.
*
* OUT:
* @curr Index in array for next sample statistics.
*/
void handle_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf,
int rows, unsigned int act_id, int *reset,
- struct file_activity *file_actlst)
+ struct file_activity *file_actlst, char *file,
+ struct file_magic *file_magic)
{
int p;
unsigned long lines = 0;
if (rtype == R_COMMENT) {
/* Display comment */
next = sar_print_special(*curr, tm_start.use, tm_end.use,
- R_COMMENT, ifd);
+ R_COMMENT, ifd, file, file_magic);
if (next) {
/* A line of comment was actually displayed */
lines++;
rtype = record_hdr[0].record_type;
if ((rtype == R_RESTART) || (rtype == R_COMMENT)) {
- sar_print_special(0, tm_start.use, tm_end.use, rtype, ifd);
+ sar_print_special(0, tm_start.use, tm_end.use, rtype,
+ ifd, from_file, &file_magic);
}
else {
/*
if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) {
handle_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, rows,
- act[p]->id, &reset, file_actlst);
+ act[p]->id, &reset, file_actlst,
+ from_file, &file_magic);
}
else {
unsigned int optf, msk;
handle_curr_act_stats(ifd, fpos, &curr, &cnt,
&eosaf, rows, act[p]->id,
- &reset, file_actlst);
+ &reset, file_actlst,
+ from_file, &file_magic);
act[p]->opt_flags = optf;
}
}
}
else if (!eosaf && (rtype == R_COMMENT)) {
/* This was a COMMENT record: print it */
- sar_print_special(curr, tm_start.use, tm_end.use, R_COMMENT, ifd);
+ sar_print_special(curr, tm_start.use, tm_end.use, R_COMMENT,
+ ifd, from_file, &file_magic);
}
}
while (!eosaf && (rtype != R_RESTART));
/* The last record we read was a RESTART one: Print it */
if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) {
- sar_print_special(curr, tm_start.use, tm_end.use, R_RESTART, ifd);
+ sar_print_special(curr, tm_start.use, tm_end.use, R_RESTART,
+ ifd, from_file, &file_magic);
}
}
while (!eosaf);