]> granicus.if.org Git - sysstat/commitdiff
Workaround for offline CPU coming back online
authorSebastien GODARD <sysstat@users.noreply.github.com>
Sat, 16 Dec 2017 08:29:21 +0000 (09:29 +0100)
committerSebastien GODARD <sysstat@users.noreply.github.com>
Sat, 16 Dec 2017 08:29:21 +0000 (09:29 +0100)
I noticed that whith recent kernels, when a CPU comes back online, some
fields (user, nice, system) restart from their previous value, whereas
others (idle, iowait) restart from zero. For values restarting from
zero, we need to set their previous value to zero to avoid getting an
interval value < 0.
We try also to guess if the counters have overflown: If the previous
value was greater than ULLONG_MAX & 0x80000, then the CPU was probably
not set offline but the counter overflew (the value 0x80000 is an
arbitrary limit that I decided to use).

See example below:

4.4.14-200.fc22.x86_64

cpu  8123 235 3359 1099139 15985 0 14 0 0 0
cpu0 1591 89 839 142345 6345 0 13 0 0 0
cpu1 1134 57 686 147160 2903 0 0 0 0 0
cpu2 1179 22 490 148289 1965 0 0 0 0 0
cpu3 1208 36 408 95477 25 0 0 0 0 0 <<<<<
cpu4 628 25 286 117308 250 0 0 0 0 0
cpu5 1122 1 260 149389 1263 0 0 0 0 0
cpu6 386 1 166 149943 1532 0 0 0 0 0
cpu7 871 0 222 149224 1698 0 0 0 0 0

cpu  8146 235 3374 1168377 18919 0 14 0 0 0
cpu0 1594 89 843 144632 6348 0 13 0 0 0
cpu1 1138 57 689 149455 2907 0 0 0 0 0
cpu2 1186 22 493 150585 1965 0 0 0 0 0
cpu4 629 25 286 119612 253 0 0 0 0 0
cpu5 1123 1 261 151693 1263 0 0 0 0 0
cpu6 386 1 166 152250 1532 0 0 0 0 0
cpu7 875 0 223 151526 1698 0 0 0 0 0

cpu  8169 236 3391 1033989 15978 0 14 0 0 0
cpu0 1598 89 847 146554 6354 0 13 0 0 0
cpu1 1143 57 692 151389 2910 0 0 0 0 0
cpu2 1192 23 497 152517 1965 0 0 0 0 0
cpu3 1213 36 411 677 0 0 0 0 0 0 <<<<<
cpu4 632 25 288 121553 253 0 0 0 0 0
cpu5 1125 1 262 153636 1263 0 0 0 0 0
cpu6 387 1 167 154193 1532 0 0 0 0 0
cpu7 877 0 224 153468 1698 0 0 0 0 0

In the example above, idle value for CPU#3 is 95477 before CPU is set
offline, then 677 when it has come back online, and iowait value goes
from 25 to 0.
On the other hand, user value for example goes from 1208 to 1213...
(We can also notice that values given for global CPU usage on the first
line have a really strange behavior...)

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

index 8b170baf8eb394f7ec241d0d1875347d78ad7413..fc4d05b5ecdb529a5ea7cb49b8c6e1e65ade6a1e 100644 (file)
--- a/common.c
+++ b/common.c
@@ -726,6 +726,24 @@ unsigned long long get_per_cpu_interval(struct stats_cpu *scc,
                          (scc->cpu_nice - scc->cpu_guest_nice);
        }
 
+       /*
+        * Workaround for CPU coming back online: With recent kernels
+        * some fields (user, nice, system) restart from their previous value,
+        * whereas others (idle, iowait) restart from zero.
+        * For the latter we need to set their previous value to zero to
+        * avoid getting an interval value < 0.
+        * (I don't know how the other fields like hardirq, steal... behave).
+        * Don't assume the CPU has come back from offline state if previous
+        * value was greater than ULLONG_MAX & 0x80000 (the counter probably
+        * overflew).
+        */
+       if ((scc->cpu_idle < scp->cpu_idle) && (scp->cpu_idle < (ULLONG_MAX & 0x80000))) {
+               scp->cpu_idle = 0;
+       }
+       if ((scc->cpu_iowait < scp->cpu_iowait) && (scp->cpu_iowait < (ULLONG_MAX & 0x80000))) {
+               scp->cpu_iowait = 0;
+       }
+
        /*
         * Don't take cpu_guest and cpu_guest_nice into account
         * because cpu_user and cpu_nice already include them.