]> granicus.if.org Git - sysstat/blobdiff - mpstat.c
Merge branch 'scop-grep-E'
[sysstat] / mpstat.c
index cd5df9590cad6a1486e77af334ee42da4bf1f06d..2ad621b5510924a959926ae1f556846f9b0dd667 100644 (file)
--- a/mpstat.c
+++ b/mpstat.c
@@ -1,6 +1,6 @@
 /*
  * mpstat: per-processor statistics
- * (C) 2000-2017 by Sebastien GODARD (sysstat <at> orange.fr)
+ * (C) 2000-2021 by Sebastien GODARD (sysstat <at> orange.fr)
  *
  ***************************************************************************
  * This program is free software; you can redistribute it and/or modify it *
@@ -31,7 +31,6 @@
 
 #include "version.h"
 #include "mpstat.h"
-#include "common.h"
 #include "rd_stats.h"
 #include "count.h"
 
@@ -48,7 +47,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 +72,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;
 
@@ -84,6 +84,9 @@ int *cpu_per_node;
  */
 int *cpu2node;
 
+/* CPU topology */
+struct cpu_topology *st_cpu_topology;
+
 struct tm mp_tstamp[3];
 
 /* Activity flag */
@@ -93,6 +96,8 @@ unsigned int flags = 0;
 
 /* Interval and count parameters */
 long interval = -1, count = 0;
+/* Number of decimal places */
+int dplaces_nr = -1;
 
 /*
  * Nb of processors on the machine.
@@ -104,6 +109,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;
 
@@ -129,8 +135,9 @@ void usage(char *progname)
                progname);
 
        fprintf(stderr, _("Options are:\n"
-                         "[ -A ] [ -n ] [ -u ] [ -V ] [ -I { SUM | CPU | SCPU | ALL } ]\n"
-                         "[ -N { <node_list> | ALL } ] [ -o JSON ] [ -P { <cpu_list> | ON | ALL } ]\n"));
+                         "[ -A ] [ -n ] [ -T ] [ -u ] [ -V ]\n"
+                         "[ -I { SUM | CPU | SCPU | ALL } ] [ -N { <node_list> | ALL } ]\n"
+                         "[ --dec={ 0 | 1 | 2 } ] [ -o JSON ] [ -P { <cpu_list> | ALL } ]\n"));
        exit(1);
 }
 
@@ -234,6 +241,11 @@ void salloc_mp_struct(int nr_cpus)
                perror("malloc");
                exit(4);
        }
+
+       if ((st_cpu_topology = (struct cpu_topology *) malloc(sizeof(struct cpu_topology) * nr_cpus)) == NULL) {
+               perror("malloc");
+               exit(4);
+       }
 }
 
 /*
@@ -265,7 +277,7 @@ void sfree_mp_struct(void)
  * CPU that each node has).
  *
  * IN:
- * @cpu_nr             Number of CPU on this machine.
+ * @nr_cpus            Number of CPU on this machine.
  *
  * OUT:
  * @cpu_per_node       Number of CPU per node.
@@ -276,22 +288,25 @@ void sfree_mp_struct(void)
  * A value of -1 means no nodes have been found.
  ***************************************************************************
  */
-int get_node_placement(int cpu_nr, int cpu_per_node[], int cpu2node[])
+int get_node_placement(int nr_cpus, int cpu_per_node[], int cpu2node[])
 
 {
        DIR *dir;
        struct dirent *drd;
        char line[MAX_PF_NAME];
-       int cpu, node, node_nr = -1;
+       int cpu, node, hi_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) * (nr_cpus + 1));
        /* CPU belongs to no node by default */
-       memset(cpu2node, -1, sizeof(int) * cpu_nr);
+       memset(cpu2node, -1, sizeof(int) * nr_cpus);
 
-       for (cpu = 0; cpu < cpu_nr; cpu++) {
-               snprintf(line, MAX_PF_NAME, "%s/cpu%d", SYSFS_DEVCPU, cpu);
-               line[MAX_PF_NAME - 1] = '\0';
+       /* This is node "all" */
+       cpu_per_node[0] = nr_cpus;
+
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+               snprintf(line, sizeof(line), "%s/cpu%d", SYSFS_DEVCPU, cpu);
+               line[sizeof(line) - 1] = '\0';
 
                /* Open relevant /sys directory */
                if ((dir = opendir(line)) == NULL)
@@ -302,15 +317,15 @@ int get_node_placement(int cpu_nr, int cpu_per_node[], int cpu2node[])
 
                        if (!strncmp(drd->d_name, "node", 4) && isdigit(drd->d_name[4])) {
                                node = atoi(drd->d_name + 4);
-                               if ((node >= cpu_nr) || (node < 0)) {
+                               if ((node >= nr_cpus) || (node < 0)) {
                                        /* Assume we cannot have more nodes than CPU */
                                        closedir(dir);
                                        return -1;
                                }
-                               cpu_per_node[node]++;
+                               cpu_per_node[node + 1]++;
                                cpu2node[cpu] = node;
-                               if (node > node_nr) {
-                                       node_nr = node;
+                               if (node > hi_node_nr) {
+                                       hi_node_nr = node;
                                }
                                /* Node placement found for current CPU: Go to next CPU directory */
                                break;
@@ -321,7 +336,91 @@ int get_node_placement(int cpu_nr, int cpu_per_node[], int cpu2node[])
                closedir(dir);
        }
 
-       return node_nr;
+       return hi_node_nr;
+}
+
+/*
+ ***************************************************************************
+ * Read system logical topology: Socket number for each logical core is read
+ * from the /sys/devices/system/cpu/cpu{N}/topology/physical_package_id file,
+ * and the logical core id number is the first number read from the
+ * /sys/devices/system/cpu/cpu{N}/topology/thread_siblings_list file.
+ * Don't use /sys/devices/system/cpu/cpu{N}/topology/core_id as this is the
+ * physical core id (seems to be different from the number displayed by lscpu).
+ *
+ * IN:
+ * @nr_cpus    Number of CPU on this machine.
+ * @cpu_topo   Structures where socket and core id numbers will be saved.
+ *
+ * OUT:
+ * @cpu_topo   Structures where socket and core id numbers have been saved.
+ ***************************************************************************
+ */
+void read_topology(int nr_cpus, struct cpu_topology *cpu_topo)
+{
+       struct cpu_topology *cpu_topo_i;
+       FILE *fp;
+       char filename[MAX_PF_NAME];
+       int cpu, rc;
+
+       /* Init system topology */
+       memset(st_cpu_topology, 0, sizeof(struct cpu_topology) * nr_cpus);
+
+       for (cpu = 0; cpu < nr_cpus; cpu++) {
+
+               cpu_topo_i = cpu_topo + cpu;
+
+               /* Read current CPU's socket number */
+               snprintf(filename, sizeof(filename), "%s/cpu%d/%s", SYSFS_DEVCPU, cpu, PHYS_PACK_ID);
+               filename[sizeof(filename) - 1] = '\0';
+
+               if ((fp = fopen(filename, "r")) != NULL) {
+                       rc = fscanf(fp, "%d", &cpu_topo_i->phys_package_id);
+                       fclose(fp);
+
+                       if (rc < 1) {
+                               cpu_topo_i->phys_package_id = -1;
+                       }
+               }
+
+               /* Read current CPU's logical core id number */
+               snprintf(filename, sizeof(filename), "%s/cpu%d/%s", SYSFS_DEVCPU, cpu, THREAD_SBL_LST);
+               filename[sizeof(filename) - 1] = '\0';
+
+               if ((fp = fopen(filename, "r")) != NULL) {
+                       rc = fscanf(fp, "%d", &cpu_topo_i->logical_core_id);
+                       fclose(fp);
+
+                       if (rc < 1) {
+                               cpu_topo_i->logical_core_id = -1;
+                       }
+               }
+       }
+}
+
+/*
+ ***************************************************************************
+ * Compute node statistics: Split CPU statistics among nodes.
+ *
+ * IN:
+ * @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;
 }
 
 /*
@@ -329,35 +428,172 @@ 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.
+ * @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);
        }
 }
 
+/*
+ ***************************************************************************
+ * Compute global CPU statistics as the sum of individual CPU ones, and
+ * calculate interval for global CPU.
+ * Also identify offline CPU.
+ *
+ * IN:
+ * @prev       Index in array where stats used as reference are.
+ * @curr       Index in array for current sample statistics.
+ * @offline_cpu_bitmap
+ *             CPU bitmap for offline CPU.
+ *
+ * OUT:
+ * @offline_cpu_bitmap
+ *             CPU bitmap with offline CPU.
+ *
+ * RETURNS:
+ * Interval for global CPU.
+ ***************************************************************************
+ */
+unsigned long long get_global_cpu_mpstats(int prev, int curr,
+                                         unsigned char offline_cpu_bitmap[])
+{
+       int i;
+       unsigned long long tot_jiffies_c, tot_jiffies_p;
+       unsigned long long deltot_jiffies = 0;
+       struct stats_cpu *scc, *scp;
+       struct stats_cpu *scc_all = st_cpu[curr];
+       struct stats_cpu *scp_all = st_cpu[prev];
+
+       /*
+        * For UP machines we keep the values read from global CPU line in /proc/stat.
+        * Also look for offline CPU: They won't be displayed, and some of their values may
+        * have to be modified.
+        */
+       if (cpu_nr > 1) {
+               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++) {
+
+               scc = st_cpu[curr] + i;
+               scp = st_cpu[prev] + i;
+
+               /*
+                * Compute the total number of jiffies spent by current processor.
+                * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
+                * already include them.
+                */
+               tot_jiffies_c = scc->cpu_user + scc->cpu_nice +
+                               scc->cpu_sys + scc->cpu_idle +
+                               scc->cpu_iowait + scc->cpu_hardirq +
+                               scc->cpu_steal + scc->cpu_softirq;
+               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 the CPU is offline then it is omitted from /proc/stat:
+                * All the fields couldn't have been read and the sum of them is zero.
+                */
+               if (tot_jiffies_c == 0) {
+                       /*
+                        * CPU is currently offline.
+                        * 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.
+                        * Note that this workaround no longer fully applies with recent kernels,
+                        * as I have noticed that when a CPU comes back online, some fields
+                        * restart from their previous value (e.g. user, nice, system)
+                        * whereas others restart from zero (idle, iowait)! To deal with this,
+                        * the get_per_cpu_interval() function will set these previous values
+                        * to zero if necessary.
+                        */
+                       *scc = *scp;
+
+                       /*
+                        * Mark CPU as offline to not display it
+                        * (and thus it will not be confused with a tickless CPU).
+                        */
+                       offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
+               }
+
+               if ((tot_jiffies_p == 0) && (interval != 0)) {
+                       /*
+                        * CPU has just come back online.
+                        * Unfortunately, no reference values are available
+                        * from a previous iteration, probably because it was
+                        * 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 want stats
+                        * since boot time.
+                        */
+                       offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
+                       continue;
+               }
+
+               /*
+                * Get interval for current CPU and add it to global CPU.
+                * Note: Previous idle and iowait values (saved in scp) may be modified here.
+                */
+               deltot_jiffies += get_per_cpu_interval(scc, scp);
+
+               add_cpu_stats(scc_all, scc);
+               add_cpu_stats(scp_all, scp);
+       }
+
+       return deltot_jiffies;
+}
+
 /*
  ***************************************************************************
  * Display CPU statistics in plain format.
@@ -376,154 +612,104 @@ void set_node_cpu_stats(struct stats_cpu *st_node, struct stats_cpu *st_cpu)
  * @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, unsigned long long deltot_jiffies, int prev, int curr,
-                          char *prev_string, char *curr_string)
+                          char *prev_string, char *curr_string, unsigned char offline_cpu_bitmap[])
 {
+       int i;
        struct stats_cpu *scc, *scp;
-       unsigned long long pc_itv;
-       int cpu;
+       struct cpu_topology *cpu_topo_i;
 
        if (dis) {
-               printf("\n%-11s  CPU    %%usr   %%nice    %%sys %%iowait    %%irq   "
-                      "%%soft  %%steal  %%guest  %%gnice   %%idle\n",
-                      prev_string);
-       }
-
-       /* Check if we want global stats among all proc */
-       if (*cpu_bitmap & 1) {
-
-               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");
+               printf("\n%-11s  CPU", prev_string);
+               if (DISPLAY_TOPOLOGY(flags)) {
+                       printf(" CORE SOCK NODE");
+               }
+               printf("    %%usr   %%nice    %%sys %%iowait    %%irq   "
+                      "%%soft  %%steal  %%guest  %%gnice   %%idle\n");
        }
 
-       for (cpu = 1; cpu <= cpu_nr; cpu++) {
-
-               scc = st_cpu[curr] + cpu;
-               scp = st_cpu[prev] + cpu;
+       /*
+        * Now display CPU statistics (including CPU "all"),
+        * except for offline CPU or CPU that the user doesn't want to see.
+        */
+       for (i = 0; i <= cpu_nr; i++) {
 
                /* Check if we want stats about this proc */
-               if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
+               if (!(*(cpu_bitmap + (i >> 3)) & (1 << (i & 0x07))) ||
+                   offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
                        continue;
 
-               /*
-                * If the CPU is offline then it is omited from /proc/stat
-                * and the sum of all values is zero.
-                * (Remember that guest/guest_nice times are already included in
-                * user/nice modes.)
-                */
-               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) {
+               scc = st_cpu[curr] + i;
+               scp = st_cpu[prev] + i;
 
-                       if (!DISPLAY_ONLINE_CPU(flags)) {
-                               printf("%-11s", curr_string);
-                               cprintf_in(IS_INT, " %4d", "", cpu - 1);
-                               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, 0.0);
-                               printf("\n");
+               printf("%-11s", curr_string);
+
+               if (i == 0) {
+                       /* This is CPU "all" */
+                       cprintf_in(IS_STR, " %s", " all", 0);
+
+                       if (DISPLAY_TOPOLOGY(flags)) {
+                               printf("               ");
                        }
-                       continue;
                }
+               else {
+                       cprintf_in(IS_INT, " %4d", "", i - 1);
 
-               printf("%-11s", curr_string);
-               cprintf_in(IS_INT, " %4d", "", cpu - 1);
+                       if (DISPLAY_TOPOLOGY(flags)) {
+                               cpu_topo_i = st_cpu_topology + i - 1;
+                               cprintf_in(IS_INT, " %4d", "", cpu_topo_i->logical_core_id);
+                               cprintf_in(IS_INT, " %4d", "", cpu_topo_i->phys_package_id);
+                               cprintf_in(IS_INT, " %4d", "", cpu2node[i - 1]);
+                       }
 
-               /* Recalculate itv for current proc */
-               pc_itv = get_per_cpu_interval(scc, scp);
+                       /* Recalculate itv for current proc */
+                       deltot_jiffies = get_per_cpu_interval(scc, scp);
 
-               if (!pc_itv) {
-                       /*
-                        * If the CPU is tickless then there is no change in CPU values
-                        * but the sum of values is not zero.
-                        */
-                       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");
-               }
+                       if (!deltot_jiffies) {
+                               /*
+                                * If the CPU is tickless then there is no change in CPU values
+                                * but the sum of values is not zero.
+                                */
+                               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");
 
-               else {
-                       cprintf_pc(NO_UNIT, 10, 7, 2,
-                                  (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
-                                  0.0 :
-                                  ll_sp_value(scp->cpu_user - scp->cpu_guest,
-                                              scc->cpu_user - scc->cpu_guest,
-                                              pc_itv),
-                                  (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
-                                  0.0 :
-                                  ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
-                                              scc->cpu_nice - scc->cpu_guest_nice,
-                                              pc_itv),
-                                  ll_sp_value(scp->cpu_sys,
-                                              scc->cpu_sys,
-                                              pc_itv),
-                                  ll_sp_value(scp->cpu_iowait,
-                                              scc->cpu_iowait,
-                                              pc_itv),
-                                  ll_sp_value(scp->cpu_hardirq,
-                                              scc->cpu_hardirq,
-                                              pc_itv),
-                                  ll_sp_value(scp->cpu_softirq,
-                                              scc->cpu_softirq,
-                                              pc_itv),
-                                  ll_sp_value(scp->cpu_steal,
-                                              scc->cpu_steal,
-                                              pc_itv),
-                                  ll_sp_value(scp->cpu_guest,
-                                              scc->cpu_guest,
-                                              pc_itv),
-                                  ll_sp_value(scp->cpu_guest_nice,
-                                              scc->cpu_guest_nice,
-                                              pc_itv),
-                                  (scc->cpu_idle < scp->cpu_idle) ?
-                                  0.0 :
-                                  ll_sp_value(scp->cpu_idle,
-                                              scc->cpu_idle,
-                                              pc_itv));
-                       printf("\n");
+                               continue;
+                       }
                }
+
+               cprintf_pc(NO_UNIT, 10, 7, 2,
+                          (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
+                          0.0 :
+                          ll_sp_value(scp->cpu_user - scp->cpu_guest,
+                                      scc->cpu_user - scc->cpu_guest, deltot_jiffies),
+                          (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
+                          0.0 :
+                          ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
+                                      scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
+                          ll_sp_value(scp->cpu_sys,
+                                      scc->cpu_sys, deltot_jiffies),
+                          ll_sp_value(scp->cpu_iowait,
+                                      scc->cpu_iowait, deltot_jiffies),
+                          ll_sp_value(scp->cpu_hardirq,
+                                      scc->cpu_hardirq, deltot_jiffies),
+                          ll_sp_value(scp->cpu_softirq,
+                                      scc->cpu_softirq, deltot_jiffies),
+                          ll_sp_value(scp->cpu_steal,
+                                      scc->cpu_steal, deltot_jiffies),
+                          ll_sp_value(scp->cpu_guest,
+                                      scc->cpu_guest, deltot_jiffies),
+                          ll_sp_value(scp->cpu_guest_nice,
+                                      scc->cpu_guest_nice, deltot_jiffies),
+                          (scc->cpu_idle < scp->cpu_idle) ?
+                          0.0 :
+                          ll_sp_value(scp->cpu_idle,
+                                      scc->cpu_idle, deltot_jiffies));
+               printf("\n");
        }
 }
 
@@ -539,152 +725,110 @@ void write_plain_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev,
  *             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, unsigned long long deltot_jiffies, 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;
+       char cpu_name[16], topology[1024] = "";
        struct stats_cpu *scc, *scp;
-       unsigned long long pc_itv;
-       int cpu, next = FALSE;
+       struct cpu_topology *cpu_topo_i;
 
        xprintf(tab++, "\"cpu-load\": [");
 
-       /* Check if we want global stats among all proc */
-       if (*cpu_bitmap & 1) {
-
-               next = TRUE;
-               xprintf0(tab, "{\"cpu\": \"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 (cpu = 1; cpu <= cpu_nr; cpu++) {
-
-               scc = st_cpu[curr] + cpu;
-               scp = st_cpu[prev] + cpu;
+       /*
+        * Now display CPU statistics (including CPU "all"),
+        * except for offline CPU or CPU that the user doesn't want to see.
+        */
+       for (i = 0; i <= cpu_nr; i++) {
 
                /* Check if we want stats about this proc */
-               if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
+               if (!(*(cpu_bitmap + (i >> 3)) & (1 << (i & 0x07))) ||
+                   offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
                        continue;
 
+               scc = st_cpu[curr] + i;
+               scp = st_cpu[prev] + i;
+
                if (next) {
                        printf(",\n");
                }
                next = TRUE;
 
-               /*
-                * If the CPU is offline then it is omited from /proc/stat
-                * and the sum of all values is zero.
-                * (Remember that guest/guest_nice times are already included in
-                * user/nice modes.)
-                */
-               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) {
-
-                       if (!DISPLAY_ONLINE_CPU(flags)) {
-                               xprintf0(tab, "{\"cpu\": \"%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\": 0.00}", cpu - 1);
+               if (i == 0) {
+                       /* This is CPU "all" */
+                       strcpy(cpu_name, "all");
+
+                       if (DISPLAY_TOPOLOGY(flags)) {
+                               snprintf(topology, 1024,
+                                        ", \"core\": \"\", \"socket\": \"\", \"node\": \"\"");
                        }
-                       continue;
+
                }
+               else {
+                       snprintf(cpu_name, 16, "%d", i - 1);
+                       cpu_name[15] = '\0';
+
+                       if (DISPLAY_TOPOLOGY(flags)) {
+                               cpu_topo_i = st_cpu_topology + i - 1;
+                               snprintf(topology, 1024,
+                                        ", \"core\": \"%d\", \"socket\": \"%d\", \"node\": \"%d\"",
+                                        cpu_topo_i->logical_core_id, cpu_topo_i->phys_package_id, cpu2node[i - 1]);
+                       }
 
-               /* Recalculate itv for current proc */
-               pc_itv = get_per_cpu_interval(scc, scp);
+                       /* Recalculate itv for current proc */
+                       deltot_jiffies = get_per_cpu_interval(scc, scp);
 
-               if (!pc_itv) {
-                       /*
-                        * If the CPU is tickless then there is no change in CPU values
-                        * but the sum of values is not zero.
-                        */
-                       xprintf0(tab, "{\"cpu\": \"%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}", cpu - 1);
-               }
+                       if (!deltot_jiffies) {
+                               /*
+                                * If the CPU is tickless then there is no change in CPU values
+                                * but the sum of values is not zero.
+                                */
+                               xprintf0(tab, "{\"cpu\": \"%d\"%s, \"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}", i - 1, topology);
+                               printf("\n");
 
-               else {
-                       xprintf0(tab, "{\"cpu\": \"%d\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
-                                     "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
-                                     "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}", cpu - 1,
-                                (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
-                                0.0 :
-                                ll_sp_value(scp->cpu_user - scp->cpu_guest,
-                                            scc->cpu_user - scc->cpu_guest,
-                                            pc_itv),
-                                (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
-                                0.0 :
-                                ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
-                                            scc->cpu_nice - scc->cpu_guest_nice,
-                                            pc_itv),
-                                ll_sp_value(scp->cpu_sys,
-                                            scc->cpu_sys,
-                                            pc_itv),
-                                ll_sp_value(scp->cpu_iowait,
-                                            scc->cpu_iowait,
-                                            pc_itv),
-                                ll_sp_value(scp->cpu_hardirq,
-                                            scc->cpu_hardirq,
-                                            pc_itv),
-                                ll_sp_value(scp->cpu_softirq,
-                                            scc->cpu_softirq,
-                                            pc_itv),
-                                ll_sp_value(scp->cpu_steal,
-                                            scc->cpu_steal,
-                                            pc_itv),
-                                ll_sp_value(scp->cpu_guest,
-                                            scc->cpu_guest,
-                                            pc_itv),
-                                ll_sp_value(scp->cpu_guest_nice,
-                                            scc->cpu_guest_nice,
-                                            pc_itv),
-                                (scc->cpu_idle < scp->cpu_idle) ?
-                                0.0 :
-                                ll_sp_value(scp->cpu_idle,
-                                            scc->cpu_idle,
-                                            pc_itv));
+                               continue;
+                       }
                }
+
+               xprintf0(tab, "{\"cpu\": \"%s\"%s, \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
+                        "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
+                        "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
+                        cpu_name, topology,
+                        (scc->cpu_user - scc->cpu_guest) < (scp->cpu_user - scp->cpu_guest) ?
+                        0.0 :
+                        ll_sp_value(scp->cpu_user - scp->cpu_guest,
+                                    scc->cpu_user - scc->cpu_guest, deltot_jiffies),
+                        (scc->cpu_nice - scc->cpu_guest_nice) < (scp->cpu_nice - scp->cpu_guest_nice) ?
+                        0.0 :
+                        ll_sp_value(scp->cpu_nice - scp->cpu_guest_nice,
+                                    scc->cpu_nice - scc->cpu_guest_nice, deltot_jiffies),
+                        ll_sp_value(scp->cpu_sys,
+                                    scc->cpu_sys, deltot_jiffies),
+                        ll_sp_value(scp->cpu_iowait,
+                                    scc->cpu_iowait, deltot_jiffies),
+                        ll_sp_value(scp->cpu_hardirq,
+                                    scc->cpu_hardirq, deltot_jiffies),
+                        ll_sp_value(scp->cpu_softirq,
+                                    scc->cpu_softirq, deltot_jiffies),
+                        ll_sp_value(scp->cpu_steal,
+                                    scc->cpu_steal, deltot_jiffies),
+                        ll_sp_value(scp->cpu_guest,
+                                    scc->cpu_guest, deltot_jiffies),
+                        ll_sp_value(scp->cpu_guest_nice,
+                                    scc->cpu_guest_nice, deltot_jiffies),
+                        (scc->cpu_idle < scp->cpu_idle) ?
+                        0.0 :
+                        ll_sp_value(scp->cpu_idle,
+                                    scc->cpu_idle, deltot_jiffies));
        }
+
        printf("\n");
        xprintf0(--tab, "]");
 }
@@ -710,20 +854,30 @@ void write_json_cpu_stats(int tab, unsigned long long deltot_jiffies, int prev,
  * @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, unsigned long long deltot_jiffies, int prev, int curr,
-                    char *prev_string, char *curr_string, int tab, int *next)
+                    char *prev_string, char *curr_string, int tab, int *next,
+                    unsigned char offline_cpu_bitmap[])
 {
+       if (!deltot_jiffies) {
+               /* CPU "all" cannot be tickless */
+               deltot_jiffies = 1;
+       }
+
        if (DISPLAY_JSON_OUTPUT(flags)) {
                if (*next) {
                        printf(",\n");
                }
                *next = TRUE;
-               write_json_cpu_stats(tab, deltot_jiffies, prev, curr);
+               write_json_cpu_stats(tab, deltot_jiffies, prev, curr,
+                                    offline_cpu_bitmap);
        }
        else {
-               write_plain_cpu_stats(dis, deltot_jiffies, prev, curr, prev_string, curr_string);
+               write_plain_cpu_stats(dis, deltot_jiffies, prev, curr,
+                                     prev_string, curr_string, offline_cpu_bitmap);
        }
 }
 
@@ -735,7 +889,6 @@ void write_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int c
  * @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.
@@ -748,11 +901,11 @@ void write_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int c
  *             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   "
@@ -760,64 +913,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])
@@ -825,45 +927,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");
        }
 }
@@ -876,75 +999,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) {
-
-               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++) {
+       for (node = 0; node <= node_nr + 1; 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])
@@ -956,45 +1032,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, "]");
@@ -1008,7 +1108,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.
@@ -1024,19 +1123,23 @@ 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 (!deltot_jiffies) {
+               /* CPU "all" cannot be tickless */
+               deltot_jiffies = 1;
+       }
+
        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);
        }
 }
@@ -1058,10 +1161,12 @@ void write_node_stats(int dis, unsigned long long deltot_jiffies, unsigned long
  * @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_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
-                              char *prev_string, char *curr_string)
+                              char *prev_string, char *curr_string, unsigned char offline_cpu_bitmap[])
 {
        struct stats_cpu *scc, *scp;
        struct stats_irq *sic, *sip;
@@ -1090,27 +1195,9 @@ void write_plain_isumcpu_stats(int dis, unsigned long long itv, int prev, int cu
                scp = st_cpu[prev] + cpu;
 
                /* Check if we want stats about this CPU */
-               if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
-                       continue;
-
-               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) {
-
-                       /* This is an offline CPU */
-
-                       if (!DISPLAY_ONLINE_CPU(flags)) {
-                               /*
-                                * Display offline CPU if requested by the user.
-                                * Value displayed is 0.00.
-                                */
-                               printf("%-11s", curr_string);
-                               cprintf_in(IS_INT, " %4d", "", cpu - 1);
-                               cprintf_f(NO_UNIT, 1, 9, 2, 0.0);
-                               printf("\n");
-                       }
+               if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) ||
+                   offline_cpu_bitmap[cpu >> 3] & (1 << (cpu & 0x07)))
                        continue;
-               }
 
                printf("%-11s", curr_string);
                cprintf_in(IS_INT, " %4d", "", cpu - 1);
@@ -1143,9 +1230,12 @@ void write_plain_isumcpu_stats(int dis, unsigned long long itv, int prev, int cu
  *             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_isumcpu_stats(int tab, unsigned long long itv, int prev, int curr)
+void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int curr,
+                             unsigned char offline_cpu_bitmap[])
 {
        struct stats_cpu *scc, *scp;
        struct stats_irq *sic, *sip;
@@ -1171,7 +1261,8 @@ void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int cur
                scp = st_cpu[prev] + cpu;
 
                /* Check if we want stats about this CPU */
-               if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))))
+               if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) ||
+                   offline_cpu_bitmap[cpu >> 3] & (1 << (cpu & 0x07)))
                        continue;
 
                if (next) {
@@ -1179,23 +1270,6 @@ void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int cur
                }
                next = TRUE;
 
-               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) {
-
-                       /* This is an offline CPU */
-
-                       if (!DISPLAY_ONLINE_CPU(flags)) {
-                               /*
-                                * Display offline CPU if requested by the user.
-                                * Value displayed is 0.00.
-                                */
-                               xprintf0(tab, "{\"cpu\": \"%d\", \"intr\": 0.00}",
-                                        cpu - 1);
-                       }
-                       continue;
-               }
-
                /* Recalculate itv for current proc */
                pc_itv = get_per_cpu_interval(scc, scp);
 
@@ -1235,20 +1309,24 @@ void write_json_isumcpu_stats(int tab, unsigned long long itv, int prev, int cur
  * @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_isumcpu_stats(int dis, unsigned long long itv, int prev, int curr,
-                    char *prev_string, char *curr_string, int tab, int *next)
+                        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_isumcpu_stats(tab, itv, prev, curr);
+               write_json_isumcpu_stats(tab, itv, prev, curr, offline_cpu_bitmap);
        }
        else {
-               write_plain_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string);
+               write_plain_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string,
+                                         offline_cpu_bitmap);
        }
 }
 
@@ -1271,13 +1349,14 @@ void write_isumcpu_stats(int dis, unsigned long long itv, 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_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
                              unsigned long long itv, int prev, int curr,
-                             char *prev_string, char *curr_string)
+                             char *prev_string, char *curr_string, unsigned char offline_cpu_bitmap[])
 {
-       struct stats_cpu *scc;
        int j = ic_nr, offset, cpu, colwidth[NR_IRQS];
        struct stats_irqcpu *p, *q, *p0, *q0;
 
@@ -1335,26 +1414,15 @@ void write_plain_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
 
        for (cpu = 1; cpu <= cpu_nr; cpu++) {
 
-               scc = st_cpu[curr] + cpu;
-
                /*
                 * Check if we want stats about this CPU.
                 * CPU must have been explicitly selected using option -P,
-                * else we display every CPU.
+                * else we display every CPU (unless it's offline).
                 */
-               if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
+               if ((!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_OPTION_P(flags)) ||
+                   offline_cpu_bitmap[cpu >> 3] & (1 << (cpu & 0x07)))
                        continue;
 
-               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 */
-
-                       if (DISPLAY_ONLINE_CPU(flags))
-                               continue;
-               }
-
                printf("%-11s", curr_string);
                cprintf_in(IS_INT, "  %3d", "", cpu - 1);
 
@@ -1420,12 +1488,14 @@ void write_plain_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
  *             the very first ones when calculating the average.
  * @curr       Position in array where current statistics will be saved.
  * @type       Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
+ * @offline_cpu_bitmap
+ *             CPU bitmap for offline CPU.
  ***************************************************************************
  */
 void write_json_irqcpu_stats(int tab, struct stats_irqcpu *st_ic[], int ic_nr,
-                            unsigned long long itv, int prev, int curr, int type)
+                            unsigned long long itv, int prev, int curr, int type,
+                            unsigned char offline_cpu_bitmap[])
 {
-       struct stats_cpu *scc;
        int j = ic_nr, offset, cpu;
        struct stats_irqcpu *p, *q, *p0, *q0;
        int nextcpu = FALSE, nextirq;
@@ -1439,26 +1509,15 @@ void write_json_irqcpu_stats(int tab, struct stats_irqcpu *st_ic[], int ic_nr,
 
        for (cpu = 1; cpu <= cpu_nr; cpu++) {
 
-               scc = st_cpu[curr] + cpu;
-
                /*
                 * Check if we want stats about this CPU.
                 * CPU must have been explicitly selected using option -P,
-                * else we display every CPU.
+                * else we display every CPU (unless it's offline).
                 */
-               if (!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_P_OPTION(flags))
+               if ((!(*(cpu_bitmap + (cpu >> 3)) & (1 << (cpu & 0x07))) && USE_OPTION_P(flags)) ||
+                   offline_cpu_bitmap[cpu >> 3] & (1 << (cpu & 0x07)))
                        continue;
 
-               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 */
-
-                       if (DISPLAY_ONLINE_CPU(flags))
-                               continue;
-               }
-
                if (nextcpu) {
                        printf(",\n");
                }
@@ -1548,23 +1607,26 @@ void write_json_irqcpu_stats(int tab, struct stats_irqcpu *st_ic[], int ic_nr,
  * @next       TRUE is a previous activity has been displayed (JSON format
  *             only).
  * @type       Activity (M_D_IRQ_CPU or M_D_SOFTIRQS).
+ * @offline_cpu_bitmap
+ *             CPU bitmap for offline CPU.
  ***************************************************************************
  */
 void write_irqcpu_stats(struct stats_irqcpu *st_ic[], int ic_nr, int dis,
                        unsigned long long itv, int prev, int curr,
                        char *prev_string, char *curr_string, int tab,
-                       int *next, int type)
+                       int *next, int type, unsigned char offline_cpu_bitmap[])
 {
        if (DISPLAY_JSON_OUTPUT(flags)) {
                if (*next) {
                        printf(",\n");
                }
                *next = TRUE;
-               write_json_irqcpu_stats(tab, st_ic, ic_nr, itv, prev, curr, type);
+               write_json_irqcpu_stats(tab, st_ic, ic_nr, itv, prev, curr, type,
+                                       offline_cpu_bitmap);
        }
        else {
                write_plain_irqcpu_stats(st_ic, ic_nr, dis, itv, prev, curr,
-                                        prev_string, curr_string);
+                                        prev_string, curr_string, offline_cpu_bitmap);
        }
 }
 
@@ -1589,84 +1651,62 @@ 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, deltot_jiffies, 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);
        }
 
        /* Print total number of interrupts per processor */
        if (DISPLAY_IRQ_SUM(actflags)) {
                write_isumcpu_stats(dis, itv, prev, curr, prev_string, curr_string,
-                                   tab, &next);
+                                   tab, &next, offline_cpu_bitmap);
        }
 
        /* Display each interrupt value for each CPU */
        if (DISPLAY_IRQ_CPU(actflags)) {
                write_irqcpu_stats(st_irqcpu, irqcpu_nr, dis, itv, prev, curr,
-                                  prev_string, curr_string, tab, &next, M_D_IRQ_CPU);
+                                  prev_string, curr_string, tab, &next, M_D_IRQ_CPU,
+                                  offline_cpu_bitmap);
        }
        if (DISPLAY_SOFTIRQS(actflags)) {
                write_irqcpu_stats(st_softirqcpu, softirqcpu_nr, dis, itv, prev, curr,
-                                  prev_string, curr_string, tab, &next, M_D_SOFTIRQS);
+                                  prev_string, curr_string, tab, &next, M_D_SOFTIRQS,
+                                  offline_cpu_bitmap);
        }
 
        if (DISPLAY_JSON_OUTPUT(flags)) {
                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;
-               }
-       }
 }
 
 /*
@@ -1834,22 +1874,41 @@ 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;
 
-       /* Dont buffer data if redirected to a pipe */
-       setbuf(stdout, NULL);
-
        /* 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;
+               }
+       }
+
+       /* Read system topology */
+       if (DISPLAY_CPU(actflags) && DISPLAY_TOPOLOGY(flags)) {
+               read_topology(cpu_nr, st_cpu_topology);
        }
 
        /*
@@ -1897,7 +1956,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));
@@ -1908,14 +1966,12 @@ void rw_mpstat_loop(int dis_hdr, int rows)
                       STATS_IRQCPU_SIZE * (cpu_nr + 1) * softirqcpu_nr);
        }
 
-       if (!DISPLAY_JSON_OUTPUT(flags)) {
-               /* Set a handler for SIGINT */
-               memset(&int_act, 0, sizeof(int_act));
-               int_act.sa_handler = int_handler;
-               sigaction(SIGINT, &int_act, NULL);
-       }
+       /* Set a handler for SIGINT */
+       memset(&int_act, 0, sizeof(int_act));
+       int_act.sa_handler = int_handler;
+       sigaction(SIGINT, &int_act, NULL);
 
-       pause();
+       __pause();
 
        if (sigint_caught)
                /* SIGINT signal caught during first interval: Exit immediately */
@@ -1928,12 +1984,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);
@@ -1941,8 +1992,10 @@ 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 system topology */
+               if (DISPLAY_CPU(actflags) && DISPLAY_TOPOLOGY(flags)) {
+                       read_topology(cpu_nr, st_cpu_topology);
                }
 
                /* Read total number of interrupts received among all CPU */
@@ -1977,17 +2030,16 @@ void rw_mpstat_loop(int dis_hdr, int rows)
 
                if (count) {
 
-                       if (DISPLAY_JSON_OUTPUT(flags)) {
-                               printf(",\n");
-                       }
-                       pause();
+                       __pause();
 
                        if (sigint_caught) {
                                /* SIGINT signal caught => Display average stats */
                                count = 0;
-                               printf("\n");   /* Skip "^C" displayed on screen */
                        }
                        else {
+                               if (DISPLAY_JSON_OUTPUT(flags)) {
+                                       printf(",\n");
+                               }
                                curr ^= 1;
                        }
                }
@@ -2048,7 +2100,15 @@ int main(int argc, char **argv)
 
        while (++opt < argc) {
 
-               if (!strcmp(argv[opt], "-I")) {
+               if (!strncmp(argv[opt], "--dec=", 6) && (strlen(argv[opt]) == 7)) {
+                       /* Get number of decimal places */
+                       dplaces_nr = atoi(argv[opt] + 6);
+                       if ((dplaces_nr < 0) || (dplaces_nr > 2)) {
+                               usage(argv[0]);
+                       }
+               }
+
+               else if (!strcmp(argv[opt], "-I")) {
                        if (!argv[++opt]) {
                                usage(argv[0]);
                        }
@@ -2091,7 +2151,7 @@ int main(int argc, char **argv)
                                usage(argv[0]);
                        }
                        if (node_nr >= 0) {
-                               flags |= F_N_OPTION;
+                               flags |= F_OPTION_N;
                                actflags |= M_D_NODE;
                                actset = TRUE;
                                dis_hdr = 9;
@@ -2106,15 +2166,10 @@ int main(int argc, char **argv)
                        if (!argv[++opt]) {
                                usage(argv[0]);
                        }
-                       flags |= F_P_OPTION;
+                       flags |= F_OPTION_P;
                        dis_hdr = 9;
 
-                       if (!strcmp(argv[opt], K_ON)) {
-                               /* Display stats for all online CPU */
-                               flags |= F_P_ON;
-                               memset(cpu_bitmap, ~0, BITMAP_SIZE(cpu_nr));
-                       }
-                       else if (parse_values(argv[opt], cpu_bitmap, cpu_nr, K_LOWERALL)) {
+                       if (parse_values(argv[opt], cpu_bitmap, cpu_nr, K_LOWERALL)) {
                                usage(argv[0]);
                        }
                }
@@ -2125,16 +2180,12 @@ int main(int argc, char **argv)
                                switch (*(argv[opt] + i)) {
 
                                case 'A':
+                                       flags |= F_OPTION_A;
                                        actflags |= M_D_CPU + M_D_IRQ_SUM + M_D_IRQ_CPU + M_D_SOFTIRQS;
                                        if (node_nr >= 0) {
                                                actflags |= M_D_NODE;
-                                               flags |= F_N_OPTION;
-                                               memset(node_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
                                        }
                                        actset = TRUE;
-                                       /* Select all processors */
-                                       flags |= F_P_OPTION;
-                                       memset(cpu_bitmap, 0xff, ((cpu_nr + 1) >> 3) + 1);
                                        break;
 
                                case 'n':
@@ -2145,6 +2196,11 @@ int main(int argc, char **argv)
                                        }
                                        break;
 
+                               case 'T':
+                                       /* Display logical topology */
+                                       flags |= F_TOPOLOGY;
+                                       break;
+
                                case 'u':
                                        /* Display CPU */
                                        actflags |= M_D_CPU;
@@ -2192,7 +2248,7 @@ int main(int argc, char **argv)
 
        /* Default: Display CPU (e.g., "mpstat", "mpstat -P 1", "mpstat -P 1 -n", "mpstat -P 1 -N 1"... */
        if (!actset ||
-           (USE_P_OPTION(flags) && !(actflags & ~M_D_NODE))) {
+           (USE_OPTION_P(flags) && !(actflags & ~M_D_NODE))) {
                actflags |= M_D_CPU;
        }
 
@@ -2200,11 +2256,26 @@ int main(int argc, char **argv)
                dis_hdr = 9;
        }
 
-       if (!USE_P_OPTION(flags)) {
+       if (USE_OPTION_A(flags)) {
+               /*
+                * Set -P ALL -N ALL only if individual CPU and/or nodes
+                * have not been selected.
+                */
+               if ((node_nr >= 0) && !USE_OPTION_N(flags)) {
+                       memset(node_bitmap, ~0, ((cpu_nr + 1) >> 3) + 1);
+                       flags += F_OPTION_N;
+               }
+               if (!USE_OPTION_P(flags)) {
+                       memset(cpu_bitmap, ~0, ((cpu_nr + 1) >> 3) + 1);
+                       flags += F_OPTION_P;
+               }
+       }
+
+       if (!USE_OPTION_P(flags)) {
                /* Option -P not used: Set bit 0 (global stats among all proc) */
                *cpu_bitmap = 1;
        }
-       if (!USE_N_OPTION(flags)) {
+       if (!USE_OPTION_N(flags)) {
                /* Option -N not used: Set bit 0 (global stats among all nodes) */
                *node_bitmap = 1;
        }
@@ -2228,8 +2299,15 @@ int main(int argc, char **argv)
        /* Get time */
        get_localtime(&(mp_tstamp[0]), 0);
 
+       /*
+        * Don't buffer data if redirected to a pipe.
+        * Note: With musl-c, the behavior of this function is undefined except
+        * when it is the first operation on the stream.
+        */
+       setbuf(stdout, NULL);
+
        /* Get system name, release number and hostname */
-       uname(&header);
+       __uname(&header);
        print_gal_header(&(mp_tstamp[0]), header.sysname, header.release,
                         header.nodename, header.machine, get_cpu_nr(~0, FALSE),
                         DISPLAY_JSON_OUTPUT(flags));