File sysstat-compute-global-CPU-stats-1.patch of Package sysstat.7878
Index: sysstat-10.2.1/pr_stats.c
===================================================================
--- sysstat-10.2.1.orig/pr_stats.c
+++ sysstat-10.2.1/pr_stats.c
@@ -45,6 +45,10 @@ extern unsigned long avg_count;
/*
***************************************************************************
* Display CPU statistics.
+ * NB: The stats are only calculated over the part of the time interval when
+ * the CPU was online. As a consequence, the sum (%user + %nice + ... + %idle)
+ * will always be 100% on the time interval even if the CPU has been offline
+ * most of the time.
*
* IN:
* @a Activity structure with statistics.
@@ -58,7 +62,13 @@ __print_funct_t print_cpu_stats(struct a
unsigned long long g_itv)
{
int i;
+ unsigned long long tot_jiffies_c, tot_jiffies_p;
struct stats_cpu *scc, *scp;
+ struct stats_cpu *scc_all = (struct stats_cpu *) ((char *) a->buf[curr]);
+ struct stats_cpu *scp_all = (struct stats_cpu *) ((char *) a->buf[prev]);
+ unsigned char offline_cpu_bitmap[BITMAP_SIZE(NR_CPUS)] = {0};
+
+ g_itv = 0;
if (dis) {
if (DISPLAY_CPU_DEF(a->opt_flags)) {
@@ -73,7 +83,19 @@ __print_funct_t print_cpu_stats(struct a
timestamp[!curr]);
}
}
-
+
+ /*
+ * Initial processing.
+ * Compute CPU "all" as sum of all individual CPU. Done only on SMP machines (a->nr > 1).
+ * 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 (a->nr > 1) {
+ memset(scc_all, 0, sizeof(struct stats_cpu));
+ memset(scp_all, 0, sizeof(struct stats_cpu));
+ }
+
for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
/*
@@ -86,126 +108,199 @@ __print_funct_t print_cpu_stats(struct a
scp = (struct stats_cpu *) ((char *) a->buf[prev] + i * a->msize);
/*
- * Note: a->nr is in [1, NR_CPUS + 1].
+ * Compute the total number of jiffies spent by current processor.
+ * 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 omited 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) && !WANT_SINCE_BOOT(flags)) {
+ /*
+ * 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".
+ */
+ 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.
+ */
+ g_itv += 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;
+ }
+
+ /*
+ * 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 < a->nr) && (i < a->bitmap->b_size + 1); i++) {
+ /*
+ * Should current CPU (including CPU "all") be displayed?
+ * Note: @nr[curr] is in [1, NR_CPUS + 1].
* Bitmap size is provided for (NR_CPUS + 1) CPUs.
* Anyway, NR_CPUS may vary between the version of sysstat
* used by sadc to create a file, and the version of sysstat
* used by sar to read it...
*/
+ if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))) ||
+ offline_cpu_bitmap[i >> 3] & (1 << (i & 0x07)))
+ /* Don't display CPU */
+ continue;
+
+ scc = (struct stats_cpu *) ((char *) a->buf[curr] + i * a->msize);
+ scp = (struct stats_cpu *) ((char *) a->buf[prev] + i * a->msize);
- /* Should current CPU (including CPU "all") be displayed? */
- if (a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))) {
-
- /* Yes: Display it */
- printf("%-11s", timestamp[curr]);
+ printf("%-11s", timestamp[curr]);
+
+ if (i == 0) {
+ /* This is CPU "all" */
+ printf(" all");
- if (!i) {
- /* This is CPU "all" */
- printf(" all");
+ if (a->nr == 1) {
+ /*
+ * This is a UP machine. In this case
+ * interval has still not been calculated.
+ */
+ g_itv = get_per_cpu_interval(scc, scp);
}
- else {
- printf(" %3d", i - 1);
+ }
+ else {
+ printf(" %3d", i - 1);
+ /* Recalculate interval for current proc */
+ g_itv = get_per_cpu_interval(scc, scp);
+
+ if (!g_itv) {
/*
- * If the CPU is offline then it is omited from /proc/stat:
- * All the fields couldn't have been read and the sum of them is zero.
- * (Remember that guest/guest_nice times are already included in
- * user/nice modes.)
+ * If the CPU is tickless then there is no change in CPU values
+ * but the sum of values is not zero.
+ * %user, %nice, %system, %iowait, %steal, ..., %idle
*/
- 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) {
- /*
- * 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;
-
- /* %user, %nice, %system, %iowait, %steal, ..., %idle */
- printf(" %6.2f %6.2f %6.2f"
- " %6.2f %6.2f %6.2f",
- 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
-
- if (DISPLAY_CPU_ALL(a->opt_flags)) {
- /*
- * Four additional fields to display:
- * %irq, %soft, %guest, %gnice.
- */
- printf(" %6.2f %6.2f %6.2f %6.2f",
- 0.0, 0.0, 0.0, 0.0);
- }
- printf("\n");
- continue;
- }
+ printf(" %6.2f %6.2f %6.2f"
+ " %6.2f %6.2f",
+ 0.0, 0.0, 0.0, 0.0, 0.0);
- /* Recalculate interval for current proc */
- g_itv = get_per_cpu_interval(scc, scp);
-
- if (!g_itv) {
- /*
- * If the CPU is tickless then there is no change in CPU values
- * but the sum of values is not zero.
- * %user, %nice, %system, %iowait, %steal, ..., %idle
- */
- printf(" %6.2f %6.2f %6.2f"
- " %6.2f %6.2f",
- 0.0, 0.0, 0.0, 0.0, 0.0);
-
- if (DISPLAY_CPU_DEF(a->opt_flags)) {
- printf(" %6.2f\n", 100.0);
- }
- /*
- * Four additional fields to display:
- * %irq, %soft, %guest, %gnice.
- */
- else if (DISPLAY_CPU_ALL(a->opt_flags)) {
- printf(" %6.2f %6.2f %6.2f %6.2f\n",
- 0.0, 0.0, 0.0, 100.0);
- }
- continue;
+ if (DISPLAY_CPU_DEF(a->opt_flags)) {
+ printf(" %6.2f\n", 100.0);
}
- }
-
- if (DISPLAY_CPU_DEF(a->opt_flags)) {
- printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n",
- ll_sp_value(scp->cpu_user, scc->cpu_user, g_itv),
- ll_sp_value(scp->cpu_nice, scc->cpu_nice, g_itv),
- ll_sp_value(scp->cpu_sys + scp->cpu_hardirq + scp->cpu_softirq,
- scc->cpu_sys + scc->cpu_hardirq + scc->cpu_softirq,
- g_itv),
- ll_sp_value(scp->cpu_iowait, scc->cpu_iowait, g_itv),
- ll_sp_value(scp->cpu_steal, scc->cpu_steal, g_itv),
- scc->cpu_idle < scp->cpu_idle ?
- 0.0 :
- ll_sp_value(scp->cpu_idle, scc->cpu_idle, g_itv));
- }
- else if (DISPLAY_CPU_ALL(a->opt_flags)) {
- printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
- " %6.2f %6.2f %6.2f %6.2f\n",
- (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, g_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, g_itv),
- ll_sp_value(scp->cpu_sys, scc->cpu_sys, g_itv),
- ll_sp_value(scp->cpu_iowait, scc->cpu_iowait, g_itv),
- ll_sp_value(scp->cpu_steal, scc->cpu_steal, g_itv),
- ll_sp_value(scp->cpu_hardirq, scc->cpu_hardirq, g_itv),
- ll_sp_value(scp->cpu_softirq, scc->cpu_softirq, g_itv),
- ll_sp_value(scp->cpu_guest, scc->cpu_guest, g_itv),
- ll_sp_value(scp->cpu_guest_nice, scc->cpu_guest_nice, g_itv),
- scc->cpu_idle < scp->cpu_idle ?
- 0.0 :
- ll_sp_value(scp->cpu_idle, scc->cpu_idle, g_itv));
+ /*
+ * Four additional fields to display:
+ * %irq, %soft, %guest, %gnice.
+ */
+ else if (DISPLAY_CPU_ALL(a->opt_flags)) {
+ printf(" %6.2f %6.2f %6.2f %6.2f\n",
+ 0.0, 0.0, 0.0, 100.0);
+ }
+ continue;
}
}
+
+ if (DISPLAY_CPU_DEF(a->opt_flags)) {
+ printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n",
+ ll_sp_value(scp->cpu_user, scc->cpu_user, g_itv),
+ ll_sp_value(scp->cpu_nice, scc->cpu_nice, g_itv),
+ ll_sp_value(scp->cpu_sys + scp->cpu_hardirq + scp->cpu_softirq,
+ scc->cpu_sys + scc->cpu_hardirq + scc->cpu_softirq,
+ g_itv),
+ ll_sp_value(scp->cpu_iowait, scc->cpu_iowait, g_itv),
+ ll_sp_value(scp->cpu_steal, scc->cpu_steal, g_itv),
+ scc->cpu_idle < scp->cpu_idle ?
+ 0.0 :
+ ll_sp_value(scp->cpu_idle, scc->cpu_idle, g_itv));
+ }
+ else if (DISPLAY_CPU_ALL(a->opt_flags)) {
+ printf(" %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
+ " %6.2f %6.2f %6.2f %6.2f\n",
+ (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, g_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, g_itv),
+ ll_sp_value(scp->cpu_sys, scc->cpu_sys, g_itv),
+ ll_sp_value(scp->cpu_iowait, scc->cpu_iowait, g_itv),
+ ll_sp_value(scp->cpu_steal, scc->cpu_steal, g_itv),
+ ll_sp_value(scp->cpu_hardirq, scc->cpu_hardirq, g_itv),
+ ll_sp_value(scp->cpu_softirq, scc->cpu_softirq, g_itv),
+ ll_sp_value(scp->cpu_guest, scc->cpu_guest, g_itv),
+ ll_sp_value(scp->cpu_guest_nice, scc->cpu_guest_nice, g_itv),
+ scc->cpu_idle < scp->cpu_idle ?
+ 0.0 :
+ ll_sp_value(scp->cpu_idle, scc->cpu_idle, g_itv));
+ }
}
}
+
/*
***************************************************************************
* Display tasks creation and context switches statistics.