]> granicus.if.org Git - procps-ng/commitdiff
top: protect against distortion when system time reset
authorJim Warner <james.warner@comcast.net>
Fri, 25 Apr 2014 05:00:00 +0000 (00:00 -0500)
committerJaromir Capik <jcapik@redhat.com>
Mon, 28 Apr 2014 11:46:06 +0000 (13:46 +0200)
If a system's time is adjusted backwards, then elapsed
time could appear as negative. This yielded a negative
%CPU value. Alternately if zeros were suppressed ('0')
the result was a blank %CPU column. In both cases that
distortion would last for one display cycle or until a
user forced a display refresh via some keyboard input.

The original recommendation was trading gettimeofday()
for clock_gettime() using CLOCK_MONOTONIC. But on some
systems that might not be possible, forcing the use of
CLOCK_REALTIME instead. Not only would that complicate
the build system, but it may leave us with minus %CPU.

Another approach was to ensure that elapsed time could
never be negative. Of course, this produced distortion
of %CPU values but it would be proportionally correct.
This wasn't dissimilar to a distortion already present
should the time be adjusted forward or backward within
any 'remaining' top delay intervals. These aberrations
would be avoided with clock_gettime & CLOCK_MONOTONIC,
but that is a less than ideal solution as noted above.

This final solution, which originated down under, will
simply rely on the /proc/uptime seconds, which will be
immune to *any* tampering with the system clock. Thus,
we now have a fix for the distortion we didn't know we
suffered plus a negative %CPU that began this odyssey.

Thanks to:
sk.alvin.x@gmail.com, for the original effort
jcapik@redhat.com, for a heads up on CLOCK_MONOTONIC
csmall-procps@enc.com.au, for the best suggestion of all

Reference(s):
. original post/patch
http://www.freelists.org/post/procps/PATCH-top-use-clock-gettime-instead-of-gettimeofday
. heads up on CLOCK_MONOTONIC
http://www.freelists.org/post/procps/PATCH-top-use-clock-gettime-instead-of-gettimeofday,2
. the final solution
http://www.freelists.org/post/procps/PATCH-top-use-clock-gettime-instead-of-gettimeofday,11

Signed-off-by: Jim Warner <james.warner@comcast.net>
top/top.c

index d7674956050a9860dbb1deac6ac3d079d6c6a577..cbcb1523958c1b900aa23aade2b780941911f83f 100644 (file)
--- a/top/top.c
+++ b/top/top.c
@@ -2518,17 +2518,14 @@ static void procs_hlp (proc_t *this) {
    HST_t *h;
 
    if (!this) {
-      static struct timeval oldtimev;
-      struct timeval timev;
-      struct timezone timez;
+      static double uptime_sav;
+      double uptime_cur;
       float et;
       void *v;
 
-      gettimeofday(&timev, &timez);
-      et = (timev.tv_sec - oldtimev.tv_sec)
-         + (float)(timev.tv_usec - oldtimev.tv_usec) / 1000000.0;
-      oldtimev.tv_sec = timev.tv_sec;
-      oldtimev.tv_usec = timev.tv_usec;
+      uptime(&uptime_cur, NULL);
+      et = uptime_cur - uptime_sav;
+      uptime_sav = uptime_cur;
 
       // if in Solaris mode, adjust our scaling for all cpus
       Frame_etscale = 100.0f / ((float)Hertz * (float)et * (Rc.mode_irixps ? 1 : smp_num_cpus));