diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2015-04-14 17:08:58 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2015-04-22 11:06:50 -0400 |
commit | c1ad348b452aacd784fb97403d03d71723c72ee1 (patch) | |
tree | 8f57456095d7125463a9647701acfe24b9d96ffc /kernel/time/timer.c | |
parent | 157d29e101c7d032e886df067aeea1b21a366cc5 (diff) |
tick: Nohz: Rework next timer evaluation
The evaluation of the next timer in the nohz code is based on jiffies
while all the tick internals are nano seconds based. We have also to
convert hrtimer nanoseconds to jiffies in the !highres case. That's
just wrong and introduces interesting corner cases.
Turn it around and convert the next timer wheel timer expiry and the
rcu event to clock monotonic and base all calculations on
nanoseconds. That identifies the case where no timer is pending
clearly with an absolute expiry value of KTIME_MAX.
Makes the code more readable and gets rid of the jiffies magic in the
nohz code.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Preeti U Murthy <preeti@linux.vnet.ibm.com>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Josh Triplett <josh@joshtriplett.org>
Cc: Lai Jiangshan <laijs@cn.fujitsu.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Link: http://lkml.kernel.org/r/20150414203502.184198593@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time/timer.c')
-rw-r--r-- | kernel/time/timer.c | 71 |
1 files changed, 34 insertions, 37 deletions
diff --git a/kernel/time/timer.c b/kernel/time/timer.c index b31f13f4fe41..172b83cd2f8e 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c | |||
@@ -49,6 +49,8 @@ | |||
49 | #include <asm/timex.h> | 49 | #include <asm/timex.h> |
50 | #include <asm/io.h> | 50 | #include <asm/io.h> |
51 | 51 | ||
52 | #include "tick-internal.h" | ||
53 | |||
52 | #define CREATE_TRACE_POINTS | 54 | #define CREATE_TRACE_POINTS |
53 | #include <trace/events/timer.h> | 55 | #include <trace/events/timer.h> |
54 | 56 | ||
@@ -1311,54 +1313,48 @@ cascade: | |||
1311 | * Check, if the next hrtimer event is before the next timer wheel | 1313 | * Check, if the next hrtimer event is before the next timer wheel |
1312 | * event: | 1314 | * event: |
1313 | */ | 1315 | */ |
1314 | static unsigned long cmp_next_hrtimer_event(unsigned long now, | 1316 | static u64 cmp_next_hrtimer_event(u64 basem, u64 expires) |
1315 | unsigned long expires) | ||
1316 | { | 1317 | { |
1317 | ktime_t hr_delta = hrtimer_get_next_event(); | 1318 | u64 nextevt = hrtimer_get_next_event(); |
1318 | struct timespec tsdelta; | ||
1319 | unsigned long delta; | ||
1320 | |||
1321 | if (hr_delta.tv64 == KTIME_MAX) | ||
1322 | return expires; | ||
1323 | 1319 | ||
1324 | /* | 1320 | /* |
1325 | * Expired timer available, let it expire in the next tick | 1321 | * If high resolution timers are enabled |
1322 | * hrtimer_get_next_event() returns KTIME_MAX. | ||
1326 | */ | 1323 | */ |
1327 | if (hr_delta.tv64 <= 0) | 1324 | if (expires <= nextevt) |
1328 | return now + 1; | 1325 | return expires; |
1329 | |||
1330 | tsdelta = ktime_to_timespec(hr_delta); | ||
1331 | delta = timespec_to_jiffies(&tsdelta); | ||
1332 | 1326 | ||
1333 | /* | 1327 | /* |
1334 | * Limit the delta to the max value, which is checked in | 1328 | * If the next timer is already expired, return the tick base |
1335 | * tick_nohz_stop_sched_tick(): | 1329 | * time so the tick is fired immediately. |
1336 | */ | 1330 | */ |
1337 | if (delta > NEXT_TIMER_MAX_DELTA) | 1331 | if (nextevt <= basem) |
1338 | delta = NEXT_TIMER_MAX_DELTA; | 1332 | return basem; |
1339 | 1333 | ||
1340 | /* | 1334 | /* |
1341 | * Take rounding errors in to account and make sure, that it | 1335 | * Round up to the next jiffie. High resolution timers are |
1342 | * expires in the next tick. Otherwise we go into an endless | 1336 | * off, so the hrtimers are expired in the tick and we need to |
1343 | * ping pong due to tick_nohz_stop_sched_tick() retriggering | 1337 | * make sure that this tick really expires the timer to avoid |
1344 | * the timer softirq | 1338 | * a ping pong of the nohz stop code. |
1339 | * | ||
1340 | * Use DIV_ROUND_UP_ULL to prevent gcc calling __divdi3 | ||
1345 | */ | 1341 | */ |
1346 | if (delta < 1) | 1342 | return DIV_ROUND_UP_ULL(nextevt, TICK_NSEC) * TICK_NSEC; |
1347 | delta = 1; | ||
1348 | now += delta; | ||
1349 | if (time_before(now, expires)) | ||
1350 | return now; | ||
1351 | return expires; | ||
1352 | } | 1343 | } |
1353 | 1344 | ||
1354 | /** | 1345 | /** |
1355 | * get_next_timer_interrupt - return the jiffy of the next pending timer | 1346 | * get_next_timer_interrupt - return the time (clock mono) of the next timer |
1356 | * @now: current time (in jiffies) | 1347 | * @basej: base time jiffies |
1348 | * @basem: base time clock monotonic | ||
1349 | * | ||
1350 | * Returns the tick aligned clock monotonic time of the next pending | ||
1351 | * timer or KTIME_MAX if no timer is pending. | ||
1357 | */ | 1352 | */ |
1358 | unsigned long get_next_timer_interrupt(unsigned long now) | 1353 | u64 get_next_timer_interrupt(unsigned long basej, u64 basem) |
1359 | { | 1354 | { |
1360 | struct tvec_base *base = __this_cpu_read(tvec_bases); | 1355 | struct tvec_base *base = __this_cpu_read(tvec_bases); |
1361 | unsigned long expires = now + NEXT_TIMER_MAX_DELTA; | 1356 | u64 expires = KTIME_MAX; |
1357 | unsigned long nextevt; | ||
1362 | 1358 | ||
1363 | /* | 1359 | /* |
1364 | * Pretend that there is no timer pending if the cpu is offline. | 1360 | * Pretend that there is no timer pending if the cpu is offline. |
@@ -1371,14 +1367,15 @@ unsigned long get_next_timer_interrupt(unsigned long now) | |||
1371 | if (base->active_timers) { | 1367 | if (base->active_timers) { |
1372 | if (time_before_eq(base->next_timer, base->timer_jiffies)) | 1368 | if (time_before_eq(base->next_timer, base->timer_jiffies)) |
1373 | base->next_timer = __next_timer_interrupt(base); | 1369 | base->next_timer = __next_timer_interrupt(base); |
1374 | expires = base->next_timer; | 1370 | nextevt = base->next_timer; |
1371 | if (time_before_eq(nextevt, basej)) | ||
1372 | expires = basem; | ||
1373 | else | ||
1374 | expires = basem + (nextevt - basej) * TICK_NSEC; | ||
1375 | } | 1375 | } |
1376 | spin_unlock(&base->lock); | 1376 | spin_unlock(&base->lock); |
1377 | 1377 | ||
1378 | if (time_before_eq(expires, now)) | 1378 | return cmp_next_hrtimer_event(basem, expires); |
1379 | return now; | ||
1380 | |||
1381 | return cmp_next_hrtimer_event(now, expires); | ||
1382 | } | 1379 | } |
1383 | #endif | 1380 | #endif |
1384 | 1381 | ||