summaryrefslogtreecommitdiff
path: root/include/linux/timer.h
diff options
context:
space:
mode:
authorJoonwoo Park <joonwoop@codeaurora.org>2015-05-26 12:44:42 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 21:10:48 -0700
commit646bf5125d202df5357b7c922f06c91ea07d07b4 (patch)
tree11d6593f484172265c553f9aab8266f40f5cdd8a /include/linux/timer.h
parent8b72bf241cb3beefdb20327ac7fe8cd1a981db71 (diff)
timer: make deferrable cpu unbound timers really not bound to a cpu
When a deferrable work (INIT_DEFERRABLE_WORK, etc.) is queued via queue_delayed_work() it's probably intended to run the work item on any CPU that isn't idle. However, we queue the work to run at a later time by starting a deferrable timer that binds to whatever CPU the work is queued on which is same with queue_delayed_work_on(smp_processor_id()) effectively. As a result WORK_CPU_UNBOUND work items aren't really cpu unbound now. In fact this is perfectly fine with UP kernel and also won't affect much a system without dyntick with SMP kernel too as every cpus run timers periodically. But on SMP systems with dyntick current implementation leads deferrable timers not very scalable because the timer's base which has queued the deferrable timer won't wake up till next non-deferrable timer expires even though there are possible other non idle cpus are running which are able to run expired deferrable timers. The deferrable work is a good example of the current implementation's victim like below. INIT_DEFERRABLE_WORK(&dwork, fn); CPU 0 CPU 1 queue_delayed_work(wq, &dwork, HZ); queue_delayed_work_on(WORK_CPU_UNBOUND); ... __mod_timer() -> queues timer to the current cpu's timer base. ... tick_nohz_idle_enter() -> cpu enters idle. A second later cpu 0 is now in idle. cpu 1 exits idle or wasn't in idle so now it's in active but won't cpu 0 won't wake up till next handle cpu unbound deferrable timer non-deferrable timer expires. as it's in cpu 0's timer base. To make all cpu unbound deferrable timers are scalable, introduce a common timer base which is only for cpu unbound deferrable timers to make those are indeed cpu unbound so that can be scheduled by tick_do_timer_cpu. This common timer fixes scalability issue of delayed work and all other cpu unbound deferrable timer using implementations. Change-Id: I8b6c57d8b6445a76fa02a8cb598a8ef22aef7200 CC: Thomas Gleixner <tglx@linutronix.de> CC: John Stultz <john.stultz@linaro.org> CC: Tejun Heo <tj@kernel.org> [joonwoop@codeaurora.org: timer->base replaced with CPU index so get the deferrable timer wheel from lock_timer_base() instead of do_init_timer().] Signed-off-by: Joonwoo Park <joonwoop@codeaurora.org>
Diffstat (limited to 'include/linux/timer.h')
-rw-r--r--include/linux/timer.h3
1 files changed, 3 insertions, 0 deletions
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 61aa61dc410c..7a5602e19e87 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -63,6 +63,7 @@ struct timer_list {
#define TIMER_BASEMASK (TIMER_CPUMASK | TIMER_MIGRATING)
#define TIMER_DEFERRABLE 0x00100000
#define TIMER_IRQSAFE 0x00200000
+#define TIMER_PINNED_ON_CPU 0x00400000
#define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \
.entry = { .next = TIMER_ENTRY_STATIC }, \
@@ -241,6 +242,8 @@ extern enum hrtimer_restart it_real_fn(struct hrtimer *);
#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
#include <linux/sysctl.h>
+extern struct tvec_base tvec_base_deferrable;
+
extern unsigned int sysctl_timer_migration;
int timer_migration_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,