Commit d550e81d authored by Paul E. McKenney's avatar Paul E. McKenney

timers: Reduce __run_timers() latency for empty list

The __run_timers() function currently steps through the list one jiffy at
a time in order to update the timer wheel.  However, if the timer wheel
is empty, no adjustment is needed other than updating ->timer_jiffies.
In this case, which is likely to be common for NO_HZ_FULL kernels, the
kernel currently incurs a large latency for no good reason.  This commit
therefore short-circuits this case.
Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: default avatarJosh Triplett <josh@joshtriplett.org>
Acked-by: default avatarPeter Zijlstra <peterz@infradead.org>
Reviewed-by: default avatarOleg Nesterov <oleg@redhat.com>
Reviewed-by: default avatarSteven Rostedt <rostedt@goodmis.org>
Tested-by: default avatarMike Galbraith <bitbucket@online.de>
parent fff42158
...@@ -338,6 +338,20 @@ void set_timer_slack(struct timer_list *timer, int slack_hz) ...@@ -338,6 +338,20 @@ void set_timer_slack(struct timer_list *timer, int slack_hz)
} }
EXPORT_SYMBOL_GPL(set_timer_slack); EXPORT_SYMBOL_GPL(set_timer_slack);
/*
* If the list is empty, catch up ->timer_jiffies to the current time.
* The caller must hold the tvec_base lock. Returns true if the list
* was empty and therefore ->timer_jiffies was updated.
*/
static bool catchup_timer_jiffies(struct tvec_base *base)
{
if (!base->all_timers) {
base->timer_jiffies = jiffies;
return true;
}
return false;
}
static void static void
__internal_add_timer(struct tvec_base *base, struct timer_list *timer) __internal_add_timer(struct tvec_base *base, struct timer_list *timer)
{ {
...@@ -1150,6 +1164,10 @@ static inline void __run_timers(struct tvec_base *base) ...@@ -1150,6 +1164,10 @@ static inline void __run_timers(struct tvec_base *base)
struct timer_list *timer; struct timer_list *timer;
spin_lock_irq(&base->lock); spin_lock_irq(&base->lock);
if (catchup_timer_jiffies(base)) {
spin_unlock_irq(&base->lock);
return;
}
while (time_after_eq(jiffies, base->timer_jiffies)) { while (time_after_eq(jiffies, base->timer_jiffies)) {
struct list_head work_list; struct list_head work_list;
struct list_head *head = &work_list; struct list_head *head = &work_list;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment