aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Barach <dave@barachs.net>2019-12-01 08:59:03 -0500
committerAndrew Yourtchenko <ayourtch@gmail.com>2020-02-06 12:30:08 +0000
commit520c355b86fba01a65593c8c026373a36c87acc6 (patch)
tree98b9020b0f30da9924f63d3f650fc28cadecd753
parent5b2eea6e0705b7e8f8b77f0efe6535885717cbee (diff)
vppinfra: preserve total_cpu_time across clock freq adjustment
If clib_time_verify_frequency() adjusts the clock frequency, transform total_cpu_time to the new time coordinate space. Otherwise, we break comparisons with previous clib_time_now() value. Without this correction, time jumps in one direction or the other depending on the sign of the frequency change. Reasonably harmless in most cases, but under perfect storm conditions the wheels fall off. Type: fix Signed-off-by: Dave Barach <dave@barachs.net> Change-Id: I21802c2630e2c87ff817cd732b7d78bc022cd2d7 (cherry picked from commit e52d8d880ac644f07154bc2fb94035a198ed6688)
-rw-r--r--src/vppinfra/time.c17
-rw-r--r--src/vppinfra/time.h4
2 files changed, 17 insertions, 4 deletions
diff --git a/src/vppinfra/time.c b/src/vppinfra/time.c
index dee50024975..bfc48ce0671 100644
--- a/src/vppinfra/time.c
+++ b/src/vppinfra/time.c
@@ -198,6 +198,7 @@ clib_time_verify_frequency (clib_time_t * c)
f64 dtr_max;
u64 dtc = c->last_cpu_time - c->last_verify_cpu_time;
f64 new_clocks_per_second, delta;
+ f64 save_total_cpu_time_in_seconds;
c->last_verify_cpu_time = c->last_cpu_time;
c->last_verify_reference_time = now_reference;
@@ -239,10 +240,12 @@ clib_time_verify_frequency (clib_time_t * c)
flt_round_nearest ((f64) dtc / (dtr * c->round_to_units))
* c->round_to_units;
+ /* Compute abs(rate change) */
delta = new_clocks_per_second - c->clocks_per_second;
if (delta < 0.0)
delta = -delta;
+ /* If rate change > 1%, reject it and try again */
if (PREDICT_FALSE ((delta / c->clocks_per_second) > .01))
{
clib_warning ("Rejecting large frequency change of %.2f%%",
@@ -251,11 +254,19 @@ clib_time_verify_frequency (clib_time_t * c)
return;
}
- c->clocks_per_second =
- flt_round_nearest ((f64) dtc / (dtr * c->round_to_units))
- * c->round_to_units;
+ /* Save total cpu time in seconds */
+ save_total_cpu_time_in_seconds = c->total_cpu_time * c->seconds_per_clock;
+
+ /* Recalculate clock rate */
+ c->clocks_per_second = new_clocks_per_second;
c->seconds_per_clock = 1 / c->clocks_per_second;
+ /*
+ * Restore total cpu time in seconds. Otherwise, if c->clocks_per_second
+ * has decreased, time may appear to flow backwards.
+ */
+ c->total_cpu_time = save_total_cpu_time_in_seconds * c->clocks_per_second;
+
/* Double time between verifies; max at 64 secs ~ 1 minute. */
if (c->log2_clocks_per_frequency_verify < c->log2_clocks_per_second + 6)
c->log2_clocks_per_frequency_verify += 1;
diff --git a/src/vppinfra/time.h b/src/vppinfra/time.h
index ae738db1307..b2d749256d3 100644
--- a/src/vppinfra/time.h
+++ b/src/vppinfra/time.h
@@ -205,14 +205,16 @@ clib_time_now_internal (clib_time_t * c, u64 n)
{
u64 l = c->last_cpu_time;
u64 t = c->total_cpu_time;
+ f64 rv;
t += n - l;
c->total_cpu_time = t;
c->last_cpu_time = n;
+ rv = t * c->seconds_per_clock;
if (PREDICT_FALSE
((c->last_cpu_time -
c->last_verify_cpu_time) >> c->log2_clocks_per_frequency_verify))
clib_time_verify_frequency (c);
- return t * c->seconds_per_clock;
+ return rv;
}
/* Maximum f64 value as max clib_time */