time: Run deferrable timers on other CPUs when tick_do_timer_cpu is busy

The deferrable timers processing is done by the tick_do_timer_cpu. If
softirqs are deferred to the ksoftirqd task on this CPU, it may take longer
time to process the deferrable timers under heavy load scenarios. Allow
deferrable timers to be processed on other CPUs when ksoftirqd is active
on the tick_do_timer_cpu.

Change-Id: Ic7b39415b5efd3239a28e41460708a3bcfdb47b2
Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
This commit is contained in:
Pavankumar Kondeti
2018-01-26 19:26:12 +05:30
parent d81364676b
commit 4fe122d73b
2 changed files with 32 additions and 4 deletions

View File

@@ -14,6 +14,7 @@
#include <linux/hrtimer.h>
#include <linux/kref.h>
#include <linux/workqueue.h>
#include <linux/sched.h>
#include <linux/atomic.h>
#include <asm/ptrace.h>
@@ -498,6 +499,13 @@ static inline struct task_struct *this_cpu_ksoftirqd(void)
return this_cpu_read(ksoftirqd);
}
static inline bool ksoftirqd_running_on(int cpu)
{
struct task_struct *tsk = per_cpu(ksoftirqd, cpu);
return tsk && (tsk->state == TASK_RUNNING);
}
/* Tasklets --- multithreaded analogue of BHs.
Main feature differing them of generic softirqs: tasklet

View File

@@ -208,7 +208,6 @@ struct timer_base {
static DEFINE_PER_CPU(struct timer_base, timer_bases[NR_BASES]);
struct timer_base timer_base_deferrable;
static atomic_t deferrable_pending;
#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
unsigned int sysctl_timer_migration = 1;
@@ -1489,6 +1488,8 @@ static u64 cmp_next_hrtimer_event(u64 basem, u64 expires)
#ifdef CONFIG_SMP
static atomic_t deferrable_pending;
/*
* check_pending_deferrable_timers - Check for unbound deferrable timer expiry
* @cpu - Current CPU
@@ -1669,6 +1670,27 @@ static inline void __run_timers(struct timer_base *base)
spin_unlock_irq(&base->lock);
}
#ifdef CONFIG_SMP
static inline bool should_this_cpu_run_deferrable_timers(void)
{
int tick_cpu = READ_ONCE(tick_do_timer_cpu);
if (atomic_cmpxchg(&deferrable_pending, 1, 0) &&
tick_cpu == TICK_DO_TIMER_NONE)
return true;
if (tick_cpu == smp_processor_id())
return true;
return (tick_cpu >= 0 && ksoftirqd_running_on(tick_cpu));
}
#else
static inline bool should_this_cpu_run_deferrable_timers(void)
{
return true;
}
#endif
/*
* This function runs timers and the timer-tq in bottom half context.
*/
@@ -1693,9 +1715,7 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h)
if (IS_ENABLED(CONFIG_NO_HZ_COMMON))
__run_timers(this_cpu_ptr(&timer_bases[BASE_DEF]));
if ((atomic_cmpxchg(&deferrable_pending, 1, 0) &&
tick_do_timer_cpu == TICK_DO_TIMER_NONE) ||
tick_do_timer_cpu == smp_processor_id())
if (should_this_cpu_run_deferrable_timers())
__run_timers(&timer_base_deferrable);
}