diff mbox series

[RFC] time: Fix ktime_get_raw() issues caused by incorrect base accumulation

Message ID 1503701824-1645-1-git-send-email-john.stultz@linaro.org
State Accepted
Commit 0bcdc0987cce9880436b70836c6a92bb8e744fd1
Headers show
Series [RFC] time: Fix ktime_get_raw() issues caused by incorrect base accumulation | expand

Commit Message

John Stultz Aug. 25, 2017, 10:57 p.m. UTC
In commit fc6eead7c1e2 ("time: Clean up CLOCK_MONOTONIC_RAW time
handling"), I mistakenly added the following:

 /* Update the monotonic raw base */
 seconds = tk->raw_sec;
 nsec = (u32)(tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift);
 tk->tkr_raw.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);

Which adds the raw_sec value and the shifted down raw xtime_nsec
to the base value.

This is problematic as when calling ktime_get_raw(), we add the
tk->tkr_raw.xtime_nsec and current offset, shift it down and add
it to the raw base.

This results in the shifted down tk->tkr_raw.xtime_nsec being
added twice.

My mistake, was that I was matching the monotonic base logic
above:

 seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);
 nsec = (u32) tk->wall_to_monotonic.tv_nsec;
 tk->tkr_mono.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);

Which adds the wall_to_monotonic.tv_nsec value, but not the
tk->tkr_mono.xtime_nsec value to the base.

The result of this is that ktime_get_raw() users (which are all
internal users) see the raw time move faster then it should
(the rate at which can vary with the current size of
tkr_raw.xtime_nsec), which has resulted in at least problems
with graphics rendering performance.

To fix this, we simplify the tkr_raw.base accumulation to only
accumulate the raw_sec portion, and do not include the
tkr_raw.xtime_nsec portion, which will be added at read time.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Miroslav Lichvar <mlichvar@redhat.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Cc: Prarit Bhargava <prarit@redhat.com>
Cc: Stephen Boyd <stephen.boyd@linaro.org>
Cc: Kevin Brodsky <kevin.brodsky@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Daniel Mentz <danielmentz@google.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reported-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: John Stultz <john.stultz@linaro.org>

---
 kernel/time/timekeeping.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

-- 
2.7.4

Comments

Chris Wilson Aug. 26, 2017, 10:20 a.m. UTC | #1
Quoting John Stultz (2017-08-25 23:57:04)
> In commit fc6eead7c1e2 ("time: Clean up CLOCK_MONOTONIC_RAW time

> handling"), I mistakenly added the following:

> 

>  /* Update the monotonic raw base */

>  seconds = tk->raw_sec;

>  nsec = (u32)(tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift);

>  tk->tkr_raw.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);

> 

> Which adds the raw_sec value and the shifted down raw xtime_nsec

> to the base value.

> 

> This is problematic as when calling ktime_get_raw(), we add the

> tk->tkr_raw.xtime_nsec and current offset, shift it down and add

> it to the raw base.

> 

> This results in the shifted down tk->tkr_raw.xtime_nsec being

> added twice.

> 

> My mistake, was that I was matching the monotonic base logic

> above:

> 

>  seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);

>  nsec = (u32) tk->wall_to_monotonic.tv_nsec;

>  tk->tkr_mono.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);

> 

> Which adds the wall_to_monotonic.tv_nsec value, but not the

> tk->tkr_mono.xtime_nsec value to the base.

> 

> The result of this is that ktime_get_raw() users (which are all

> internal users) see the raw time move faster then it should

> (the rate at which can vary with the current size of

> tkr_raw.xtime_nsec), which has resulted in at least problems

> with graphics rendering performance.

> 

> To fix this, we simplify the tkr_raw.base accumulation to only

> accumulate the raw_sec portion, and do not include the

> tkr_raw.xtime_nsec portion, which will be added at read time.


This fixes our testcase of using ktime_get_raw() deltas. Thanks,
Tested-by: Chris Wilson <chris@chris-wilson.co.uk>

-Chris
diff mbox series

Patch

diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index cedafa0..7e7e61c 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -637,9 +637,7 @@  static inline void tk_update_ktime_data(struct timekeeper *tk)
 	tk->ktime_sec = seconds;
 
 	/* Update the monotonic raw base */
-	seconds = tk->raw_sec;
-	nsec = (u32)(tk->tkr_raw.xtime_nsec >> tk->tkr_raw.shift);
-	tk->tkr_raw.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
+	tk->tkr_raw.base = ns_to_ktime(tk->raw_sec * NSEC_PER_SEC);
 }
 
 /* must hold timekeeper_lock */