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...*/
/*
* 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;
* 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;
int cpu, node, node_nr = -1;
/* Init number of CPU per node */
- memset(cpu_per_node, 0, sizeof(int) * cpu_nr);
+ memset(cpu_per_node, 0, sizeof(int) * (cpu_nr + 1));
/* CPU belongs to no node by default */
memset(cpu2node, -1, sizeof(int) * cpu_nr);
+ /* This is node "all" */
+ cpu_per_node[0] = cpu_nr;
+
for (cpu = 0; cpu < cpu_nr; cpu++) {
snprintf(line, MAX_PF_NAME, "%s/cpu%d", SYSFS_DEVCPU, cpu);
line[MAX_PF_NAME - 1] = '\0';
closedir(dir);
return -1;
}
- cpu_per_node[node]++;
+ cpu_per_node[node + 1]++;
cpu2node[cpu] = node;
if (node > node_nr) {
node_nr = node;
* Compute node statistics: Split CPU statistics among nodes.
*
* IN:
- * @st_cpu Array where current CPU stats have been read.
+ * @src Structure containing CPU stats to add.
+ *
+ * OUT:
+ * @dest Structure containing global CPU stats.
+ ***************************************************************************
+ */
+void add_cpu_stats(struct stats_cpu *dest, struct stats_cpu *src)
+{
+ dest->cpu_user += src->cpu_user;
+ dest->cpu_nice += src->cpu_nice;
+ dest->cpu_sys += src->cpu_sys;
+ dest->cpu_idle += src->cpu_idle;
+ dest->cpu_iowait += src->cpu_iowait;
+ dest->cpu_hardirq += src->cpu_hardirq;
+ dest->cpu_softirq += src->cpu_softirq;
+ dest->cpu_steal += src->cpu_steal;
+ dest->cpu_guest += src->cpu_guest;
+ dest->cpu_guest_nice += src->cpu_guest_nice;
+}
+
+/*
+ ***************************************************************************
+ * Compute node statistics: Split CPU statistics among nodes.
+ *
+ * IN:
+ * @prev Index in array where stats used as reference are.
+ * @curr Index in array for current sample statistics.
*
* OUT:
* @st_node Array where CPU stats for each node have been saved.
***************************************************************************
*/
-void set_node_cpu_stats(struct stats_cpu *st_node, struct stats_cpu *st_cpu)
+void set_node_cpu_stats(int prev, int curr)
{
int cpu;
- struct stats_cpu *st_cpu_i, *st_node_i;
+ unsigned long long tot_jiffies_p;
+ struct stats_cpu *scp, *scc, *snp, *snc;
+ struct stats_cpu *scc_all = st_cpu[curr];
+ struct stats_cpu *scp_all = st_cpu[prev];
+ struct stats_cpu *snc_all = st_node[curr];
+ struct stats_cpu *snp_all = st_node[prev];
+
+ /* Reset structures */
+ memset(st_node[prev], 0, STATS_CPU_SIZE * (cpu_nr + 1));
+ memset(st_node[curr], 0, STATS_CPU_SIZE * (cpu_nr + 1));
+
+ /* Node 'all' is the same as CPU 'all' */
+ *snp_all = *scp_all;
+ *snc_all = *scc_all;
+ /* Individual nodes */
for (cpu = 0; cpu < cpu_nr; cpu++) {
- /* Don't store stats for node 'all'. They are the same as CPU 'all' */
- st_cpu_i = st_cpu + cpu + 1;
- st_node_i = st_node + cpu2node[cpu] + 1;
-
- st_node_i->cpu_user += st_cpu_i->cpu_user;
- st_node_i->cpu_nice += st_cpu_i->cpu_nice;
- st_node_i->cpu_sys += st_cpu_i->cpu_sys;
- st_node_i->cpu_idle += st_cpu_i->cpu_idle;
- st_node_i->cpu_iowait += st_cpu_i->cpu_iowait;
- st_node_i->cpu_hardirq += st_cpu_i->cpu_hardirq;
- st_node_i->cpu_softirq += st_cpu_i->cpu_softirq;
- st_node_i->cpu_steal += st_cpu_i->cpu_steal;
- st_node_i->cpu_guest += st_cpu_i->cpu_guest;
- st_node_i->cpu_guest_nice += st_cpu_i->cpu_guest_nice;
+ scc = st_cpu[curr] + cpu + 1;
+ scp = st_cpu[prev] + cpu + 1;
+ snp = st_node[prev] + cpu2node[cpu] + 1;
+ snc = st_node[curr] + cpu2node[cpu] + 1;
+
+
+ tot_jiffies_p = scp->cpu_user + scp->cpu_nice +
+ scp->cpu_sys + scp->cpu_idle +
+ scp->cpu_iowait + scp->cpu_hardirq +
+ scp->cpu_steal + scp->cpu_softirq;
+ if ((tot_jiffies_p == 0) && (interval != 0))
+ /*
+ * CPU has just come back online with no ref from
+ * previous iteration: Skip it.
+ */
+ continue;
+
+ add_cpu_stats(snp, scp);
+ add_cpu_stats(snc, scc);
}
}
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++) {
* already offline when the first sample has been taken.
* So don't display that CPU to prevent "jump-from-zero"
* output syndrome, and don't take it into account for CPU "all".
- * NB: Test for interval != 0 to make sure we don't stats since boot time.
+ * NB: Test for interval != 0 to make sure we don't want stats
+ * since boot time.
*/
offline_cpu_bitmap[i >> 3] |= 1 << (i & 0x07);
continue;
*/
deltot_jiffies += get_per_cpu_interval(scc, scp);
- scc_all->cpu_user += scc->cpu_user;
- scp_all->cpu_user += scp->cpu_user;
-
- scc_all->cpu_nice += scc->cpu_nice;
- scp_all->cpu_nice += scp->cpu_nice;
-
- scc_all->cpu_sys += scc->cpu_sys;
- scp_all->cpu_sys += scp->cpu_sys;
-
- scc_all->cpu_idle += scc->cpu_idle;
- scp_all->cpu_idle += scp->cpu_idle;
-
- scc_all->cpu_iowait += scc->cpu_iowait;
- scp_all->cpu_iowait += scp->cpu_iowait;
-
- scc_all->cpu_hardirq += scc->cpu_hardirq;
- scp_all->cpu_hardirq += scp->cpu_hardirq;
-
- scc_all->cpu_steal += scc->cpu_steal;
- scp_all->cpu_steal += scp->cpu_steal;
-
- scc_all->cpu_softirq += scc->cpu_softirq;
- scp_all->cpu_softirq += scp->cpu_softirq;
-
- scc_all->cpu_guest += scc->cpu_guest;
- scp_all->cpu_guest += scp->cpu_guest;
-
- scc_all->cpu_guest_nice += scc->cpu_guest_nice;
- scp_all->cpu_guest_nice += scp->cpu_guest_nice;
+ add_cpu_stats(scc_all, scc);
+ add_cpu_stats(scp_all, scp);
}
return deltot_jiffies;
*
* IN:
* @dis TRUE if a header line must be printed.
+ * @deltot_jiffies
+ * Number of jiffies spent on the interval by all processors.
* @prev Position in array where statistics used as reference are.
* Stats used as reference may be the previous ones read, or
* the very first ones when calculating the average.
* @curr_string String displayed at the beginning of current sample stats.
* This is the timestamp of the current sample, or "Average"
* when displaying average stats.
+ * @offline_cpu_bitmap
+ * CPU bitmap for offline CPU.
***************************************************************************
*/
-void write_plain_cpu_stats(int dis, int prev, int curr,
- char *prev_string, char *curr_string)
+void write_plain_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
+ char *prev_string, char *curr_string, unsigned char offline_cpu_bitmap[])
{
int i;
struct stats_cpu *scc, *scp;
- unsigned long long deltot_jiffies = 1;
- unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
if (dis) {
printf("\n%-11s CPU %%usr %%nice %%sys %%iowait %%irq "
prev_string);
}
- /*
- * Compute CPU "all" as sum of all individual CPU (on SMP machines)
- * and look for offline CPU.
- */
- if (cpu_nr > 1) {
- deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
- }
-
/*
* Now display CPU statistics (including CPU "all"),
* except for offline CPU or CPU that the user doesn't want to see.
if (i == 0) {
/* This is CPU "all" */
cprintf_in(IS_STR, " %s", " all", 0);
-
- if (cpu_nr == 1) {
- /*
- * This is a UP machine. In this case
- * interval has still not been calculated.
- */
- deltot_jiffies = get_per_cpu_interval(scc, scp);
- }
}
else {
cprintf_in(IS_INT, " %4d", "", i - 1);
*
* IN:
* @tab Number of tabs to print.
+ * @deltot_jiffies
+ * Number of jiffies spent on the interval by all processors.
* @prev Position in array where statistics used as reference are.
* Stats used as reference may be the previous ones read, or
* the very first ones when calculating the average.
* @curr Position in array where current statistics will be saved.
+ * @offline_cpu_bitmap
+ * CPU bitmap for offline CPU.
***************************************************************************
*/
-void write_json_cpu_stats(int tab, int prev, int curr)
+void write_json_cpu_stats(int tab, unsigned long long deltot_jiffies, int prev, int curr,
+ unsigned char offline_cpu_bitmap[])
{
int i, next = FALSE;
struct stats_cpu *scc, *scp;
- unsigned long long deltot_jiffies = 1;
- unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
xprintf(tab++, "\"cpu-load\": [");
- /*
- * Compute CPU "all" as sum of all individual CPU (on SMP machines)
- * and look for offline CPU.
- */
- if (cpu_nr > 1) {
- deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
- }
-
/*
* Now display CPU statistics (including CPU "all"),
* except for offline CPU or CPU that the user doesn't want to see.
}
next = TRUE;
- if (i == 0) {
-
- if (cpu_nr == 1) {
- /*
- * This is a UP machine. In this case
- * interval has still not been calculated.
- */
- deltot_jiffies = get_per_cpu_interval(scc, scp);
- }
- }
- else {
+ if (i != 0) {
/* Recalculate itv for current proc */
deltot_jiffies = get_per_cpu_interval(scc, scp);
*
* IN:
* @dis TRUE if a header line must be printed.
+ * @deltot_jiffies
+ * Number of jiffies spent on the interval by all processors.
* @prev Position in array where statistics used as reference are.
* Stats used as reference may be the previous ones read, or
* the very first ones when calculating the average.
* @tab Number of tabs to print (JSON format only).
* @next TRUE is a previous activity has been displayed (JSON format
* only).
+ * @offline_cpu_bitmap
+ * CPU bitmap for offline CPU.
***************************************************************************
*/
-void write_cpu_stats(int dis, int prev, int curr, char *prev_string,
- char *curr_string, int tab, int *next)
+void write_cpu_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
+ char *prev_string, char *curr_string, int tab, int *next,
+ unsigned char offline_cpu_bitmap[])
{
if (DISPLAY_JSON_OUTPUT(flags)) {
if (*next) {
printf(",\n");
}
*next = TRUE;
- write_json_cpu_stats(tab, prev, curr);
+ write_json_cpu_stats(tab, deltot_jiffies, prev, curr,
+ offline_cpu_bitmap);
}
else {
- write_plain_cpu_stats(dis, prev, curr, prev_string, curr_string);
+ write_plain_cpu_stats(dis, deltot_jiffies, prev, curr,
+ prev_string, curr_string, offline_cpu_bitmap);
}
}
* @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.
* 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 "
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])
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");
}
}
* @tab Number of tabs to print.
* @deltot_jiffies
* Number of jiffies spent on the interval by all processors.
- * @itv Interval value.
* @prev Position in array where statistics used as reference are.
* Stats used as reference may be the previous ones read, or
* the very first ones when calculating the average.
* @curr Position in array where current statistics will be saved.
***************************************************************************
*/
-void write_json_node_stats(int tab, unsigned long long deltot_jiffies, unsigned long long itv,
+void write_json_node_stats(int tab, unsigned long long deltot_jiffies,
int prev, int curr)
{
- struct stats_cpu *snc, *snp;
- int node, next = FALSE;
+ struct stats_cpu *snc, *snp, *scc, *scp;
+ int cpu, node, next = FALSE;
+ char node_name[16];
xprintf(tab++, "\"node-load\": [");
- /* Check if we want global stats among all nodes */
- if (*node_bitmap & 1) {
+ for (node = 0; node <= node_nr + 1; node++) {
- next = TRUE;
- xprintf0(tab, "{\"node\": \"all\", \"usr\": %.2f, \"nice\": %.2f, \"sys\": %.2f, "
- "\"iowait\": %.2f, \"irq\": %.2f, \"soft\": %.2f, \"steal\": %.2f, "
- "\"guest\": %.2f, \"gnice\": %.2f, \"idle\": %.2f}",
- (st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest) <
- (st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest) ?
- 0.0 :
- ll_sp_value(st_cpu[prev]->cpu_user - st_cpu[prev]->cpu_guest,
- st_cpu[curr]->cpu_user - st_cpu[curr]->cpu_guest,
- deltot_jiffies),
- (st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice) <
- (st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice) ?
- 0.0 :
- ll_sp_value(st_cpu[prev]->cpu_nice - st_cpu[prev]->cpu_guest_nice,
- st_cpu[curr]->cpu_nice - st_cpu[curr]->cpu_guest_nice,
- deltot_jiffies),
- ll_sp_value(st_cpu[prev]->cpu_sys,
- st_cpu[curr]->cpu_sys,
- deltot_jiffies),
- ll_sp_value(st_cpu[prev]->cpu_iowait,
- st_cpu[curr]->cpu_iowait,
- deltot_jiffies),
- ll_sp_value(st_cpu[prev]->cpu_hardirq,
- st_cpu[curr]->cpu_hardirq,
- deltot_jiffies),
- ll_sp_value(st_cpu[prev]->cpu_softirq,
- st_cpu[curr]->cpu_softirq,
- deltot_jiffies),
- ll_sp_value(st_cpu[prev]->cpu_steal,
- st_cpu[curr]->cpu_steal,
- deltot_jiffies),
- ll_sp_value(st_cpu[prev]->cpu_guest,
- st_cpu[curr]->cpu_guest,
- deltot_jiffies),
- ll_sp_value(st_cpu[prev]->cpu_guest_nice,
- st_cpu[curr]->cpu_guest_nice,
- deltot_jiffies),
- (st_cpu[curr]->cpu_idle < st_cpu[prev]->cpu_idle) ?
- 0.0 :
- ll_sp_value(st_cpu[prev]->cpu_idle,
- st_cpu[curr]->cpu_idle,
- deltot_jiffies));
- }
-
- for (node = 0; node <= node_nr; node++) {
-
- snc = st_node[curr] + node + 1;
- snp = st_node[prev] + node + 1;
+ snc = st_node[curr] + node;
+ snp = st_node[prev] + node;
/* Check if we want stats about this node */
- if (!(*(node_bitmap + ((node + 1) >> 3)) & (1 << ((node + 1) & 0x07))))
+ if (!(*(node_bitmap + (node >> 3)) & (1 << (node & 0x07))))
continue;
if (!cpu_per_node[node])
}
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, "]");
* @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.
* only).
***************************************************************************
*/
-void write_node_stats(int dis, unsigned long long deltot_jiffies, unsigned long long itv,
- int prev, int curr, char *prev_string, char *curr_string,
- int tab, int *next)
+void write_node_stats(int dis, unsigned long long deltot_jiffies, int prev, int curr,
+ char *prev_string, char *curr_string, int tab, int *next)
{
if (DISPLAY_JSON_OUTPUT(flags)) {
if (*next) {
printf(",\n");
}
*next = TRUE;
- write_json_node_stats(tab, deltot_jiffies, itv, prev, curr);
+ write_json_node_stats(tab, deltot_jiffies, prev, curr);
}
else {
- write_plain_node_stats(dis, deltot_jiffies, itv, prev, curr,
+ write_plain_node_stats(dis, deltot_jiffies, prev, curr,
prev_string, curr_string);
}
}
void write_stats_core(int prev, int curr, int dis,
char *prev_string, char *curr_string)
{
- struct stats_cpu *scc, *scp;
- unsigned long long itv, deltot_jiffies;
- int cpu, tab = 4, next = FALSE;
+ unsigned long long itv, deltot_jiffies = 1;
+ int tab = 4, next = FALSE;
+ unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
/* Test stdout */
TEST_STDOUT(STDOUT_FILENO);
+ /*
+ * Compute CPU "all" as sum of all individual CPU (on SMP machines)
+ * and look for offline CPU.
+ */
+ deltot_jiffies = get_global_cpu_mpstats(prev, curr, offline_cpu_bitmap);
+
if (DISPLAY_JSON_OUTPUT(flags)) {
xprintf(tab++, "{");
xprintf(tab, "\"timestamp\": \"%s\",", curr_string);
}
- /*
- * Compute the total number of jiffies spent by all processors.
- * NB: Don't add cpu_guest/cpu_guest_nice because cpu_user/cpu_nice
- * already include them.
- */
- tot_jiffies[curr] = st_cpu[curr]->cpu_user + st_cpu[curr]->cpu_nice +
- st_cpu[curr]->cpu_sys + st_cpu[curr]->cpu_idle +
- st_cpu[curr]->cpu_iowait + st_cpu[curr]->cpu_hardirq +
- st_cpu[curr]->cpu_steal + st_cpu[curr]->cpu_softirq;
- /* Total number of jiffies spent on the interval */
- deltot_jiffies = get_interval(tot_jiffies[prev], tot_jiffies[curr]);
-
/* Get time interval */
itv = get_interval(uptime_cs[prev], uptime_cs[curr]);
/* Print CPU stats */
if (DISPLAY_CPU(actflags)) {
- write_cpu_stats(dis, prev, curr, prev_string,
- curr_string, tab, &next);
+ write_cpu_stats(dis, deltot_jiffies, prev, curr,
+ prev_string, curr_string, tab, &next, offline_cpu_bitmap);
}
/* Print node CPU stats */
if (DISPLAY_NODE(actflags)) {
- write_node_stats(dis, deltot_jiffies, itv, prev, curr, prev_string,
+ set_node_cpu_stats(prev, curr);
+ write_node_stats(dis, deltot_jiffies, prev, curr, prev_string,
curr_string, tab, &next);
}
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;
- }
- }
}
/*
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;
/* 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;
+ }
}
/*
/* 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));
* 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);
/* Read uptime and CPU stats */
read_uptime(&(uptime_cs[curr]));
read_stat_cpu(st_cpu[curr], cpu_nr + 1);
- if (DISPLAY_NODE(actflags)) {
- set_node_cpu_stats(st_node[curr], st_cpu[curr]);
- }
/* Read total number of interrupts received among all CPU */
if (DISPLAY_IRQ_SUM(actflags)) {