Commit c1ad348b authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

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: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Acked-by: default avatarPeter 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: default avatarThomas Gleixner <tglx@linutronix.de>
parent 157d29e1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -386,7 +386,7 @@ static inline int hrtimer_restart(struct hrtimer *timer)
/* Query timers: */
extern ktime_t hrtimer_get_remaining(const struct hrtimer *timer);

extern ktime_t hrtimer_get_next_event(void);
extern u64 hrtimer_get_next_event(void);

/*
 * A timer is active, when it is enqueued into the rbtree or the
+4 −2
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@
#include <linux/debugobjects.h>
#include <linux/bug.h>
#include <linux/compiler.h>
#include <linux/ktime.h>

#include <asm/barrier.h>

extern int rcu_expedited; /* for sysctl */
@@ -1154,9 +1156,9 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
	__kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head))

#if defined(CONFIG_TINY_RCU) || defined(CONFIG_RCU_NOCB_CPU_ALL)
static inline int rcu_needs_cpu(unsigned long *delta_jiffies)
static inline int rcu_needs_cpu(u64 basemono, u64 *nextevt)
{
	*delta_jiffies = ULONG_MAX;
	*nextevt = KTIME_MAX;
	return 0;
}
#endif /* #if defined(CONFIG_TINY_RCU) || defined(CONFIG_RCU_NOCB_CPU_ALL) */
+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@

void rcu_note_context_switch(void);
#ifndef CONFIG_RCU_NOCB_CPU_ALL
int rcu_needs_cpu(unsigned long *delta_jiffies);
int rcu_needs_cpu(u64 basem, u64 *nextevt);
#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
void rcu_cpu_stall_reset(void);

+0 −7
Original line number Diff line number Diff line
@@ -187,13 +187,6 @@ extern void set_timer_slack(struct timer_list *time, int slack_hz);
 */
#define NEXT_TIMER_MAX_DELTA	((1UL << 30) - 1)

/*
 * Return when the next timer-wheel timeout occurs (in absolute jiffies),
 * locks the timer base and does the comparison against the given
 * jiffie.
 */
extern unsigned long get_next_timer_interrupt(unsigned long now);

/*
 * Timer-statistics info:
 */
+8 −6
Original line number Diff line number Diff line
@@ -1368,9 +1368,9 @@ static void rcu_prepare_kthreads(int cpu)
 * any flavor of RCU.
 */
#ifndef CONFIG_RCU_NOCB_CPU_ALL
int rcu_needs_cpu(unsigned long *delta_jiffies)
int rcu_needs_cpu(u64 basemono, u64 *nextevt)
{
	*delta_jiffies = ULONG_MAX;
	*nextevt = KTIME_MAX;
	return rcu_cpu_has_callbacks(NULL);
}
#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
@@ -1481,16 +1481,17 @@ static bool __maybe_unused rcu_try_advance_all_cbs(void)
 * The caller must have disabled interrupts.
 */
#ifndef CONFIG_RCU_NOCB_CPU_ALL
int rcu_needs_cpu(unsigned long *dj)
int rcu_needs_cpu(u64 basemono, u64 *nextevt)
{
	struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);
	unsigned long dj;

	/* Snapshot to detect later posting of non-lazy callback. */
	rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted;

	/* If no callbacks, RCU doesn't need the CPU. */
	if (!rcu_cpu_has_callbacks(&rdtp->all_lazy)) {
		*dj = ULONG_MAX;
		*nextevt = KTIME_MAX;
		return 0;
	}

@@ -1504,11 +1505,12 @@ int rcu_needs_cpu(unsigned long *dj)

	/* Request timer delay depending on laziness, and round. */
	if (!rdtp->all_lazy) {
		*dj = round_up(rcu_idle_gp_delay + jiffies,
		dj = round_up(rcu_idle_gp_delay + jiffies,
			       rcu_idle_gp_delay) - jiffies;
	} else {
		*dj = round_jiffies(rcu_idle_lazy_gp_delay + jiffies) - jiffies;
		dj = round_jiffies(rcu_idle_lazy_gp_delay + jiffies) - jiffies;
	}
	*nextevt = basemono + dj * TICK_NSEC;
	return 0;
}
#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
Loading