scheduler changes for v4.5
Subsystems (6)
Ingo Molnar
maintainerLinus,
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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); }