]> granicus.if.org Git - sysstat/commitdiff
mpstat: Compute stats for node "all" as the sum of individual CPU
authorSebastien GODARD <sysstat@users.noreply.github.com>
Fri, 23 Mar 2018 11:14:49 +0000 (12:14 +0100)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Fri, 23 Mar 2018 11:14:49 +0000 (12:14 +0100)
Don't use global CPU stats from /proc/stat file for node "all".
Compute stats for node "all" as the sum of individual ones.
Also better handle CPUs that go offline or back online.

Signed-off-by: Sebastien GODARD <sysstat@users.noreply.github.com>
mpstat.c

index 43f8beae02a605197b11e656205781f5c136056b..41dde2c4db9f76383bfa6d922abd774355550f91 100644 (file)
--- a/mpstat.c
+++ b/mpstat.c
@@ -48,7 +48,6 @@
 char *sccsid(void) { return (SCCSID); }
 #endif
 
-unsigned long long tot_jiffies[3] = {0, 0, 0};
 unsigned long long uptime_cs[3] = {0, 0, 0};
 
 /* NOTE: Use array of _char_ for bitmaps to avoid endianness problems...*/
@@ -74,7 +73,9 @@ struct stats_irqcpu *st_softirqcpu[3];
 
 /*
  * Number of CPU per node, e.g.:
- * cpu_per_node[0]: nr of CPU for node 0..
+ * cpu_per_node[0]: total nr of CPU (this is node "all")
+ * cpu_per_node[1]: nr of CPU for node 0
+ * etc.
  */
 int *cpu_per_node;
 
@@ -104,6 +105,7 @@ int cpu_nr = 0;
  * Highest NUMA node number found on the machine.
  * A value of 0 means node 0 (one node).
  * A value of -1 means no nodes found.
+ * We have: node_nr < cpu_nr (see get_node_placement() function).
  */
 int node_nr = -1;
 
@@ -285,10 +287,13 @@ int get_node_placement(int cpu_nr, int cpu_per_node[], int cpu2node[])
        int cpu, node, node_nr = -1;
 
        /* Init number of CPU per node */
-       memset(cpu_per_node, 0, sizeof(int) * cpu_nr);
+       memset(cpu_per_node, 0, sizeof(int) * (cpu_nr + 1));
        /* CPU belongs to no node by default */
        memset(cpu2node, -1, sizeof(int) * cpu_nr);
 
+       /* This is node "all" */
+       cpu_per_node[0] = cpu_nr;
+
        for (cpu = 0; cpu < cpu_nr; cpu++) {
                snprintf(line, MAX_PF_NAME, "%s/cpu%d", SYSFS_DEVCPU, cpu);
                line[MAX_PF_NAME - 1] = '\0';
@@ -307,7 +312,7 @@ int get_node_placement(int cpu_nr, int cpu_per_node[], int cpu2node[])
                                        closedir(dir);
                                        return -1;
                                }
-                               cpu_per_node[node]++;
+                               cpu_per_node[node + 1]++;
                                cpu2node[cpu] = node;
                                if (node > node_nr) {
                                        node_nr = node;
@@ -329,32 +334,77 @@ int get_node_placement(int cpu_nr, int cpu_per_node[], int cpu2node[])
  * Compute node statistics: Split CPU statistics among nodes.
  *
  * IN:
- * @st_cpu     Array where current CPU stats have been read.
+ * @src                Structure containing CPU stats to add.
+ *
+ * OUT:
+ * @dest       Structure containing global CPU stats.
+ ***************************************************************************
+ */
+void add_cpu_stats(struct stats_cpu *dest, struct stats_cpu *src)
+{
+       dest->cpu_user       += src->cpu_user;
+       dest->cpu_nice       += src->cpu_nice;
+       dest->cpu_sys        += src->cpu_sys;
+       dest->cpu_idle       += src->cpu_idle;
+       dest->cpu_iowait     += src->cpu_iowait;
+       dest->cpu_hardirq    += src->cpu_hardirq;
+       dest->cpu_softirq    += src->cpu_softirq;
+       dest->cpu_steal      += src->cpu_steal;
+       dest->cpu_guest      += src->cpu_guest;
+       dest->cpu_guest_nice += src->cpu_guest_nice;
+}
+
+/*
+ ***************************************************************************
+ * Compute node statistics: Split CPU statistics among nodes.
+ *
+ * IN:
+ * @prev       Index in array where stats used as reference are.
+ * @curr       Index in array for current sample statistics.
  *
  * OUT:
  * @st_node    Array where CPU stats for each node have been saved.
  ***************************************************************************
  */
-void set_node_cpu_stats(struct stats_cpu *st_node, struct stats_cpu *st_cpu)
+void set_node_cpu_stats(int prev, int curr)
 {
        int cpu;
-       struct stats_cpu *st_cpu_i, *st_node_i;
+       unsigned long long tot_jiffies_p;
+       struct stats_cpu *scp, *scc, *snp, *snc;
+       struct stats_cpu *scc_all = st_cpu[curr];
+       struct stats_cpu *scp_all = st_cpu[prev];
+       struct stats_cpu *snc_all = st_node[curr];
+       struct stats_cpu *snp_all = st_node[prev];
+
+       /* Reset structures */
+       memset(st_node[prev], 0, STATS_CPU_SIZE * (cpu_nr + 1));
+       memset(st_node[curr], 0, STATS_CPU_SIZE * (cpu_nr + 1));
+
+       /* Node 'all' is the same as CPU 'all' */
+       *snp_all = *scp_all;
+       *snc_all = *scc_all;
 
+       /* Individual nodes */
        for (cpu = 0; cpu < cpu_nr; cpu++) {
-               /* Don't store stats for node 'all'. They are the same as CPU 'all' */
-               st_cpu_i = st_cpu + cpu + 1;
-               st_node_i = st_node + cpu2node[cpu] + 1;
-
-               st_node_i->cpu_user += st_cpu_i->cpu_user;
-               st_node_i->cpu_nice += st_cpu_i->cpu_nice;
-               st_node_i->cpu_sys += st_cpu_i->cpu_sys;
-               st_node_i->cpu_idle += st_cpu_i->cpu_idle;
-               st_node_i->cpu_iowait += st_cpu_i->cpu_iowait;
-               st_node_i->cpu_hardirq += st_cpu_i->cpu_hardirq;
-               st_node_i->cpu_softirq += st_cpu_i->cpu_softirq;
-               st_node_i->cpu_steal += st_cpu_i->cpu_steal;
-               st_node_i->cpu_guest += st_cpu_i->cpu_guest;
-               st_node_i->cpu_guest_nice += st_cpu_i->cpu_guest_nice;
+               scc = st_cpu[curr] + cpu + 1;
+               scp = st_cpu[prev] + cpu + 1;
+               snp = st_node[prev] + cpu2node[cpu] + 1;
+               snc = st_node[curr] + cpu2node[cpu] + 1;
+
+
+               tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
+                               scp->cpu_sys + scp->cpu_idle +
+                               scp->cpu_iowait + scp->cpu_hardirq +
+                               scp->cpu_steal + scp->cpu_softirq;
+               if ((tot_jiffies_p == 0) && (interval != 0))
+                       /*
+                        * CPU has just come back online with no ref from
+                        * previous iteration: Skip it.
+                        */
+                       continue;
+
+               add_cpu_stats(snp, scp);
+               add_cpu_stats(snc, scc);
        }
 }
 
@@ -397,6 +447,10 @@ unsigned long long get_global_cpu_mpstats(int prev, int curr,
                memset(scc_all, 0, sizeof(struct stats_cpu));
                memset(scp_all, 0, sizeof(struct stats_cpu));
        }
+       else {
+               /* This is a UP machine */
+               return get_per_cpu_interval(st_cpu[curr], st_cpu[prev]);
+       }
 
        for (i = 1; i <= cpu_nr; i++) {
 
@@ -451,7 +505,8 @@ unsigned long long get_global_cpu_mpstats(int prev, int curr,
                         * already offline when the first sample has been taken.
                         * So don't display that CPU to prevent "jump-from-zero"
                         * output syndrome, and don't take it into account for CPU "all".
-                        * NB: Test for interval != 0 to make sure we don't stats since boot time.
+                        * NB: Test for interval != 0 to make sure we don't want stats
+                        * since boot time.
                         */
                        offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
                        continue;
@@ -463,35 +518,8 @@ unsigned long long get_global_cpu_mpstats(int prev, int curr,
                 */
                deltot_jiffies += get_per_cpu_interval(scc, scp);
 
-               scc_all->cpu_user += scc->cpu_user;
-               scp_all->cpu_user += scp->cpu_user;
-
-               scc_all->cpu_nice += scc->cpu_nice;
-               scp_all->cpu_nice += scp->cpu_nice;
-
-               scc_all->cpu_sys += scc->cpu_sys;
-               scp_all->cpu_sys += scp->cpu_sys;
-
-               scc_all->cpu_idle += scc->cpu_idle;
-               scp_all->cpu_idle += scp->cpu_idle;
-
-               scc_all->cpu_iowait += scc->cpu_iowait;
-               scp_all->cpu_iowait += scp->cpu_iowait;
-
-               scc_all->cpu_hardirq += scc->cpu_hardirq;
-               scp_all->cpu_hardirq += scp->cpu_hardirq;
-
-               scc_all->cpu_steal += scc->cpu_steal;
-               scp_all->cpu_steal += scp->cpu_steal;
-
-               scc_all->cpu_softirq += scc->cpu_softirq;
-               scp_all->cpu_softirq += scp->cpu_softirq;
-
-               scc_all->cpu_guest += scc->cpu_guest;
-               scp_all->cpu_guest += scp->cpu_guest;
-
-               scc_all->cpu_guest_nice += scc->cpu_guest_nice;
-               scp_all->cpu_guest_nice += scp->cpu_guest_nice;
+               add_cpu_stats(scc_all, scc);
+               add_cpu_stats(scp_all, scp);
        }
 
        return deltot_jiffies;
@@ -503,6 +531,8 @@ unsigned long long get_global_cpu_mpstats(int prev, int curr,
  *
  * IN:
  * @dis                TRUE if a header line must be printed.
+ * @deltot_jiffies
+ *             Number of jiffies spent on the interval by all processors.
  * @prev       Position in array where statistics used as reference are.
  *             Stats used as reference may be the previous ones read, or
  *             the very first ones when calculating the average.
@@ -513,15 +543,15 @@ unsigned long long get_global_cpu_mpstats(int prev, int curr,
  * @curr_string        String displayed at the beginning of current sample stats.
  *             This is the timestamp of the current sample, or "Average"
  *             when displaying average stats.
+ * @offline_cpu_bitmap
+ *             CPU bitmap for offline CPU.
  ***************************************************************************
  */
-void write_plain_cpu_stats(int dis, int prev, int curr,
-                          char *prev_string, char *curr_string)
+void write_plain_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
+                          char *prev_string, char *curr_string, unsigned char offline_cpu_bitmap[])
 {
        int i;
        struct stats_cpu *scc, *scp;
-       unsigned long long deltot_jiffies = 1;
-       unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
 
        if (dis) {
                printf("\n%-11s  CPU    %%usr   %%nice    %%sys %%iowait    %%irq   "
@@ -529,14 +559,6 @@ void write_plain_cpu_stats(int dis, int prev, int curr,
                       prev_string);
        }
 
-       /*
-        * Compute CPU "all" as sum of all individual CPU (on SMP machines)
-        * and look for offline CPU.
-        */
-       if (cpu_nr > 1) {
-               deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
-       }
-
        /*
         * Now display CPU statistics (including CPU "all"),
         * except for offline CPU or CPU that the user doesn't want to see.
@@ -556,14 +578,6 @@ void write_plain_cpu_stats(int dis, int prev, int curr,
                if (i == 0) {
                        /* This is CPU "all" */
                        cprintf_in(IS_STR, " %s", " all", 0);
-
-                       if (cpu_nr == 1) {
-                               /*
-                                * This is a UP machine. In this case
-                                * interval has still not been calculated.
-                                */
-                               deltot_jiffies = get_per_cpu_interval(scc, scp);
-                       }
                }
                else {
                        cprintf_in(IS_INT, " %4d", "", i - 1);
@@ -621,29 +635,24 @@ void write_plain_cpu_stats(int dis, int prev, int curr,
  *
  * IN:
  * @tab                Number of tabs to print.
+ * @deltot_jiffies
+ *             Number of jiffies spent on the interval by all processors.
  * @prev       Position in array where statistics used as reference are.
  *             Stats used as reference may be the previous ones read, or
  *             the very first ones when calculating the average.
  * @curr       Position in array where current statistics will be saved.
+ * @offline_cpu_bitmap
+ *             CPU bitmap for offline CPU.
  ***************************************************************************
  */
-void write_json_cpu_stats(int tab, int prev, int curr)
+void write_json_cpu_stats(int tab, unsigned long long deltot_jiffies, int prev, int curr,
+                         unsigned char offline_cpu_bitmap[])
 {
        int i, next = FALSE;
        struct stats_cpu *scc, *scp;
-       unsigned long long deltot_jiffies = 1;
-       unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
 
        xprintf(tab++, "\"cpu-load\": [");
 
-       /*
-        * Compute CPU "all" as sum of all individual CPU (on SMP machines)
-        * and look for offline CPU.
-        */
-       if (cpu_nr > 1) {
-               deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
-       }
-
        /*
         * Now display CPU statistics (including CPU "all"),
         * except for offline CPU or CPU that the user doesn't want to see.
@@ -663,17 +672,7 @@ void write_json_cpu_stats(int tab, int prev, int curr)
                }
                next = TRUE;
 
-               if (i == 0) {
-
-                       if (cpu_nr == 1) {
-                               /*
-                                * This is a UP machine. In this case
-                                * interval has still not been calculated.
-                                */
-                               deltot_jiffies = get_per_cpu_interval(scc, scp);
-                       }
-               }
-               else {
+               if (i != 0) {
                        /* Recalculate itv for current proc */
                        deltot_jiffies = get_per_cpu_interval(scc, scp);
 
@@ -733,6 +732,8 @@ void write_json_cpu_stats(int tab, int prev, int curr)
  *
  * IN:
  * @dis                TRUE if a header line must be printed.
+ * @deltot_jiffies
+ *             Number of jiffies spent on the interval by all processors.
  * @prev       Position in array where statistics used as reference are.
  *             Stats used as reference may be the previous ones read, or
  *             the very first ones when calculating the average.
@@ -746,20 +747,25 @@ void write_json_cpu_stats(int tab, int prev, int curr)
  * @tab                Number of tabs to print (JSON format only).
  * @next       TRUE is a previous activity has been displayed (JSON format
  *             only).
+ * @offline_cpu_bitmap
+ *             CPU bitmap for offline CPU.
  ***************************************************************************
  */
-void write_cpu_stats(int dis, int prev, int curr, char *prev_string,
-                    char *curr_string, int tab, int *next)
+void write_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
+                    char *prev_string, char *curr_string, int tab, int *next,
+                    unsigned char offline_cpu_bitmap[])
 {
        if (DISPLAY_JSON_OUTPUT(flags)) {
                if (*next) {
                        printf(",\n");
                }
                *next = TRUE;
-               write_json_cpu_stats(tab, prev, curr);
+               write_json_cpu_stats(tab, deltot_jiffies, prev, curr,
+                                    offline_cpu_bitmap);
        }
        else {
-               write_plain_cpu_stats(dis, prev, curr, prev_string, curr_string);
+               write_plain_cpu_stats(dis, deltot_jiffies, prev, curr,
+                                     prev_string, curr_string, offline_cpu_bitmap);
        }
 }
 
@@ -771,7 +777,6 @@ void write_cpu_stats(int dis, int prev, int curr, char *prev_string,
  * @dis                TRUE if a header line must be printed.
  * @deltot_jiffies
  *             Number of jiffies spent on the interval by all processors.
- * @itv                Interval value in 1/100th of a second.
  * @prev       Position in array where statistics used as reference are.
  *             Stats used as reference may be the previous ones read, or
  *             the very first ones when calculating the average.
@@ -784,11 +789,11 @@ void write_cpu_stats(int dis, int prev, int curr, char *prev_string,
  *             when displaying average stats.
  ***************************************************************************
  */
-void write_plain_node_stats(int dis, unsigned long long deltot_jiffies, unsigned long long itv,
+void write_plain_node_stats(int dis, unsigned long long deltot_jiffies,
                            int prev, int curr, char *prev_string, char *curr_string)
 {
-       struct stats_cpu *snc, *snp;
-       int node;
+       struct stats_cpu *snc, *snp, *scc, *scp;
+       int cpu, node;
 
        if (dis) {
                printf("\n%-11s NODE    %%usr   %%nice    %%sys %%iowait    %%irq   "
@@ -796,64 +801,13 @@ void write_plain_node_stats(int dis, unsigned long long deltot_jiffies, unsigned
                       prev_string);
        }
 
-       /*
-        * Check if we want global stats among all nodes.
-        * Stats are the same as global CPU stats among all processors.
-        */
-       if (*node_bitmap & 1) {
+       for (node = 0; node <= node_nr + 1; node++) {
 
-               printf("%-11s", curr_string);
-               cprintf_in(IS_STR, " %s", " all", 0);
-
-               cprintf_pc(NO_UNIT, 10, 7, 2,
-                          (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
-                          (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
-                          0.0 :
-                          ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
-                                      st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
-                                      deltot_jiffies),
-                          (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
-                          (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
-                          0.0 :
-                          ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
-                                      st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
-                                      deltot_jiffies),
-                          ll_sp_value(st_cpu[prev]->cpu_sys,
-                                      st_cpu[curr]->cpu_sys,
-                                      deltot_jiffies),
-                          ll_sp_value(st_cpu[prev]->cpu_iowait,
-                                      st_cpu[curr]->cpu_iowait,
-                                      deltot_jiffies),
-                          ll_sp_value(st_cpu[prev]->cpu_hardirq,
-                                      st_cpu[curr]->cpu_hardirq,
-                                      deltot_jiffies),
-                          ll_sp_value(st_cpu[prev]->cpu_softirq,
-                                      st_cpu[curr]->cpu_softirq,
-                                      deltot_jiffies),
-                          ll_sp_value(st_cpu[prev]->cpu_steal,
-                                      st_cpu[curr]->cpu_steal,
-                                      deltot_jiffies),
-                          ll_sp_value(st_cpu[prev]->cpu_guest,
-                                      st_cpu[curr]->cpu_guest,
-                                      deltot_jiffies),
-                          ll_sp_value(st_cpu[prev]->cpu_guest_nice,
-                                      st_cpu[curr]->cpu_guest_nice,
-                                      deltot_jiffies),
-                          (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
-                          0.0 :
-                          ll_sp_value(st_cpu[prev]->cpu_idle,
-                                      st_cpu[curr]->cpu_idle,
-                                      deltot_jiffies));
-               printf("\n");
-       }
-
-       for (node = 0; node <= node_nr; node++) {
-
-               snc = st_node[curr] + node + 1;
-               snp = st_node[prev] + node + 1;
+               snc = st_node[curr] + node;
+               snp = st_node[prev] + node;
 
                /* Check if we want stats about this node */
-               if (!(*(node_bitmap + ((node + 1) >> 3)) & (1 << ((node + 1) & 0x07))))
+               if (!(*(node_bitmap + (node >> 3)) & (1 << (node & 0x07))))
                        continue;
 
                if (!cpu_per_node[node])
@@ -861,45 +815,66 @@ void write_plain_node_stats(int dis, unsigned long long deltot_jiffies, unsigned
                        continue;
 
                printf("%-11s", curr_string);
-               cprintf_in(IS_INT, " %4d", "", node);
+               if (node == 0) {
+                       /* This is node "all", i.e. CPU "all" */
+                       cprintf_in(IS_STR, " %s", " all", 0);
+               }
+               else {
+                       cprintf_in(IS_INT, " %4d", "", node - 1);
+
+                       /* Recalculate interval for current node */
+                       deltot_jiffies = 0;
+                       for (cpu = 1; cpu <= cpu_nr; cpu++) {
+                               scc = st_cpu[curr] + cpu;
+                               scp = st_cpu[prev] + cpu;
+
+                               if ((scp->cpu_user + scp->cpu_nice + scp->cpu_sys +
+                                    scp->cpu_idle + scp->cpu_iowait + scp->cpu_hardirq +
+                                    scp->cpu_steal + scp->cpu_softirq == 0) && (interval != 0))
+                                       continue;
+
+                               if (cpu2node[cpu - 1] == node - 1) {
+                                       deltot_jiffies += get_per_cpu_interval(scc, scp);
+                               }
+                       }
+
+                       if (!deltot_jiffies) {
+                               /* All CPU in node are tickless and/or offline */
+                               cprintf_pc(NO_UNIT, 10, 7, 2,
+                                          0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 100.0);
+                               printf("\n");
+
+                               continue;
+                       }
+               }
 
                cprintf_pc(NO_UNIT, 10, 7, 2,
                           (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
                           0.0 :
                           ll_sp_value(snp->cpu_user - snp->cpu_guest,
-                                      snc->cpu_user - snc->cpu_guest,
-                                      itv * HZ / 100 * cpu_per_node[node]),
+                                      snc->cpu_user - snc->cpu_guest, deltot_jiffies),
                           (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
                           0.0 :
                           ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
-                                      snc->cpu_nice - snc->cpu_guest_nice,
-                                      itv * HZ / 100 * cpu_per_node[node]),
+                                      snc->cpu_nice - snc->cpu_guest_nice, deltot_jiffies),
                           ll_sp_value(snp->cpu_sys,
-                                      snc->cpu_sys,
-                                      itv * HZ / 100 * cpu_per_node[node]),
+                                      snc->cpu_sys, deltot_jiffies),
                           ll_sp_value(snp->cpu_iowait,
-                                      snc->cpu_iowait,
-                                      itv * HZ / 100 * cpu_per_node[node]),
+                                      snc->cpu_iowait, deltot_jiffies),
                           ll_sp_value(snp->cpu_hardirq,
-                                      snc->cpu_hardirq,
-                                      itv * HZ / 100 * cpu_per_node[node]),
+                                      snc->cpu_hardirq, deltot_jiffies),
                           ll_sp_value(snp->cpu_softirq,
-                                      snc->cpu_softirq,
-                                      itv * HZ / 100 * cpu_per_node[node]),
+                                      snc->cpu_softirq, deltot_jiffies),
                           ll_sp_value(snp->cpu_steal,
-                                      snc->cpu_steal,
-                                      itv * HZ / 100 * cpu_per_node[node]),
+                                      snc->cpu_steal, deltot_jiffies),
                           ll_sp_value(snp->cpu_guest,
-                                      snc->cpu_guest,
-                                      itv * HZ / 100 * cpu_per_node[node]),
+                                      snc->cpu_guest, deltot_jiffies),
                           ll_sp_value(snp->cpu_guest_nice,
-                                      snc->cpu_guest_nice,
-                                      itv * HZ / 100 * cpu_per_node[node]),
+                                      snc->cpu_guest_nice, deltot_jiffies),
                           (snc->cpu_idle < snp->cpu_idle) ?
                           0.0 :
                           ll_sp_value(snp->cpu_idle,
-                                      snc->cpu_idle,
-                                      itv * HZ / 100 * cpu_per_node[node]));
+                                      snc->cpu_idle, deltot_jiffies));
                printf("\n");
        }
 }
@@ -912,75 +887,28 @@ void write_plain_node_stats(int dis, unsigned long long deltot_jiffies, unsigned
  * @tab                Number of tabs to print.
  * @deltot_jiffies
  *             Number of jiffies spent on the interval by all processors.
- * @itv                Interval value.
  * @prev       Position in array where statistics used as reference are.
  *             Stats used as reference may be the previous ones read, or
  *             the very first ones when calculating the average.
  * @curr       Position in array where current statistics will be saved.
  ***************************************************************************
  */
-void write_json_node_stats(int tab, unsigned long long deltot_jiffies, unsigned long long itv,
+void write_json_node_stats(int tab, unsigned long long deltot_jiffies,
                           int prev, int curr)
 {
-       struct stats_cpu *snc, *snp;
-       int node, next = FALSE;
+       struct stats_cpu *snc, *snp, *scc, *scp;
+       int cpu, node, next = FALSE;
+       char node_name[16];
 
        xprintf(tab++, "\"node-load\": [");
 
-       /* Check if we want global stats among all nodes */
-       if (*node_bitmap & 1) {
+       for (node = 0; node <= node_nr + 1; node++) {
 
-               next = TRUE;
-               xprintf0(tab, "{\"node\": \"all\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
-                             "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
-                             "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
-                        (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
-                        (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
-                        0.0 :
-                        ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
-                                    st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
-                                    deltot_jiffies),
-                        (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
-                        (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
-                        0.0 :
-                        ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
-                                    st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
-                                    deltot_jiffies),
-                        ll_sp_value(st_cpu[prev]->cpu_sys,
-                                    st_cpu[curr]->cpu_sys,
-                                    deltot_jiffies),
-                        ll_sp_value(st_cpu[prev]->cpu_iowait,
-                                    st_cpu[curr]->cpu_iowait,
-                                    deltot_jiffies),
-                        ll_sp_value(st_cpu[prev]->cpu_hardirq,
-                                    st_cpu[curr]->cpu_hardirq,
-                                    deltot_jiffies),
-                        ll_sp_value(st_cpu[prev]->cpu_softirq,
-                                    st_cpu[curr]->cpu_softirq,
-                                    deltot_jiffies),
-                        ll_sp_value(st_cpu[prev]->cpu_steal,
-                                    st_cpu[curr]->cpu_steal,
-                                    deltot_jiffies),
-                        ll_sp_value(st_cpu[prev]->cpu_guest,
-                                    st_cpu[curr]->cpu_guest,
-                                    deltot_jiffies),
-                        ll_sp_value(st_cpu[prev]->cpu_guest_nice,
-                                    st_cpu[curr]->cpu_guest_nice,
-                                    deltot_jiffies),
-                        (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
-                        0.0 :
-                        ll_sp_value(st_cpu[prev]->cpu_idle,
-                                    st_cpu[curr]->cpu_idle,
-                                    deltot_jiffies));
-       }
-
-       for (node = 0; node <= node_nr; node++) {
-
-               snc = st_node[curr] + node + 1;
-               snp = st_node[prev] + node + 1;
+               snc = st_node[curr] + node;
+               snp = st_node[prev] + node;
 
                /* Check if we want stats about this node */
-               if (!(*(node_bitmap + ((node + 1) >> 3)) & (1 << ((node + 1) & 0x07))))
+               if (!(*(node_bitmap + (node >> 3)) & (1 << (node & 0x07))))
                        continue;
 
                if (!cpu_per_node[node])
@@ -992,45 +920,69 @@ void write_json_node_stats(int tab, unsigned long long deltot_jiffies, unsigned
                }
                next = TRUE;
 
-               xprintf0(tab, "{\"node\": \"%d\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
+               if (node == 0) {
+                       /* This is node "all", i.e. CPU "all" */
+                       strcpy(node_name, "all");
+               }
+               else {
+                       snprintf(node_name, 16, "%d", node - 1);
+                       node_name[15] = '\0';
+
+                       /* Recalculate interval for current node */
+                       deltot_jiffies = 0;
+                       for (cpu = 1; cpu <= cpu_nr; cpu++) {
+                               scc = st_cpu[curr] + cpu;
+                               scp = st_cpu[prev] + cpu;
+
+                               if ((scp->cpu_user + scp->cpu_nice + scp->cpu_sys +
+                                    scp->cpu_idle + scp->cpu_iowait + scp->cpu_hardirq +
+                                    scp->cpu_steal + scp->cpu_softirq == 0) && (interval != 0))
+                                       continue;
+
+                               if (cpu2node[cpu - 1] == node - 1) {
+                                       deltot_jiffies += get_per_cpu_interval(scc, scp);
+                               }
+                       }
+
+                       if (!deltot_jiffies) {
+                               /* All CPU in node are tickless and/or offline */
+                               xprintf0(tab, "{\"node\": \"%d\", \"usr\": 0.00, \"nice\": 0.00, \"sys\": 0.00, "
+                             "\"iowait\": 0.00, \"irq\": 0.00, \"soft\": 0.00, \"steal\": 0.00, "
+                             "\"guest\": 0.00, \"gnice\": 0.00, \"idle\": 100.00}", node - 1);
+
+                               continue;
+                       }
+               }
+
+               xprintf0(tab, "{\"node\": \"%s\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
                              "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
-                             "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", node,
+                             "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", node_name,
                         (snc->cpu_user - snc->cpu_guest) < (snp->cpu_user - snp->cpu_guest) ?
                         0.0 :
                         ll_sp_value(snp->cpu_user - snp->cpu_guest,
-                                    snc->cpu_user - snc->cpu_guest,
-                                    itv * HZ / 100 * cpu_per_node[node]),
+                                    snc->cpu_user - snc->cpu_guest, deltot_jiffies),
                         (snc->cpu_nice - snc->cpu_guest_nice) < (snp->cpu_nice - snp->cpu_guest_nice) ?
                         0.0 :
                         ll_sp_value(snp->cpu_nice - snp->cpu_guest_nice,
-                                    snc->cpu_nice - snc->cpu_guest_nice,
-                                    itv * HZ / 100 * cpu_per_node[node]),
+                                    snc->cpu_nice - snc->cpu_guest_nice, deltot_jiffies),
                         ll_sp_value(snp->cpu_sys,
-                                    snc->cpu_sys,
-                                    itv * HZ / 100 * cpu_per_node[node]),
+                                    snc->cpu_sys, deltot_jiffies),
                         ll_sp_value(snp->cpu_iowait,
-                                    snc->cpu_iowait,
-                                    itv * HZ / 100 * cpu_per_node[node]),
+                                    snc->cpu_iowait, deltot_jiffies),
                         ll_sp_value(snp->cpu_hardirq,
-                                    snc->cpu_hardirq,
-                                    itv * HZ / 100 * cpu_per_node[node]),
+                                    snc->cpu_hardirq, deltot_jiffies),
                         ll_sp_value(snp->cpu_softirq,
-                                    snc->cpu_softirq,
-                                    itv * HZ / 100 * cpu_per_node[node]),
+                                    snc->cpu_softirq, deltot_jiffies),
                         ll_sp_value(snp->cpu_steal,
-                                    snc->cpu_steal,
-                                    itv * HZ / 100 * cpu_per_node[node]),
+                                    snc->cpu_steal, deltot_jiffies),
                         ll_sp_value(snp->cpu_guest,
-                                    snc->cpu_guest,
-                                    itv * HZ / 100 * cpu_per_node[node]),
+                                    snc->cpu_guest, deltot_jiffies),
                         ll_sp_value(snp->cpu_guest_nice,
-                                    snc->cpu_guest_nice,
-                                    itv * HZ / 100 * cpu_per_node[node]),
+                                    snc->cpu_guest_nice, deltot_jiffies),
                         (snc->cpu_idle < snp->cpu_idle) ?
                         0.0 :
                         ll_sp_value(snp->cpu_idle,
-                                    snc->cpu_idle,
-                                    itv * HZ / 100 * cpu_per_node[node]));
+                                    snc->cpu_idle, deltot_jiffies));
        }
        printf("\n");
        xprintf0(--tab, "]");
@@ -1044,7 +996,6 @@ void write_json_node_stats(int tab, unsigned long long deltot_jiffies, unsigned
  * @dis                TRUE if a header line must be printed.
  * @deltot_jiffies
  *             Number of jiffies spent on the interval by all processors.
- * @itv                Interval value.
  * @prev       Position in array where statistics used as reference are.
  *             Stats used as reference may be the previous ones read, or
  *             the very first ones when calculating the average.
@@ -1060,19 +1011,18 @@ void write_json_node_stats(int tab, unsigned long long deltot_jiffies, unsigned
  *             only).
  ***************************************************************************
  */
-void write_node_stats(int dis, unsigned long long deltot_jiffies, unsigned long long itv,
-                     int prev, int curr, char *prev_string, char *curr_string,
-                     int tab, int *next)
+void write_node_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
+                     char *prev_string, char *curr_string, int tab, int *next)
 {
        if (DISPLAY_JSON_OUTPUT(flags)) {
                if (*next) {
                        printf(",\n");
                }
                *next = TRUE;
-               write_json_node_stats(tab, deltot_jiffies, itv, prev, curr);
+               write_json_node_stats(tab, deltot_jiffies, prev, curr);
        }
        else {
-               write_plain_node_stats(dis, deltot_jiffies, itv, prev, curr,
+               write_plain_node_stats(dis, deltot_jiffies, prev, curr,
                                       prev_string, curr_string);
        }
 }
@@ -1625,42 +1575,37 @@ void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
 void write_stats_core(int prev, int curr, int dis,
                      char *prev_string, char *curr_string)
 {
-       struct stats_cpu *scc, *scp;
-       unsigned long long itv, deltot_jiffies;
-       int cpu, tab = 4, next = FALSE;
+       unsigned long long itv, deltot_jiffies = 1;
+       int tab = 4, next = FALSE;
+       unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
 
        /* Test stdout */
        TEST_STDOUT(STDOUT_FILENO);
 
+       /*
+        * Compute CPU "all" as sum of all individual CPU (on SMP machines)
+        * and look for offline CPU.
+        */
+       deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
+
        if (DISPLAY_JSON_OUTPUT(flags)) {
                xprintf(tab++, "{");
                xprintf(tab, "\"timestamp\": \"%s\",", curr_string);
        }
 
-       /*
-        * Compute the total number of jiffies spent by all processors.
-        * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
-        * already include them.
-        */
-       tot_jiffies[curr] = st_cpu[curr]->cpu_user + st_cpu[curr]->cpu_nice +
-                           st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_idle +
-                           st_cpu[curr]->cpu_iowait + st_cpu[curr]->cpu_hardirq +
-                           st_cpu[curr]->cpu_steal + st_cpu[curr]->cpu_softirq;
-       /* Total number of jiffies spent on the interval */
-       deltot_jiffies = get_interval(tot_jiffies[prev], tot_jiffies[curr]);
-
        /* Get time interval */
        itv = get_interval(uptime_cs[prev], uptime_cs[curr]);
 
        /* Print CPU stats */
        if (DISPLAY_CPU(actflags)) {
-               write_cpu_stats(dis, prev, curr, prev_string,
-                               curr_string, tab, &next);
+               write_cpu_stats(dis, deltot_jiffies, prev, curr,
+                               prev_string, curr_string, tab, &next, offline_cpu_bitmap);
        }
 
        /* Print node CPU stats */
        if (DISPLAY_NODE(actflags)) {
-               write_node_stats(dis, deltot_jiffies, itv, prev, curr, prev_string,
+               set_node_cpu_stats(prev, curr);
+               write_node_stats(dis, deltot_jiffies, prev, curr, prev_string,
                                 curr_string, tab, &next);
        }
 
@@ -1684,25 +1629,6 @@ void write_stats_core(int prev, int curr, int dis,
                printf("\n");
                xprintf0(--tab, "}");
        }
-
-       /* Fix CPU counter values for every offline CPU */
-       for (cpu = 1; cpu <= cpu_nr; cpu++) {
-
-               scc = st_cpu[curr] + cpu;
-               scp = st_cpu[prev] + cpu;
-
-               if ((scc->cpu_user    + scc->cpu_nice + scc->cpu_sys   +
-                    scc->cpu_iowait  + scc->cpu_idle + scc->cpu_steal +
-                    scc->cpu_hardirq + scc->cpu_softirq) == 0) {
-                       /*
-                        * Offline CPU found.
-                        * Set current struct fields (which have been set to zero)
-                        * to values from previous iteration. Hence their values won't
-                        * jump from zero when the CPU comes back online.
-                        */
-                       *scc = *scp;
-               }
-       }
 }
 
 /*
@@ -1870,7 +1796,7 @@ void read_interrupts_stat(char *file, struct stats_irqcpu *st_ic[], int ic_nr, i
 void rw_mpstat_loop(int dis_hdr, int rows)
 {
        struct stats_cpu *scc;
-       int cpu;
+       int i;
        int curr = 1, dis = 1;
        unsigned long lines = rows;
 
@@ -1880,12 +1806,29 @@ void rw_mpstat_loop(int dis_hdr, int rows)
        /* Read system uptime and CPU stats */
        read_uptime(&(uptime_cs[0]));
        read_stat_cpu(st_cpu[0], cpu_nr + 1);
-       tot_jiffies[0] = st_cpu[0]->cpu_user + st_cpu[0]->cpu_nice +
-                        st_cpu[0]->cpu_sys + st_cpu[0]->cpu_idle +
-                        st_cpu[0]->cpu_iowait + st_cpu[0]->cpu_hardirq +
-                        st_cpu[0]->cpu_steal + st_cpu[0]->cpu_softirq;
-       if (DISPLAY_NODE(actflags)) {
-               set_node_cpu_stats(st_node[0], st_cpu[0]);
+
+       /*
+        * Calculate global CPU stats as the sum of individual ones.
+        * Done only on SMP machines. On UP machines, we keep the values
+        * read from /proc/stat for global CPU stats.
+        */
+       if (cpu_nr > 1) {
+               memset(st_cpu[0], 0, STATS_CPU_SIZE);
+
+               for (i = 1; i <= cpu_nr; i++) {
+                       scc = st_cpu[0] + i;
+
+                       st_cpu[0]->cpu_user += scc->cpu_user;
+                       st_cpu[0]->cpu_nice += scc->cpu_nice;
+                       st_cpu[0]->cpu_sys += scc->cpu_sys;
+                       st_cpu[0]->cpu_idle += scc->cpu_idle;
+                       st_cpu[0]->cpu_iowait += scc->cpu_iowait;
+                       st_cpu[0]->cpu_hardirq += scc->cpu_hardirq;
+                       st_cpu[0]->cpu_steal += scc->cpu_steal;
+                       st_cpu[0]->cpu_softirq += scc->cpu_softirq;
+                       st_cpu[0]->cpu_guest += scc->cpu_guest;
+                       st_cpu[0]->cpu_guest_nice += scc->cpu_guest_nice;
+               }
        }
 
        /*
@@ -1933,7 +1876,6 @@ void rw_mpstat_loop(int dis_hdr, int rows)
 
        /* Save the first stats collected. Will be used to compute the average */
        mp_tstamp[2] = mp_tstamp[0];
-       tot_jiffies[2] = tot_jiffies[0];
        uptime_cs[2] = uptime_cs[0];
        memcpy(st_cpu[2], st_cpu[0], STATS_CPU_SIZE * (cpu_nr + 1));
        memcpy(st_node[2], st_node[0], STATS_CPU_SIZE * (cpu_nr + 1));
@@ -1964,12 +1906,7 @@ void rw_mpstat_loop(int dis_hdr, int rows)
                 * if corresponding processor is disabled (offline). We set them to zero
                 * to be able to distinguish between offline and tickless CPUs.
                 */
-               for (cpu = 1; cpu <= cpu_nr; cpu++) {
-                       scc = st_cpu[curr] + cpu;
-                       memset(scc, 0, STATS_CPU_SIZE);
-                       scc = st_node[curr] + cpu;
-                       memset(scc, 0, STATS_CPU_SIZE);
-               }
+               memset(st_cpu[curr], 0, STATS_CPU_SIZE * (cpu_nr + 1));
 
                /* Get time */
                get_localtime(&(mp_tstamp[curr]), 0);
@@ -1977,9 +1914,6 @@ void rw_mpstat_loop(int dis_hdr, int rows)
                /* Read uptime and CPU stats */
                read_uptime(&(uptime_cs[curr]));
                read_stat_cpu(st_cpu[curr], cpu_nr + 1);
-               if (DISPLAY_NODE(actflags)) {
-                       set_node_cpu_stats(st_node[curr], st_cpu[curr]);
-               }
 
                /* Read total number of interrupts received among all CPU */
                if (DISPLAY_IRQ_SUM(actflags)) {