]> granicus.if.org Git - sysstat/commitdiff
sar: Take into account a change of CPU number in sar datafile (4)
authorSebastien GODARD <sysstat@users.noreply.github.com>
Wed, 5 Feb 2014 14:56:26 +0000 (15:56 +0100)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Wed, 5 Feb 2014 14:56:26 +0000 (15:56 +0100)
Update sadf so that it can read the new datafiles format.
sadf now displays the CPU count in the restart messages.

Signed-off-by: Sebastien GODARD <sysstat@users.noreply.github.com>
sa.h
sa_common.c
sadf.c
sadf.h
sadf_misc.c

diff --git a/sa.h b/sa.h
index df59374f79543c523971f428429e07664433e74b..1ef74133b30ad1f9b496dcd3405f7d42c17d7884 100644 (file)
--- a/sa.h
+++ b/sa.h
@@ -795,6 +795,8 @@ extern __read_funct_t
 /* Other functions */
 extern void
        allocate_bitmaps(struct activity * []);
+extern void
+       allocate_cpu_structures(struct activity * [], unsigned int);
 extern void
        allocate_structures(struct activity * []);
 extern int
index f0338e8a5244d5354fe36a82947833450b1b886d..829736dfa5965f7c64ed712f856b2c9fe6a422b1 100644 (file)
@@ -1234,6 +1234,28 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
        }
 }
 
+/*
+ ***************************************************************************
+ * Set number of CPU items and reallocate CPU structures accordingly.
+ *
+ * IN:
+ * @act                Array of activities.
+ * @cpu_nr     Number of CPU items.
+ ***************************************************************************
+ */
+void allocate_cpu_structures(struct activity *act[], unsigned int cpu_nr)
+{
+       int j, p;
+       
+       /* Set new CPU count and reallocate structures */
+       p = get_activity_position(act, A_CPU);
+       act[p]->nr = cpu_nr;
+
+       for (j = 0; j < 3; j++) {
+               SREALLOC(act[p]->buf[j], void, act[p]->msize * act[p]->nr * act[p]->nr2);
+       }
+}
+
 /*
  ***************************************************************************
  * Read the new CPU count following a RESTART record. Then set corresponding
@@ -1250,7 +1272,6 @@ void check_file_actlst(int *ifd, char *dfile, struct activity *act[],
 unsigned int read_new_cpu_nr(int ifd, struct activity *act[])
 {
        unsigned int new_cpu_nr;
-       int j, p;
        
        /* Read new number of CPU following the RESTART record */
        sa_fread(ifd, &new_cpu_nr, sizeof(unsigned int), HARD_SIZE);
@@ -1263,12 +1284,7 @@ unsigned int read_new_cpu_nr(int ifd, struct activity *act[])
        }
        
        /* Set new CPU count and reallocate structures */
-       p = get_activity_position(act, A_CPU);
-       act[p]->nr = new_cpu_nr;
-
-       for (j = 0; j < 3; j++) {
-               SREALLOC(act[p]->buf[j], void, act[p]->msize * act[p]->nr * act[p]->nr2);
-       }
+       allocate_cpu_structures(act, new_cpu_nr);
        
        return new_cpu_nr;
 }
diff --git a/sadf.c b/sadf.c
index 671083acca3f43748d3325688350a68c043c8515..94fe09743bb8085ac31e5d29ed3b6fc5bb5d4f27 100644 (file)
--- a/sadf.c
+++ b/sadf.c
@@ -341,6 +341,7 @@ void xprintf(int nr_tab, const char *fmtf, ...)
  *                     been used or not) can be saved for current record.
  * @loctime            Structure where timestamp (expressed in local time)
  *                     can be saved for current record.
+ * @new_cpu_nr         CPU count associated with restart mark.
  *
  * OUT:
  * @rectime            Structure where timestamp for current record has
@@ -350,7 +351,8 @@ void xprintf(int nr_tab, const char *fmtf, ...)
  ***************************************************************************
  */
 void write_textual_restarts(int curr, int use_tm_start, int use_tm_end, int tab,
-                           struct tm *rectime, struct tm *loctime)
+                           struct tm *rectime, struct tm *loctime,
+                           unsigned int new_cpu_nr)
 {
        char cur_date[32], cur_time[32];
 
@@ -367,7 +369,8 @@ void write_textual_restarts(int curr, int use_tm_start, int use_tm_end, int tab,
        if (*fmt[f_position]->f_restart) {
                (*fmt[f_position]->f_restart)(&tab, F_MAIN, cur_date, cur_time,
                                              !PRINT_LOCAL_TIME(flags) &&
-                                             !PRINT_TRUE_TIME(flags), &file_hdr);
+                                             !PRINT_TRUE_TIME(flags), &file_hdr,
+                                             new_cpu_nr);
        }
 }
 
@@ -784,6 +787,7 @@ void sadf_print_special(int curr, int use_tm_start, int use_tm_end, int rtype, i
 {
        char cur_date[32], cur_time[32];
        int dp = 1;
+       unsigned int new_cpu_nr;
 
        /* Fill timestamp structure (rectime) for current record */
        sadf_get_record_timestamp_struct(curr, rectime, loctime);
@@ -798,13 +802,17 @@ void sadf_print_special(int curr, int use_tm_start, int use_tm_end, int rtype, i
        }
 
        if (rtype == R_RESTART) {
+               /* Don't forget to read new number of CPU */
+               new_cpu_nr = read_new_cpu_nr(ifd, act);
+               
                if (!dp)
                        return;
 
                if (*fmt[f_position]->f_restart) {
                        (*fmt[f_position]->f_restart)(NULL, F_MAIN, cur_date, cur_time,
                                                      !PRINT_LOCAL_TIME(flags) &&
-                                                     !PRINT_TRUE_TIME(flags), &file_hdr);
+                                                     !PRINT_TRUE_TIME(flags), &file_hdr,
+                                                     new_cpu_nr);
                }
        }
        else if (rtype == R_COMMENT) {
@@ -941,6 +949,7 @@ void textual_display_loop(int ifd, struct file_activity *file_actlst, char *dfil
 {
        int curr, tab = 0, rtype;
        int eosaf = TRUE, next, reset = FALSE;
+       unsigned int save_cpu_nr, new_cpu_nr;
        long cnt = 1;
        off_t fpos;
 
@@ -949,6 +958,8 @@ void textual_display_loop(int ifd, struct file_activity *file_actlst, char *dfil
                perror("lseek");
                exit(2);
        }
+       /* Save number of CPU items for current file position */
+       save_cpu_nr = act[get_activity_position(act, A_CPU)]->nr;
 
        /* Print header (eg. XML file header) */
        if (*fmt[f_position]->f_header) {
@@ -970,24 +981,29 @@ void textual_display_loop(int ifd, struct file_activity *file_actlst, char *dfil
                        eosaf = sa_fread(ifd, &record_hdr[0], RECORD_HEADER_SIZE, SOFT_SIZE);
                        rtype = record_hdr[0].record_type;
 
-                       if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
-                               /*
-                                * OK: Previous record was not a special one.
-                                * So read now the extra fields.
-                                */
-                               read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act,
-                                                    file_actlst);
-                               sadf_get_record_timestamp_struct(0, rectime, loctime);
-                       }
-
-                       if (!eosaf && (rtype == R_COMMENT)) {
-                               /*
-                                * Ignore COMMENT record.
-                                * (Unlike RESTART records, COMMENT records have an additional
-                                * comment field).
-                                */
-                               if (lseek(ifd, MAX_COMMENT_LEN, SEEK_CUR) < MAX_COMMENT_LEN) {
-                                       perror("lseek");
+                       if (!eosaf) {
+                               if (rtype == R_COMMENT) {
+                                       /* Ignore COMMENT record */
+                                       if (lseek(ifd, MAX_COMMENT_LEN, SEEK_CUR) < MAX_COMMENT_LEN) {
+                                               perror("lseek");
+                                       }
+                               }
+                               else if (rtype == R_RESTART) {
+                                       /*
+                                        * Ignore RESTART record (don't display it)
+                                        * but anyway we have to reallocate CPU structures
+                                        * according to new CPU count (value saved after RESTART record).
+                                        */
+                                       read_new_cpu_nr(ifd, act);
+                               }
+                               else {
+                                       /*
+                                        * OK: Previous record was not a special one.
+                                        * So read now the extra fields.
+                                        */
+                                       read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act,
+                                                            file_actlst);
+                                       sadf_get_record_timestamp_struct(0, rectime, loctime);
                                }
                        }
                }
@@ -1008,32 +1024,41 @@ void textual_display_loop(int ifd, struct file_activity *file_actlst, char *dfil
                                                 SOFT_SIZE);
                                rtype = record_hdr[curr].record_type;
 
-                               if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
-                                       /* Read the extra fields since it's not a special record */
-                                       read_file_stat_bunch(act, curr, ifd, file_hdr.sa_nr_act,
-                                                            file_actlst);
-
-                                       if (*fmt[f_position]->f_statistics) {
-                                               (*fmt[f_position]->f_statistics)(&tab, F_MAIN);
+                               if (!eosaf) {
+                                       if (rtype == R_COMMENT) {
+                                               /* Ignore COMMENT record */
+                                               if (lseek(ifd, MAX_COMMENT_LEN, SEEK_CUR) < MAX_COMMENT_LEN) {
+                                                       perror("lseek");
+                                               }
                                        }
+                                       else if (rtype == R_RESTART) {
+                                               /*
+                                                * Ignore RESTART record (don't display it)
+                                                * but anyway we have to reallocate CPU structures
+                                                * according to new CPU count (value saved after RESTART record.
+                                                */
+                                               read_new_cpu_nr(ifd, act);
+                                       }
+                                       else {
+                                               /* This is not a special record, so read the extra fields */
+                                               read_file_stat_bunch(act, curr, ifd, file_hdr.sa_nr_act,
+                                                                    file_actlst);
 
-                                       /* next is set to 1 when we were close enough to desired interval */
-                                       next = write_textual_stats(curr, tm_start.use, tm_end.use, reset,
-                                                                  &cnt, tab, cpu_nr, rectime, loctime);
-
-                                       if (next) {
-                                               curr ^= 1;
-                                               if (cnt > 0) {
-                                                       cnt--;
+                                               if (*fmt[f_position]->f_statistics) {
+                                                       (*fmt[f_position]->f_statistics)(&tab, F_MAIN);
                                                }
-                                       }
-                                       reset = FALSE;
-                               }
 
-                               if (!eosaf && (rtype == R_COMMENT)) {
-                                       /* Ignore COMMENT record */
-                                       if (lseek(ifd, MAX_COMMENT_LEN, SEEK_CUR) < MAX_COMMENT_LEN) {
-                                               perror("lseek");
+                                               /* next is set to 1 when we were close enough to desired interval */
+                                               next = write_textual_stats(curr, tm_start.use, tm_end.use, reset,
+                                                                          &cnt, tab, cpu_nr, rectime, loctime);
+
+                                               if (next) {
+                                                       curr ^= 1;
+                                                       if (cnt > 0) {
+                                                               cnt--;
+                                                       }
+                                               }
+                                               reset = FALSE;
                                        }
                                }
                        }
@@ -1045,14 +1070,25 @@ void textual_display_loop(int ifd, struct file_activity *file_actlst, char *dfil
                                        eosaf = sa_fread(ifd, &record_hdr[curr], RECORD_HEADER_SIZE,
                                                         SOFT_SIZE);
                                        rtype = record_hdr[curr].record_type;
-                                       if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
-                                               read_file_stat_bunch(act, curr, ifd, file_hdr.sa_nr_act,
-                                                                    file_actlst);
-                                       }
-                                       else if (!eosaf && (rtype == R_COMMENT)) {
-                                               /* Ignore COMMENT record */
-                                               if (lseek(ifd, MAX_COMMENT_LEN, SEEK_CUR) < MAX_COMMENT_LEN) {
-                                                       perror("lseek");
+                                       if (!eosaf) {
+                                               if (rtype == R_COMMENT) {
+                                                       /* Ignore COMMENT record */
+                                                       if (lseek(ifd, MAX_COMMENT_LEN, SEEK_CUR) < MAX_COMMENT_LEN) {
+                                                               perror("lseek");
+                                                       }
+                                               }
+                                               else if (rtype == R_RESTART) {
+                                                       /*
+                                                        * Ignore RESTART record (don't display it)
+                                                        * but anyway we have to reallocate CPU structures
+                                                        * according to new CPU count (value saved after RESTART record.
+                                                        */
+                                                       read_new_cpu_nr(ifd, act);
+                                               }
+                                               else {
+                                                       /* This is not a special record: Read the extra fields */
+                                                       read_file_stat_bunch(act, curr, ifd, file_hdr.sa_nr_act,
+                                                                            file_actlst);
                                                }
                                        }
                                }
@@ -1067,16 +1103,18 @@ void textual_display_loop(int ifd, struct file_activity *file_actlst, char *dfil
                (*fmt[f_position]->f_statistics)(&tab, F_END);
        }
 
-       /* Rewind file */
+       /* Rewind file... */
        if (lseek(ifd, fpos, SEEK_SET) < fpos) {
                perror("lseek");
                exit(2);
        }
+       /* ... and restore number of CPU items for this position in file */
+       allocate_cpu_structures(act, save_cpu_nr);
 
        /* Process now RESTART entries to display restart messages */
        if (*fmt[f_position]->f_restart) {
                (*fmt[f_position]->f_restart)(&tab, F_BEGIN, NULL, NULL, FALSE,
-                                             &file_hdr);
+                                             &file_hdr, 0);
        }
 
        do {
@@ -1084,13 +1122,13 @@ void textual_display_loop(int ifd, struct file_activity *file_actlst, char *dfil
                                      SOFT_SIZE)) == 0) {
 
                        rtype = record_hdr[0].record_type;
-                       if ((rtype != R_RESTART) && (rtype != R_COMMENT)) {
-                               read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act,
-                                                    file_actlst);
-                       }
                        if (rtype == R_RESTART) {
+                               /* Read new CPU count */
+                               new_cpu_nr = read_new_cpu_nr(ifd, act);
+                               
+                               /* Display RESTART records */
                                write_textual_restarts(0, tm_start.use, tm_end.use, tab,
-                                                      rectime, loctime);
+                                                      rectime, loctime, new_cpu_nr);
                        }
                        else if (rtype == R_COMMENT) {
                                /* Ignore COMMENT record */
@@ -1098,19 +1136,26 @@ void textual_display_loop(int ifd, struct file_activity *file_actlst, char *dfil
                                        perror("lseek");
                                }
                        }
+                       else {
+                               /* Not a special record: Read the extra fields */
+                               read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act,
+                                                    file_actlst);
+                       }
                }
        }
        while (!eosaf);
 
        if (*fmt[f_position]->f_restart) {
-               (*fmt[f_position]->f_restart)(&tab, F_END, NULL, NULL, FALSE, &file_hdr);
+               (*fmt[f_position]->f_restart)(&tab, F_END, NULL, NULL, FALSE, &file_hdr, 0);
        }
 
-       /* Rewind file */
+       /* Rewind file... */
        if (lseek(ifd, fpos, SEEK_SET) < fpos) {
                perror("lseek");
                exit(2);
        }
+       /* ... and restore number of CPU items for this position in file */
+       allocate_cpu_structures(act, save_cpu_nr);
 
        /* Last, process COMMENT entries to display comments */
        if (DISPLAY_COMMENT(flags)) {
@@ -1123,14 +1168,24 @@ void textual_display_loop(int ifd, struct file_activity *file_actlst, char *dfil
                                              SOFT_SIZE)) == 0) {
 
                                rtype = record_hdr[0].record_type;
-                               if ((rtype != R_RESTART) && (rtype != R_COMMENT)) {
-                                       read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act,
-                                                            file_actlst);
-                               }
                                if (rtype == R_COMMENT) {
+                                       /* Display R_COMMENT records */
                                        write_textual_comments(0, tm_start.use, tm_end.use,
                                                               tab, ifd, rectime, loctime);
                                }
+                               else if (rtype == R_RESTART) {
+                                       /*
+                                        * Ignore RESTART record (don't display it)
+                                        * but anyway we have to reallocate CPU structures
+                                        * according to new CPU count (value saved after RESTART record.
+                                        */
+                                       read_new_cpu_nr(ifd, act);
+                               }
+                               else {
+                                       /* Not a special record: Read the extra fields */
+                                       read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act,
+                                                            file_actlst);
+                               }
                        }
                }
                while (!eosaf);
@@ -1269,14 +1324,17 @@ void main_display_loop(int ifd, struct file_activity *file_actlst, __nr_t cpu_nr
                                eosaf = sa_fread(ifd, &record_hdr[curr], RECORD_HEADER_SIZE,
                                                 SOFT_SIZE);
                                rtype = record_hdr[curr].record_type;
-                               if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) {
-                                       read_file_stat_bunch(act, curr, ifd, file_hdr.sa_nr_act,
-                                                            file_actlst);
-                               }
-                               else if (!eosaf && (rtype == R_COMMENT)) {
-                                       /* This was a COMMENT record: print it */
-                                       sadf_print_special(curr, tm_start.use, tm_end.use,
-                                                          R_COMMENT, ifd, rectime, loctime);
+                               if (!eosaf) {
+                                       if (rtype == R_COMMENT) {
+                                               /* This was a COMMENT record: print it */
+                                               sadf_print_special(curr, tm_start.use, tm_end.use,
+                                                                  R_COMMENT, ifd, rectime, loctime);
+                                       }
+                                       else if (rtype != R_RESTART) {
+                                               /* This is not a RESTART or a COMMENT record */
+                                               read_file_stat_bunch(act, curr, ifd, file_hdr.sa_nr_act,
+                                                                    file_actlst);
+                                       }
                                }
                        }
                        while (!eosaf && (rtype != R_RESTART));
diff --git a/sadf.h b/sadf.h
index 4ba646bec173c3b77569b1a6da31e39d5e0f4ac9..45424df8f713f9b1cdb943bdc93546c461b93c0a 100644 (file)
--- a/sadf.h
+++ b/sadf.h
@@ -163,7 +163,8 @@ struct report_format {
        /*
         * This function displays the restart messages.
         */
-       __printf_funct_t (*f_restart) (int *, int, char *, char *, int, struct file_header *);
+       __printf_funct_t (*f_restart) (int *, int, char *, char *, int, struct file_header *,
+                                      unsigned int);
        /*
         * This function displays the comments.
         */
@@ -185,13 +186,13 @@ extern void
  * Prototypes used to display restart messages
  */
 __printf_funct_t
-       print_db_restart(int *, int, char *, char *, int, struct file_header *);
+       print_db_restart(int *, int, char *, char *, int, struct file_header *, unsigned int);
 __printf_funct_t
-       print_ppc_restart(int *, int, char *, char *, int, struct file_header *);
+       print_ppc_restart(int *, int, char *, char *, int, struct file_header *, unsigned int);
 __printf_funct_t
-       print_xml_restart(int *, int, char *, char *, int, struct file_header *);
+       print_xml_restart(int *, int, char *, char *, int, struct file_header *, unsigned int);
 __printf_funct_t
-       print_json_restart(int *, int, char *, char *, int, struct file_header *);
+       print_json_restart(int *, int, char *, char *, int, struct file_header *, unsigned int);
 
 /*
  * Prototypes used to display comments
index 70e5cd6b98d532dfd00149c1468405423b470aeb..c0446b356a059413926b621d8c971a44e3efc69f 100644 (file)
@@ -45,10 +45,11 @@ extern unsigned int flags;
  * @utc                True if @cur_time is expressed in UTC.
  * @sep                Character used as separator.
  * @file_hdr   System activity file standard header.
+ * @cpu_nr     CPU count associated with restart mark.
  ***************************************************************************
  */
 void print_dbppc_restart(char *cur_date, char *cur_time, int utc, char sep,
-                        struct file_header *file_hdr)
+                        struct file_header *file_hdr, unsigned int cpu_nr)
 {
        printf("%s%c-1%c", file_hdr->sa_nodename, sep, sep);
        if (strlen(cur_date)) {
@@ -58,7 +59,8 @@ void print_dbppc_restart(char *cur_date, char *cur_time, int utc, char sep,
        if (strlen(cur_date) && utc) {
                printf(" UTC");
        }
-       printf("%cLINUX-RESTART\n", sep);
+       printf("%cLINUX-RESTART\t(%d CPU)\n",
+              sep, cpu_nr > 1 ? cpu_nr - 1 : 1);
 }
 
 /*
@@ -72,14 +74,16 @@ void print_dbppc_restart(char *cur_date, char *cur_time, int utc, char sep,
  * @cur_time   Time string of current restart message.
  * @utc                True if @cur_time is expressed in UTC.
  * @file_hdr   System activity file standard header.
+ * @cpu_nr     CPU count associated with restart mark.
  ***************************************************************************
  */
 __printf_funct_t print_db_restart(int *tab, int action, char *cur_date,
-                                 char *cur_time, int utc, struct file_header *file_hdr)
+                                 char *cur_time, int utc, struct file_header *file_hdr,
+                                 unsigned int cpu_nr)
 {
        /* Actions F_BEGIN and F_END ignored */
        if (action == F_MAIN) {
-               print_dbppc_restart(cur_date, cur_time, utc, ';', file_hdr);
+               print_dbppc_restart(cur_date, cur_time, utc, ';', file_hdr, cpu_nr);
        }
 }
 
@@ -94,14 +98,16 @@ __printf_funct_t print_db_restart(int *tab, int action, char *cur_date,
  * @cur_time   Time string of current restart message.
  * @utc                True if @cur_time is expressed in UTC.
  * @file_hdr   System activity file standard header.
+ * @cpu_nr     CPU count associated with restart mark.
  ***************************************************************************
  */
 __printf_funct_t print_ppc_restart(int *tab, int action, char *cur_date,
-                                  char *cur_time, int utc, struct file_header *file_hdr)
+                                  char *cur_time, int utc, struct file_header *file_hdr,
+                                  unsigned int cpu_nr)
 {
        /* Actions F_BEGIN and F_END ignored */
        if (action == F_MAIN) {
-               print_dbppc_restart(cur_date, cur_time, utc, '\t', file_hdr);
+               print_dbppc_restart(cur_date, cur_time, utc, '\t', file_hdr, cpu_nr);
        }
 }
 
@@ -116,20 +122,22 @@ __printf_funct_t print_ppc_restart(int *tab, int action, char *cur_date,
  * @cur_time   Time string of current restart message.
  * @utc                True if @cur_time is expressed in UTC.
  * @file_hdr   System activity file standard header (unused here).
+ * @cpu_nr     CPU count associated with restart mark.
  *
  * OUT:
  * @tab                Number of tabulations.
  ***************************************************************************
  */
 __printf_funct_t print_xml_restart(int *tab, int action, char *cur_date,
-                                  char *cur_time, int utc, struct file_header *file_hdr)
+                                  char *cur_time, int utc, struct file_header *file_hdr,
+                                  unsigned int cpu_nr)
 {
        if (action & F_BEGIN) {
                xprintf((*tab)++, "<restarts>");
        }
        if (action & F_MAIN) {
-               xprintf(*tab, "<boot date=\"%s\" time=\"%s\" utc=\"%d\"/>",
-                       cur_date, cur_time, utc ? 1 : 0);
+               xprintf(*tab, "<boot date=\"%s\" time=\"%s\" utc=\"%d\" cpu_count=\"%d\"/>",
+                       cur_date, cur_time, utc ? 1 : 0, cpu_nr > 1 ? cpu_nr - 1 : 1);
        }
        if (action & F_END) {
                xprintf(--(*tab), "</restarts>");
@@ -147,13 +155,15 @@ __printf_funct_t print_xml_restart(int *tab, int action, char *cur_date,
  * @cur_time   Time string of current restart message.
  * @utc                True if @cur_time is expressed in UTC.
  * @file_hdr   System activity file standard header (unused here).
+ * @cpu_nr     CPU count associated with restart mark.
  *
  * OUT:
  * @tab                Number of tabulations.
  ***************************************************************************
  */
 __printf_funct_t print_json_restart(int *tab, int action, char *cur_date,
-                                   char *cur_time, int utc, struct file_header *file_hdr)
+                                   char *cur_time, int utc, struct file_header *file_hdr,
+                                   unsigned int cpu_nr)
 {
        static int sep = FALSE;
        
@@ -166,8 +176,8 @@ __printf_funct_t print_json_restart(int *tab, int action, char *cur_date,
                        printf(",\n");
                }
                xprintf((*tab)++, "{");
-               xprintf(*tab, "\"boot\": {\"date\": \"%s\", \"time\": \"%s\", \"utc\": %d}",
-                       cur_date, cur_time, utc ? 1 : 0);
+               xprintf(*tab, "\"boot\": {\"date\": \"%s\", \"time\": \"%s\", \"utc\": %d, \"cpu_count\": %d}",
+                       cur_date, cur_time, utc ? 1 : 0, cpu_nr > 1 ? cpu_nr - 1 : 1);
                xprintf0(--(*tab), "}");
                sep = TRUE;
        }