Skip to contentSkip to conversation

scheduler changes for v4.5

GIT PULL Ingo Molnar 1 participant 1 message Jan 11, 2016

Subsystems (6)
lore
Share & tools
lore

Ingo Molnar

author maintainer
#0 lore raw

Linus,

Please pull the latest sched-core-for-linus git tree from:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched-core-for-linus

# HEAD: 0905f04eb21fc1c2e690bed5d0418a061d56c225 sched/fair: Fix new task's load avg removed from source CPU in wake_up_new_task()

The main changes in this cycle were:

- tickless load average calculation enhancements (Byungchul Park)

- vtime handling enhancements (Frederic Weisbecker)

- scalability improvement via properly aligning a key structure field (Jiri Olsa)

- various stop_machine() fixes (Oleg Nesterov)

- sched/numa enhancement (Rik van Riel)

- various fixes and improvements (Andi Kleen, Dietmar Eggemann, Geliang Tang, Hiroshi Shimamoto, Joonwoo Park, Peter Zijlstra, Waiman Long, Wanpeng Li, Yuyang Du)

Thanks,

Ingo

------------------>
Andi Kleen (1):

      sched/core: Move the sched_to_prio[] arrays out of line

Byungchul Park (4):
sched/fair: Prepare __update_cpu_load() to handle active tickless sched/fair: Consider missed ticks in NOHZ_FULL in update_cpu_load_nohz() sched/fair: Modify the comment about lock assumptions in migrate_task_rq_fair() sched/fair: Make it possible to account fair load avg consistently

Dietmar Eggemann (1):
sched/fair: Remove empty idle enter and exit functions

Frederic Weisbecker (5):
sched/cputime: Clarify vtime symbols and document them sched/cputime: Correctly handle task guest time on housekeepers sched/cputime: Rename vtime_accounting_enabled() to vtime_accounting_cpu_enabled() sched/cputime: Introduce vtime accounting check for readers sched/cputime: Convert vtime_seqlock to seqcount

Geliang Tang (1):
sched/core: Use list_is_singular() in sched_can_stop_tick()

Hiroshi Shimamoto (1):
sched/cputime: Remove extra cost in task_cputime()

Jiri Olsa (2):
x86/fpu: Properly align size in CHECK_MEMBER_AT_END_OF() macro sched/core: Move sched_entity::avg into separate cache line

Joonwoo Park (1):
sched/core: Fix incorrect wait time and wait count statistics

Oleg Nesterov (8):
stop_machine: Fix possible cpu_stopper_thread() crash
stop_machine: Don't disable preemption in stop_two_cpus()
stop_machine: Make cpu_stop_queue_work() and stop_one_cpu_nowait() return bool
stop_machine: Change stop_one_cpu() to rely on cpu_stop_queue_work()
stop_machine: Change __stop_cpus() to rely on cpu_stop_queue_work()
stop_machine: Kill cpu_stop_done->executed
stop_machine: Shift the 'done != NULL' check from cpu_stop_signal_done() to callers
stop_machine: Clean up the usage of the preemption counter in cpu_stopper_thread()

Peter Zijlstra (2):
sched/wait: Document waitqueue_active()
sched/fair: Clean up the explanation around decaying load update misses

Rik van Riel (1):
sched/numa: Cap PTE scanning overhead to 3% of run time

Waiman Long (3):
sched/fair: Avoid redundant idle_cpu() call in update_sg_lb_stats() sched/fair: Move the cache-hot 'load_avg' variable into its own cacheline sched/fair: Disable the task group load_avg update for the root_task_group

Wanpeng Li (1):
sched/deadline: Fix the earliest_dl.next logic

Yuyang Du (1):
sched/fair: Fix new task's load avg removed from source CPU in wake_up_new_task()

 arch/x86/kernel/fpu/init.c       |  13 +-
 include/linux/context_tracking.h |   4 +-
 include/linux/init_task.h        |   2 +-
 include/linux/sched.h            |  20 ++-
 include/linux/stop_machine.h     |   7 +-
 include/linux/vtime.h            |  25 +++-
 include/linux/wait.h             |  30 ++++
 kernel/fork.c                    |   4 +-
 kernel/sched/auto_group.c        |   2 +-
 kernel/sched/core.c              |  76 +++++++++-
 kernel/sched/cputime.c           |  74 ++++++----
 kernel/sched/deadline.c          |  59 +-------
 kernel/sched/fair.c              | 312 +++++++++++++++++++++++++++------------
 kernel/sched/idle_task.c         |   1 -
 kernel/sched/sched.h             |  68 +++------
 kernel/stop_machine.c            |  84 +++++------
 kernel/time/tick-sched.c         |  10 +-
 17 files changed, 485 insertions(+), 306 deletions(-)
arch/x86/kernel/fpu/init.c +11 -2
index be39b5fde4b9..8e839e7f5e2f 100644
@@ -143,9 +143,18 @@ static void __init fpu__init_system_generic(void)
 unsigned int xstate_size;
 EXPORT_SYMBOL_GPL(xstate_size);
 
-/* Enforce that 'MEMBER' is the last field of 'TYPE': */
+/* Get alignment of the TYPE. */
+#define TYPE_ALIGN(TYPE) offsetof(struct { char x; TYPE test; }, test)
+
+/*
+ * Enforce that 'MEMBER' is the last field of 'TYPE'.
+ *
+ * Align the computed size with alignment of the TYPE,
+ * because that's how C aligns structs.
+ */
 #define CHECK_MEMBER_AT_END_OF(TYPE, MEMBER) \
-	BUILD_BUG_ON(sizeof(TYPE) != offsetofend(TYPE, MEMBER))
+	BUILD_BUG_ON(sizeof(TYPE) != ALIGN(offsetofend(TYPE, MEMBER), \
+					   TYPE_ALIGN(TYPE)))
 
 /*
  * We append the 'struct fpu' to the task_struct:
include/linux/context_tracking.h +2 -2
index 68b575afe5f5..d259274238db 100644
@@ -86,7 +86,7 @@ static inline void context_tracking_init(void) { }
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
 static inline void guest_enter(void)
 {
-	if (vtime_accounting_enabled())
+	if (vtime_accounting_cpu_enabled())
 		vtime_guest_enter(current);
 	else
 		current->flags |= PF_VCPU;
@@ -100,7 +100,7 @@ static inline void guest_exit(void)
 	if (context_tracking_is_enabled())
 		__context_tracking_exit(CONTEXT_GUEST);
 
-	if (vtime_accounting_enabled())
+	if (vtime_accounting_cpu_enabled())
 		vtime_guest_exit(current);
 	else
 		current->flags &= ~PF_VCPU;
include/linux/init_task.h +1 -1
index 1c1ff7e4faa4..f2cb8d45513d 100644
@@ -150,7 +150,7 @@ extern struct task_group root_task_group;
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
 # define INIT_VTIME(tsk)						\
-	.vtime_seqlock = __SEQLOCK_UNLOCKED(tsk.vtime_seqlock),	\
+	.vtime_seqcount = SEQCNT_ZERO(tsk.vtime_seqcount),	\
 	.vtime_snap = 0,				\
 	.vtime_snap_whence = VTIME_SYS,
 #else
include/linux/sched.h +14 -6
index fa39434e3fdd..0c0e78102850 100644
@@ -177,9 +177,9 @@ extern void get_iowait_load(unsigned long *nr_waiters, unsigned long *load);
 extern void calc_global_load(unsigned long ticks);
 
 #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
-extern void update_cpu_load_nohz(void);
+extern void update_cpu_load_nohz(int active);
 #else
-static inline void update_cpu_load_nohz(void) { }
+static inline void update_cpu_load_nohz(int active) { }
 #endif
 
 extern unsigned long get_parent_ip(unsigned long addr);
@@ -1268,8 +1268,13 @@ struct sched_entity {
 #endif
 
 #ifdef CONFIG_SMP
-	/* Per entity load average tracking */
-	struct sched_avg	avg;
+	/*
+	 * Per entity load average tracking.
+	 *
+	 * Put into separate cache line so it does not
+	 * collide with read-mostly values above.
+	 */
+	struct sched_avg	avg ____cacheline_aligned_in_smp;
 #endif
 };
 
@@ -1520,11 +1525,14 @@ struct task_struct {
 	cputime_t gtime;
 	struct prev_cputime prev_cputime;
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
-	seqlock_t vtime_seqlock;
+	seqcount_t vtime_seqcount;
 	unsigned long long vtime_snap;
 	enum {
-		VTIME_SLEEPING = 0,
+		/* Task is sleeping or running in a CPU with VTIME inactive */
+		VTIME_INACTIVE = 0,
+		/* Task runs in userspace in a CPU with VTIME active */
 		VTIME_USER,
+		/* Task runs in kernelspace in a CPU with VTIME active */
 		VTIME_SYS,
 	} vtime_snap_whence;
 #endif
include/linux/stop_machine.h +5 -2
index 0e1b1540597a..3cc9632dcc2a 100644
@@ -29,7 +29,7 @@ struct cpu_stop_work {
 
 int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg);
 int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *arg);
-void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
+bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
 			 struct cpu_stop_work *work_buf);
 int stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg);
 int try_stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg);
@@ -65,7 +65,7 @@ static void stop_one_cpu_nowait_workfn(struct work_struct *work)
 	preempt_enable();
 }
 
-static inline void stop_one_cpu_nowait(unsigned int cpu,
+static inline bool stop_one_cpu_nowait(unsigned int cpu,
 				       cpu_stop_fn_t fn, void *arg,
 				       struct cpu_stop_work *work_buf)
 {
@@ -74,7 +74,10 @@ static inline void stop_one_cpu_nowait(unsigned int cpu,
 		work_buf->fn = fn;
 		work_buf->arg = arg;
 		schedule_work(&work_buf->work);
+		return true;
 	}
+
+	return false;
 }
 
 static inline int stop_cpus(const struct cpumask *cpumask,
include/linux/vtime.h +18 -7
index c5165fd256f9..fa2196990f84 100644
@@ -10,16 +10,27 @@
 struct task_struct;
 
 /*
- * vtime_accounting_enabled() definitions/declarations
+ * vtime_accounting_cpu_enabled() definitions/declarations
  */
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
-static inline bool vtime_accounting_enabled(void) { return true; }
+static inline bool vtime_accounting_cpu_enabled(void) { return true; }
 #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
+/*
+ * Checks if vtime is enabled on some CPU. Cputime readers want to be careful
+ * in that case and compute the tickless cputime.
+ * For now vtime state is tied to context tracking. We might want to decouple
+ * those later if necessary.
+ */
 static inline bool vtime_accounting_enabled(void)
 {
-	if (context_tracking_is_enabled()) {
+	return context_tracking_is_enabled();
+}
+
+static inline bool vtime_accounting_cpu_enabled(void)
+{
+	if (vtime_accounting_enabled()) {
 		if (context_tracking_cpu_is_enabled())
 			return true;
 	}
@@ -29,7 +40,7 @@ static inline bool vtime_accounting_enabled(void)
 #endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */
 
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
-static inline bool vtime_accounting_enabled(void) { return false; }
+static inline bool vtime_accounting_cpu_enabled(void) { return false; }
 #endif /* !CONFIG_VIRT_CPU_ACCOUNTING */
 
 
@@ -44,7 +55,7 @@ extern void vtime_task_switch(struct task_struct *prev);
 extern void vtime_common_task_switch(struct task_struct *prev);
 static inline void vtime_task_switch(struct task_struct *prev)
 {
-	if (vtime_accounting_enabled())
+	if (vtime_accounting_cpu_enabled())
 		vtime_common_task_switch(prev);
 }
 #endif /* __ARCH_HAS_VTIME_TASK_SWITCH */
@@ -59,7 +70,7 @@ extern void vtime_account_irq_enter(struct task_struct *tsk);
 extern void vtime_common_account_irq_enter(struct task_struct *tsk);
 static inline void vtime_account_irq_enter(struct task_struct *tsk)
 {
-	if (vtime_accounting_enabled())
+	if (vtime_accounting_cpu_enabled())
 		vtime_common_account_irq_enter(tsk);
 }
 #endif /* __ARCH_HAS_VTIME_ACCOUNT */
@@ -78,7 +89,7 @@ extern void vtime_gen_account_irq_exit(struct task_struct *tsk);
 
 static inline void vtime_account_irq_exit(struct task_struct *tsk)
 {
-	if (vtime_accounting_enabled())
+	if (vtime_accounting_cpu_enabled())
 		vtime_gen_account_irq_exit(tsk);
 }
 
include/linux/wait.h +30 -0
index 513b36f04dfd..d2f4ec7dba7c 100644
@@ -102,6 +102,36 @@ init_waitqueue_func_entry(wait_queue_t *q, wait_queue_func_t func)
 	q->func		= func;
 }
 
+/**
+ * waitqueue_active -- locklessly test for waiters on the queue
+ * @q: the waitqueue to test for waiters
+ *
+ * returns true if the wait list is not empty
+ *
+ * NOTE: this function is lockless and requires care, incorrect usage _will_
+ * lead to sporadic and non-obvious failure.
+ *
+ * Use either while holding wait_queue_head_t::lock or when used for wakeups
+ * with an extra smp_mb() like:
+ *
+ *      CPU0 - waker                    CPU1 - waiter
+ *
+ *                                      for (;;) {
+ *      @cond = true;                     prepare_to_wait(&wq, &wait, state);
+ *      smp_mb();                         // smp_mb() from set_current_state()
+ *      if (waitqueue_active(wq))         if (@cond)
+ *        wake_up(wq);                      break;
+ *                                        schedule();
+ *                                      }
+ *                                      finish_wait(&wq, &wait);
+ *
+ * Because without the explicit smp_mb() it's possible for the
+ * waitqueue_active() load to get hoisted over the @cond store such that we'll
+ * observe an empty wait list while the waiter might not observe @cond.
+ *
+ * Also note that this 'optimization' trades a spin_lock() for an smp_mb(),
+ * which (when the lock is uncontended) are of roughly equal cost.
+ */
 static inline int waitqueue_active(wait_queue_head_t *q)
 {
 	return !list_empty(&q->task_list);
kernel/fork.c +2 -2
index 1155eac61687..291b08cc817b 100644
@@ -1349,9 +1349,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	prev_cputime_init(&p->prev_cputime);
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
-	seqlock_init(&p->vtime_seqlock);
+	seqcount_init(&p->vtime_seqcount);
 	p->vtime_snap = 0;
-	p->vtime_snap_whence = VTIME_SLEEPING;
+	p->vtime_snap_whence = VTIME_INACTIVE;
 #endif
 
 #if defined(SPLIT_RSS_COUNTING)
kernel/sched/auto_group.c +1 -1
index 750ed601ddf7..a5d966cb8891 100644
@@ -212,7 +212,7 @@ int proc_sched_autogroup_set_nice(struct task_struct *p, int nice)
 	ag = autogroup_task_get(p);
 
 	down_write(&ag->lock);
-	err = sched_group_set_shares(ag->tg, prio_to_weight[nice + 20]);
+	err = sched_group_set_shares(ag->tg, sched_prio_to_weight[nice + 20]);
 	if (!err)
 		ag->nice = nice;
 	up_write(&ag->lock);
kernel/sched/core.c +68 -8

154 lines not on this page · raw message

kernel/sched/cputime.c +46 -28

190 lines not on this page · raw message

kernel/sched/deadline.c +7 -52

98 lines not on this page · raw message

kernel/sched/fair.c +216 -96

483 lines not on this page · raw message

kernel/sched/idle_task.c +0 -1
index c4ae0f1fdf9b..47ce94931f1b 100644
@@ -47,7 +47,6 @@ dequeue_task_idle(struct rq *rq, struct task_struct *p, int flags)
 
 static void put_prev_task_idle(struct rq *rq, struct task_struct *prev)
 {
-	idle_exit_fair(rq);
 	rq_last_tick_reset(rq);
 }
 
kernel/sched/sched.h +18 -50

100 lines not on this page · raw message

kernel/stop_machine.c +41 -43

182 lines not on this page · raw message

kernel/time/tick-sched.c +5 -5
index 7c7ec4515983..11ce59916c1a 100644
@@ -694,11 +694,11 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
 	return tick;
 }
 
-static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now)
+static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now, int active)
 {
 	/* Update jiffies first */
 	tick_do_update_jiffies64(now);
-	update_cpu_load_nohz();
+	update_cpu_load_nohz(active);
 
 	calc_load_exit_idle();
 	touch_softlockup_watchdog();
@@ -725,7 +725,7 @@ static void tick_nohz_full_update_tick(struct tick_sched *ts)
 	if (can_stop_full_tick())
 		tick_nohz_stop_sched_tick(ts, ktime_get(), cpu);
 	else if (ts->tick_stopped)
-		tick_nohz_restart_sched_tick(ts, ktime_get());
+		tick_nohz_restart_sched_tick(ts, ktime_get(), 1);
 #endif
 }
 
@@ -875,7 +875,7 @@ static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
 	unsigned long ticks;
 
-	if (vtime_accounting_enabled())
+	if (vtime_accounting_cpu_enabled())
 		return;
 	/*
 	 * We stopped the tick in idle. Update process times would miss the
@@ -916,7 +916,7 @@ void tick_nohz_idle_exit(void)
 		tick_nohz_stop_idle(ts, now);
 
 	if (ts->tick_stopped) {
-		tick_nohz_restart_sched_tick(ts, now);
+		tick_nohz_restart_sched_tick(ts, now, 0);
 		tick_nohz_account_idle_ticks(ts);
 	}