sched: Optimize cgroup pick_next_task_fair
Peter Zijlstra
maintainerRFC PATCH 1/1 sched: Optimize cgroup pick_next_task_fair
Since commit 2f36825b1 ("sched: Next buddy hint on sleep and preempt path") it is likely we pick a new task from the same cgroup, doing a put and then set on all intermediate entities is a waste of time, so try to avoid this.
XXX check put_prev_task()'s update_rq_clock() magic..
Compile tested only.. inspired by pjt's fast switch stories.
--- include/linux/sched.h | 4 +- kernel/sched/core.c | 11 ++--- kernel/sched/fair.c | 94 +++++++++++++++++++++++++++++----------------- kernel/sched/idle_task.c | 6 ++- kernel/sched/rt.c | 10 ++++- kernel/sched/stop_task.c | 6 ++- 6 files changed, 85 insertions(+), 46 deletions(-)
include/linux/sched.h +3 -1
@@ -1117,7 +1117,8 @@ struct sched_class {void (*check_preempt_curr) (struct rq *rq,struct task_struct *p,int flags); -struct task_struct * (*pick_next_task) (struct rq *rq); +struct task_struct * (*pick_next_task) (struct rq *rq, +struct task_struct *prev);void (*put_prev_task) (struct rq *rq,struct task_struct *p);#ifdef CONFIG_SMP
@@ -1210,6 +1211,7 @@ struct sched_entity {#endif #ifdef CONFIG_FAIR_GROUP_SCHED +int depth;struct sched_entity *parent;/* rq on which this entity is (to be) queued: */ struct cfs_rq *cfs_rq;
kernel/sched/core.c +5 -6
@@ -3120,7 +3120,7 @@ static void put_prev_task(struct rq *rq, struct task_struct *prev)* Pick up the highest-prio task: */ static inline struct task_struct * -pick_next_task (struct rq *rq) +pick_next_task (struct rq *rq,struct task_struct *prev) {const struct sched_class *class;struct task_struct *p;
@@ -3130,13 +3130,13 @@ pick_next_task(struct rq *rq)* the fair class we can call that function directly: */ if (likely (rq->nr_running == rq->cfs.h_nr_running)) { - p = fair_sched_class.pick_next_task (rq); + p = fair_sched_class.pick_next_task (rq, prev);if (likely (p))return p; }for_each_class (class) { - p = class->pick_next_task (rq); + p = class->pick_next_task (rq, prev);if (p)return p; }
@@ -3197,8 +3197,7 @@ static void __sched __schedule(void)if (unlikely (!rq->nr_running))idle_balance (cpu, rq); -put_prev_task (rq, prev); - next =pick_next_task (rq); + next =pick_next_task (rq, prev);clear_tsk_need_resched (prev); rq->skip_clock_update =0 ;
@@ -5102,7 +5101,7 @@ static void migrate_tasks(unsigned int dead_cpu)if (rq->nr_running ==1 )break ; - next =pick_next_task (rq); + next =pick_next_task (rq,NULL );BUG_ON (!next); next->sched_class->put_prev_task (rq, next);
kernel/sched/fair.c +59 -35
189 lines not on this page · raw message
kernel/sched/idle_task.c +5 -1
@@ -22,8 +22,12 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int flresched_task (rq->idle); } -static struct task_struct *pick_next_task_idle (struct rq *rq) +static struct task_struct * +pick_next_task_idle (struct rq *rq,struct task_struct *prev) { +if (prev) + prev->sched_class->put_prev_task (rq, prev); +schedstat_inc (rq, sched_goidle);calc_load_account_idle (rq);return rq->idle;
kernel/sched/rt.c +8 -2
@@ -1343,9 +1343,15 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq)return p; } -static struct task_struct *pick_next_task_rt (struct rq *rq) +static struct task_struct * +pick_next_task_rt (struct rq *rq,struct task_struct *prev) { -struct task_struct *p =_pick_next_task_rt (rq); +struct task_struct *p; + +if (prev) + prev->sched_class->put_prev_task (rq, prev); + + p =_pick_next_task_rt (rq);/* The running task is never eligible for pushing */ if (p)
kernel/sched/stop_task.c +5 -1
@@ -23,10 +23,14 @@ check_preempt_curr_stop(struct rq *rq, struct task_struct *p, int flags)/* we're never preempted */ } -static struct task_struct *pick_next_task_stop (struct rq *rq) +static struct task_struct * +pick_next_task_stop (struct rq *rq,struct task_struct *prev) {struct task_struct *stop = rq->stop; +if (prev) + prev->sched_class->put_prev_task (rq, prev); +if (stop && stop->on_rq)return stop;
Quoted 4 lines · Peter Zijlstra
Since commit
2f36825b1("sched: Next buddy hint on sleep and preempt path") it is likely we pick a new task from the same cgroup, doing a put and then set on all intermediate entities is a waste of time, so try to avoid this.
Good idea, we need to lose some weight.
Quoted 1 line
XXX check put_prev_task()'s
update_rq_clock()magic..
I made that even more lovable ;-)
kernel/sched/core.c +3 -1
@@ -3175,6 +3175,7 @@ need_resched: }else {deactivate_task (rq, prev,DEQUEUE_SLEEP ); prev->on_rq =0 ; + rq->skip_clock_update =1 ;/* * If a worker went to sleep, notify and ask workqueue
@@ -3200,9 +3201,9 @@ need_resched:put_prev_task (rq, prev); next =pick_next_task (rq);clear_tsk_need_resched (prev); - rq->skip_clock_update =0 ;if (likely (prev != next)) { + rq->skip_clock_update =0 ; rq->nr_switches++; rq->curr = next; ++*switch_count;
@@ -3220,6 +3221,7 @@ need_resched:raw_spin_unlock_irq (&rq->lock);post_schedule (rq); + rq->skip_clock_update =0 ;preempt_enable_no_resched ();if (need_resched ())
Quoted 1 line
Compile tested only.. inspired by pjt's fast switch stories.
I was looking forward to seeing those fast switch patches, nice spot to cut lard.
Quoted 1 line
Not-quite-signed-off-by Peter Zijlstra <[email protected]>
I'll see if I can give it some runtime.
-Mike
Peter Zijlstra
maintainerQuoted 7 lines · Mike Galbraith
Quoted 4 lines · Peter Zijlstra
Since commit
2f36825b1("sched: Next buddy hint on sleep and preempt path") it is likely we pick a new task from the same cgroup, doing a put and then set on all intermediate entities is a waste of time, so try to avoid this.Good idea, we need to lose some weight.
I actually set out to do something else, but then ended up here.. weird how that works ;-)
My initial idea was to try and get rid of the pick_next_entity() downward walk by keeping that data up-to-date when we dequeue/enqueue.
That all got a tad convoluted, I'll have to try it again. Anyway, that ended up needing to rework the put/set stuff, and that part wasn't as bad.
Peter Zijlstra
maintainerQuoted 10 lines · Peter Zijlstra
Since commit
2f36825b1("sched: Next buddy hint on sleep and preempt path") it is likely we pick a new task from the same cgroup, doing a put and then set on all intermediate entities is a waste of time, so try to avoid this.XXX check put_prev_task()'s
update_rq_clock()magic..Compile tested only.. inspired by pjt's fast switch stories.
Not-quite-signed-off-by Peter Zijlstra <[email protected]>
Here's one that actually boots..
---
include/linux/sched.h +3 -1
@@ -1117,7 +1117,8 @@ struct sched_class {void (*check_preempt_curr) (struct rq *rq,struct task_struct *p,int flags); -struct task_struct * (*pick_next_task) (struct rq *rq); +struct task_struct * (*pick_next_task) (struct rq *rq, +struct task_struct *prev);void (*put_prev_task) (struct rq *rq,struct task_struct *p);#ifdef CONFIG_SMP
@@ -1210,6 +1211,7 @@ struct sched_entity {#endif #ifdef CONFIG_FAIR_GROUP_SCHED +int depth;struct sched_entity *parent;/* rq on which this entity is (to be) queued: */ struct cfs_rq *cfs_rq;
kernel/sched/core.c +7 -6
@@ -3119,7 +3119,7 @@ static void put_prev_task(struct rq *rq,* Pick up the highest-prio task: */ static inline struct task_struct * -pick_next_task (struct rq *rq) +pick_next_task (struct rq *rq,struct task_struct *prev) {const struct sched_class *class;struct task_struct *p;
@@ -3129,13 +3129,13 @@ pick_next_task(struct rq *rq)* the fair class we can call that function directly: */ if (likely (rq->nr_running == rq->cfs.h_nr_running)) { - p = fair_sched_class.pick_next_task (rq); + p = fair_sched_class.pick_next_task (rq, prev);if (likely (p))return p; }for_each_class (class) { - p = class->pick_next_task (rq); + p = class->pick_next_task (rq, prev);if (p)return p; }
@@ -3196,8 +3196,9 @@ static void __sched __schedule(void)if (unlikely (!rq->nr_running))idle_balance (cpu, rq); -put_prev_task (rq, prev); - next =pick_next_task (rq); +if (prev->on_rq || rq->skip_clock_update <0 ) +update_rq_clock (rq); + next =pick_next_task (rq, prev);clear_tsk_need_resched (prev); rq->skip_clock_update =0 ;
@@ -5101,7 +5102,7 @@ static void migrate_tasks(unsigned int dif (rq->nr_running ==1 )break ; - next =pick_next_task (rq); + next =pick_next_task (rq,NULL );BUG_ON (!next); next->sched_class->put_prev_task (rq, next);
kernel/sched/fair.c +61 -35
191 lines not on this page · raw message
kernel/sched/idle_task.c +5 -1
@@ -22,8 +22,12 @@ static void check_preempt_curr_idle(struresched_task (rq->idle); } -static struct task_struct *pick_next_task_idle (struct rq *rq) +static struct task_struct * +pick_next_task_idle (struct rq *rq,struct task_struct *prev) { +if (prev) + prev->sched_class->put_prev_task (rq, prev); +schedstat_inc (rq, sched_goidle);calc_load_account_idle (rq);return rq->idle;
kernel/sched/rt.c +16 -11
@@ -1321,15 +1321,7 @@ static struct task_struct *_pick_next_ta {struct sched_rt_entity *rt_se;struct task_struct *p; -struct rt_rq *rt_rq; - - rt_rq = &rq->rt; - -if (!rt_rq->rt_nr_running) -return NULL ; - -if (rt_rq_throttled (rt_rq)) -return NULL ; +struct rt_rq *rt_rq = &rq->rt; do { rt_se = pick_next_rt_entity(rq, rt_rq);
@@ -1343,9 +1335,22 @@ static struct task_struct *_pick_next_tareturn p; } -static struct task_struct *pick_next_task_rt (struct rq *rq) +static struct task_struct * +pick_next_task_rt (struct rq *rq,struct task_struct *prev) { -struct task_struct *p =_pick_next_task_rt (rq); +struct task_struct *p; +struct rt_rq *rt_rq = &rq->rt; + +if (!rt_rq->rt_nr_running) +return NULL ; + +if (rt_rq_throttled (rt_rq)) +return NULL ; + +if (prev) + prev->sched_class->put_prev_task (rq, prev); + + p =_pick_next_task_rt (rq);/* The running task is never eligible for pushing */ if (p)
kernel/sched/stop_task.c +7 -2
@@ -23,12 +23,17 @@ check_preempt_curr_stop(struct rq *rq, s/* we're never preempted */ } -static struct task_struct *pick_next_task_stop (struct rq *rq) +static struct task_struct * +pick_next_task_stop (struct rq *rq,struct task_struct *prev) {struct task_struct *stop = rq->stop; -if (stop && stop->on_rq) +if (stop && stop->on_rq) { +if (prev) + prev->sched_class->put_prev_task (rq, prev); +return stop; + }return NULL ; }
Peter Zijlstra
maintainerkernel/sched/fair.c static void check_preempt_wakeup(struct · line 2996
Quoted 2 lines · Peter Zijlstra
kernel/sched/fair.c +2
-0+if (prev && (prev->sched_class != &fair_sched_class || + cfs_rq->nr_running ==1 )) {
this ==1 check is way ugly and a problem that needs addressing. Not putting cfs_rq->curr back in the tree perturbs pick_next_entity()'s view of things.
Probably easiest to pick leftmost and ->curr and go from there, but that's for tomorrow or so.
tip-bot for Peter Zijlstra
merge bot[tip:sched/core] sched/fair: Track cgroup depth
In reply to Peter Zijlstrasched/fair: Track cgroup depth
Commit-ID: fed14d45f945042a15b09de48d7d3d58d9455fc4 Gitweb: http://git.kernel.org/tip/fed14d45f945042a15b09de48d7d3d58d9455fc4 Author: Peter Zijlstra <[email protected]> AuthorDate: Sat, 11 Feb 2012 06:05:00 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 10 Feb 2014 16:17:10 +0100
sched/fair: Track cgroup depth
Track depth in cgroup tree, this is useful for things like find_matching_se() where you need to get to a common parent of two sched entities.
Keeping the depth avoids having to calculate it on the spot, which saves a number of possible cache-misses.
--- include/linux/sched.h | 1 + kernel/sched/fair.c | 47 +++++++++++++++++++++-------------------------- 2 files changed, 22 insertions(+), 26 deletions(-)
include/linux/sched.h +1 -0
@@ -1078,6 +1078,7 @@ struct sched_entity {#endif #ifdef CONFIG_FAIR_GROUP_SCHED +int depth;struct sched_entity *parent;/* rq on which this entity is (to be) queued: */ struct cfs_rq *cfs_rq;
kernel/sched/fair.c +21 -26
109 lines not on this page · raw message
tip-bot for Peter Zijlstra
merge bot[tip:sched/core] sched: Push put_prev_task() into pick_next_task( )
In reply to Peter Zijlstrasched: Push put_prev_task() into pick_next_task()
Commit-ID: 606dba2e289446600a0b68422ed2019af5355c12 Gitweb: http://git.kernel.org/tip/606dba2e289446600a0b68422ed2019af5355c12 Author: Peter Zijlstra <[email protected]> AuthorDate: Sat, 11 Feb 2012 06:05:00 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 10 Feb 2014 16:17:13 +0100
sched: Push put_prev_task() into pick_next_task()
In order to avoid having to do put/set on a whole cgroup hierarchy when we context switch, push the put into pick_next_task() so that both operations are in the same function. Further changes then allow us to possibly optimize away redundant work.
--- kernel/sched/core.c | 21 ++++++++------------- kernel/sched/deadline.c | 5 ++++- kernel/sched/fair.c | 6 +++++- kernel/sched/idle_task.c | 6 +++++- kernel/sched/rt.c | 27 ++++++++++++++++----------- kernel/sched/sched.h | 8 +++++++- kernel/sched/stop_task.c | 16 ++++++++++------ 7 files changed, 55 insertions(+), 34 deletions(-)
kernel/sched/core.c +8 -13
@@ -2579,18 +2579,11 @@ static inline void schedule_debug(struct task_struct *prev)schedstat_inc (this_rq (), sched_count); } -static void put_prev_task (struct rq *rq,struct task_struct *prev) -{ -if (prev->on_rq || rq->skip_clock_update <0 ) -update_rq_clock (rq); - prev->sched_class->put_prev_task (rq, prev); -} -/* * Pick up the highest-prio task: */ static inline struct task_struct * -pick_next_task (struct rq *rq) +pick_next_task (struct rq *rq,struct task_struct *prev) {const struct sched_class *class;struct task_struct *p;
@@ -2600,13 +2593,13 @@ pick_next_task(struct rq *rq)* the fair class we can call that function directly: */ if (likely (rq->nr_running == rq->cfs.h_nr_running)) { - p = fair_sched_class.pick_next_task (rq); + p = fair_sched_class.pick_next_task (rq, prev);if (likely (p))return p; }for_each_class (class) { - p = class->pick_next_task (rq); + p = class->pick_next_task (rq, prev);if (p)return p; }
@@ -2714,8 +2707,10 @@ need_resched: rq->idle_stamp =0 ; } -put_prev_task (rq, prev); - next =pick_next_task (rq); +if (prev->on_rq || rq->skip_clock_update <0 ) +update_rq_clock (rq); + + next =pick_next_task (rq, prev);clear_tsk_need_resched (prev);clear_preempt_need_resched (); rq->skip_clock_update =0 ;
@@ -4748,7 +4743,7 @@ static void migrate_tasks(unsigned int dead_cpu)if (rq->nr_running ==1 )break ; - next =pick_next_task (rq); + next =pick_next_task (rq,NULL );BUG_ON (!next); next->sched_class->put_prev_task (rq, next);
kernel/sched/deadline.c +4 -1
@@ -990,7 +990,7 @@ static struct sched_dl_entity *pick_next_dl_entity(struct rq *rq, return rb_entry(left, struct sched_dl_entity, rb_node); } -struct task_struct *pick_next_task_dl (struct rq *rq) +struct task_struct *pick_next_task_dl (struct rq *rq,struct task_struct *prev) {struct sched_dl_entity *dl_se;struct task_struct *p;
@@ -1001,6 +1001,9 @@ struct task_struct *pick_next_task_dl(struct rq *rq)if (unlikely (!dl_rq->dl_nr_running))return NULL ; +if (prev) + prev->sched_class->put_prev_task (rq, prev); + dl_se =pick_next_dl_entity (rq, dl_rq);BUG_ON (!dl_se);
kernel/sched/fair.c +5 -1
@@ -4655,7 +4655,8 @@ preempt:set_last_buddy (se); } -static struct task_struct *pick_next_task_fair (struct rq *rq) +static struct task_struct * +pick_next_task_fair (struct rq *rq,struct task_struct *prev) {struct task_struct *p;struct cfs_rq *cfs_rq = &rq->cfs;
@@ -4664,6 +4665,9 @@ static struct task_struct *pick_next_task_fair(struct rq *rq)if (!cfs_rq->nr_running)return NULL ; +if (prev) + prev->sched_class->put_prev_task (rq, prev); + do { se = pick_next_entity(cfs_rq); set_next_entity(cfs_rq, se);
kernel/sched/idle_task.c +5 -1
@@ -33,8 +33,12 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int flresched_task (rq->idle); } -static struct task_struct *pick_next_task_idle (struct rq *rq) +static struct task_struct * +pick_next_task_idle (struct rq *rq,struct task_struct *prev) { +if (prev) + prev->sched_class->put_prev_task (rq, prev); +schedstat_inc (rq, sched_goidle);#ifdef CONFIG_SMP /* Trigger the post schedule to do an idle_enter for CFS */
kernel/sched/rt.c +16 -11
@@ -1310,15 +1310,7 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq) {struct sched_rt_entity *rt_se;struct task_struct *p; -struct rt_rq *rt_rq; - - rt_rq = &rq->rt; - -if (!rt_rq->rt_nr_running) -return NULL ; - -if (rt_rq_throttled (rt_rq)) -return NULL ; +struct rt_rq *rt_rq = &rq->rt; do { rt_se = pick_next_rt_entity(rq, rt_rq);
@@ -1332,9 +1324,22 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq)return p; } -static struct task_struct *pick_next_task_rt (struct rq *rq) +static struct task_struct * +pick_next_task_rt (struct rq *rq,struct task_struct *prev) { -struct task_struct *p =_pick_next_task_rt (rq); +struct task_struct *p; +struct rt_rq *rt_rq = &rq->rt; + +if (!rt_rq->rt_nr_running) +return NULL ; + +if (rt_rq_throttled (rt_rq)) +return NULL ; + +if (prev) + prev->sched_class->put_prev_task (rq, prev); + + p =_pick_next_task_rt (rq);/* The running task is never eligible for pushing */ if (p)
kernel/sched/sched.h +7 -1
@@ -1105,7 +1105,13 @@ struct sched_class {void (*check_preempt_curr) (struct rq *rq,struct task_struct *p,int flags); -struct task_struct * (*pick_next_task) (struct rq *rq); +/* +* It is the responsibility of the pick_next_task() method that will +* return the next task to call put_prev_task() on the @prev task or +* something equivalent. +*/ +struct task_struct * (*pick_next_task) (struct rq *rq, +struct task_struct *prev);void (*put_prev_task) (struct rq *rq,struct task_struct *p);#ifdef CONFIG_SMP
kernel/sched/stop_task.c +10 -6
@@ -23,16 +23,20 @@ check_preempt_curr_stop(struct rq *rq, struct task_struct *p, int flags)/* we're never preempted */ } -static struct task_struct *pick_next_task_stop (struct rq *rq) +static struct task_struct * +pick_next_task_stop (struct rq *rq,struct task_struct *prev) {struct task_struct *stop = rq->stop; -if (stop && stop->on_rq) { - stop->se.exec_start =rq_clock_task (rq); -return stop; - } +if (!stop || !stop->on_rq) +return NULL ; -return NULL ; +if (prev) + prev->sched_class->put_prev_task (rq, prev); + + stop->se.exec_start =rq_clock_task (rq); + +return stop; } static void
Re: [tip:sched/core] sched: Push put_prev_task() into pick_next_task( )
11.02.2014, 16:17, "tip-bot for Peter Zijlstra" <[email protected]>:
Quoted 81 lines
Commit-ID: 606dba2e289446600a0b68422ed2019af5355c12
Gitweb: http://git.kernel.org/tip/606dba2e289446600a0b68422ed2019af5355c12
Author: Peter Zijlstra <[email protected]>
AuthorDate: Sat, 11 Feb 2012 06:05:00 +0100
Committer: Ingo Molnar <[email protected]>
CommitDate: Mon, 10 Feb 2014 16:17:13 +0100sched: Push
put_prev_task()intopick_next_task()In order to avoid having to do put/set on a whole cgroup hierarchy when we context switch, push the put into
pick_next_task()so that both operations are in the same function. Further changes then allow us to possibly optimize away redundant work.Signed-off-by Peter Zijlstra <[email protected]>Signed-off-by Ingo Molnar <[email protected]>---
kernel/sched/core.c | 21 ++++++++-------------kernel/sched/deadline.c| 5 ++++-kernel/sched/fair.c| 6 +++++-kernel/sched/idle_task.c| 6 +++++-kernel/sched/rt.c| 27 ++++++++++++++++-----------kernel/sched/sched.h| 8 +++++++-kernel/sched/stop_task.c| 16 ++++++++++------7 files changed, 55 insertions(+), 34 deletions(-)kernel/sched/core.c +0
-7@@ -2579,18 +2579,11 @@ static inline void schedule_debug(struct task_struct *prev) schedstat_inc(this_rq(), sched_count); } -static void put_prev_task (struct rq *rq,struct task_struct *prev) -{ -if (prev->on_rq || rq->skip_clock_update <0 ) -update_rq_clock (rq); - prev->sched_class->put_prev_task (rq, prev); -} - /** Pick up the highest-prio task: */ static inline struct
task_struct*kernel/sched/core.c +1
-1-pick_next_task(struct rq *rq) +pick_next_task(struct rq *rq, struct task_struct *prev){
const structsched_class*class;
structtask_struct*p;kernel/sched/core.c +6
-4@@ -2600,13 +2593,13 @@ pick_next_task(struct rq *rq)* the fair class we can call that function directly: */ if (likely(rq->nr_running == rq->cfs.h_nr_running)) { - p = fair_sched_class.pick_next_task (rq); + p = fair_sched_class.pick_next_task (rq, prev); if (likely(p)) return p; } for_each_class(class) { - p = class->pick_next_task (rq); + p = class->pick_next_task (rq, prev); if (p) return p; }@@ -2714,8 +2707,10 @@ need_resched: rq->idle_stamp = 0; } -put_prev_task (rq, prev); - next =pick_next_task (rq); +if (prev->on_rq || rq->skip_clock_update <0 ) +update_rq_clock (rq); + + next =pick_next_task (rq, prev); clear_tsk_need_resched(prev); clear_preempt_need_resched(); rq->skip_clock_update = 0;
kernel/sched/core.c static void migrate_tasks(unsigned int dead_cpu) · line 4746
Quoted 5 lines
kernel/sched/core.c +1
-1@@ -4748,7 +4743,7 @@ static void migrate_tasks(unsigned int dead_cpu) if (rq->nr_running == 1) break; - next =pick_next_task (rq); + next =pick_next_task (rq,NULL );
pick_next_task() firstly checks for prev->sched_class, doesn't it ???
The same for pick_next_task_rt().
Quoted 169 lines
kernel/sched/core.c +0
-0BUG_ON(!next); next->sched_class->put_prev_task(rq, next);kernel/sched/deadline.c +4
-1@@ -990,7 +990,7 @@ static struct sched_dl_entity *pick_next_dl_entity(struct rq *rq, return rb_entry(left, struct sched_dl_entity, rb_node); } -struct task_struct *pick_next_task_dl (struct rq *rq) +struct task_struct *pick_next_task_dl (struct rq *rq,struct task_struct *prev) { struct sched_dl_entity *dl_se; struct task_struct *p;@@ -1001,6 +1001,9 @@ struct task_struct *pick_next_task_dl(struct rq *rq) if (unlikely(!dl_rq->dl_nr_running)) return NULL; +if (prev) + prev->sched_class->put_prev_task (rq, prev); + dl_se = pick_next_dl_entity(rq, dl_rq); BUG_ON(!dl_se);kernel/sched/fair.c +5
-1@@ -4655,7 +4655,8 @@ preempt: set_last_buddy(se); } -static struct task_struct *pick_next_task_fair (struct rq *rq) +static struct task_struct * +pick_next_task_fair (struct rq *rq,struct task_struct *prev) { struct task_struct *p; struct cfs_rq *cfs_rq = &rq->cfs;@@ -4664,6 +4665,9 @@ static struct task_struct *pick_next_task_fair(struct rq *rq) if (!cfs_rq->nr_running) return NULL; +if (prev) + prev->sched_class->put_prev_task (rq, prev); + do { se = pick_next_entity(cfs_rq); set_next_entity(cfs_rq, se);kernel/sched/idle_task.c +5
-1@@ -33,8 +33,12 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int fl resched_task(rq->idle); } -static struct task_struct *pick_next_task_idle (struct rq *rq) +static struct task_struct * +pick_next_task_idle (struct rq *rq,struct task_struct *prev) { +if (prev) + prev->sched_class->put_prev_task (rq, prev); + schedstat_inc(rq, sched_goidle); #ifdef CONFIG_SMP /* Trigger the post schedule to do an idle_enter for CFS */kernel/sched/rt.c +16
-11@@ -1310,15 +1310,7 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq) { struct sched_rt_entity *rt_se; struct task_struct *p; -struct rt_rq *rt_rq; - - rt_rq = &rq->rt; - -if (!rt_rq->rt_nr_running) -return NULL ; - -if (rt_rq_throttled (rt_rq)) -return NULL ; + struct rt_rq *rt_rq = &rq->rt; do { rt_se = pick_next_rt_entity(rq, rt_rq);@@ -1332,9 +1324,22 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq) return p; } -static struct task_struct *pick_next_task_rt (struct rq *rq) +static struct task_struct * +pick_next_task_rt (struct rq *rq,struct task_struct *prev) { -struct task_struct *p =_pick_next_task_rt (rq); +struct task_struct *p; +struct rt_rq *rt_rq = &rq->rt; + +if (!rt_rq->rt_nr_running) +return NULL ; + +if (rt_rq_throttled (rt_rq)) +return NULL ; + +if (prev) + prev->sched_class->put_prev_task (rq, prev); + + p =_pick_next_task_rt (rq); /* The running task is never eligible for pushing */ if (p)kernel/sched/sched.h +7
-1@@ -1105,7 +1105,13 @@ struct sched_class { void (*check_preempt_curr) (struct rq *rq, struct task_struct *p, int flags); -struct task_struct * (*pick_next_task) (struct rq *rq); +/* +* It is the responsibility of the pick_next_task() method that will +* return the next task to call put_prev_task() on the @prev task or +* something equivalent. +*/ +struct task_struct * (*pick_next_task) (struct rq *rq, +struct task_struct *prev); void (*put_prev_task) (struct rq *rq, struct task_struct *p); #ifdef CONFIG_SMPkernel/sched/stop_task.c +10
-6@@ -23,16 +23,20 @@ check_preempt_curr_stop(struct rq *rq, struct task_struct *p, int flags) /* we're never preempted */ } -static struct task_struct *pick_next_task_stop (struct rq *rq) +static struct task_struct * +pick_next_task_stop (struct rq *rq,struct task_struct *prev) { struct task_struct *stop = rq->stop; -if (stop && stop->on_rq) { - stop->se.exec_start =rq_clock_task (rq); -return stop; - } +if (!stop || !stop->on_rq) +return NULL ; -return NULL ; +if (prev) + prev->sched_class->put_prev_task (rq, prev); + + stop->se.exec_start =rq_clock_task (rq); + +return stop; }static void
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Peter Zijlstra
maintainerRe: [tip:sched/core] sched: Push put_prev_task() into pick_next_task( )
Quoted 10 lines · Kirill Tkhai
kernel/sched/core.c static void migrate_tasks(unsigned int dead_cpu) · line 4746
Quoted 6 lines
kernel/sched/core.c +1
-1@@ -4748,7 +4743,7 @@ static void migrate_tasks(unsigned int dead_cpu) if (rq->nr_running == 1) break; - next =pick_next_task (rq); + next =pick_next_task (rq,NULL );
pick_next_task()firstly checks forprev->sched_class, doesn't it ???The same for
pick_next_task_rt().
Right you are... and pick_next_task_dl(). Smatch caught the _{rt,dl} ones, it failed to spot this one though.
Peter Zijlstra
maintainerRe: [tip:sched/core] sched: Push put_prev_task() into pick_next_task( )
In reply to Kirill TkhaiQuoted 10 lines · Kirill Tkhai
Review static void migrate_tasks(unsigned int dead_cpu) · line 4746
Quoted 6 lines
(quoted diff) +1
-1@@ -4748,7 +4743,7 @@ static void migrate_tasks(unsigned int dead_cpu) if (rq->nr_running == 1) break; - next = pick_next_task(rq); + next = pick_next_task(rq, NULL);
pick_next_task()firstly checks forprev->sched_class, doesn't it ???The same for
pick_next_task_rt().
OK, how about something like this?
---
Subject: sched: Fix hotplug task migration
From: Peter Zijlstra <[email protected]>
Date: Wed, 12 Feb 2014 10:49:30 +0100
Dan Carpenter reported:
Quoted 2 lines
kernel/sched/rt.c:1347pick_next_task_rt()warn: variable dereferenced before check 'prev' (see line 1338)kernel/sched/deadline.c:1011pick_next_task_dl()warn: variable dereferenced before check 'prev' (see line 1005)
Kirill also spotted that migrate_tasks() will have an instant NULL deref because pick_next_task() will immediately deref prev.
Instead of fixing all the corner cases because migrate_tasks() can pass in a NULL prev task in the unlikely case of hot-un-plug, provide a fake task such that we can remove all the NULL checks from the far more common paths.
A further problem; not previously spotted; is that because we pushed pre_schedule() and idle_balance() into pick_next_task() we now need to avoid those getting called and pulling more tasks on our dying CPU.
We avoid pull_{dl,rt}_task() by setting fake_task.prio to MAX_PRIO+1. We also note that since we call pick_next_task() exactly the amount of times we have runnable tasks present, we should never land in idle_balance().
--- kernel/sched/core.c | 18 +++++++++++++++++- kernel/sched/deadline.c | 3 +-- kernel/sched/fair.c | 5 ++--- kernel/sched/idle_task.c | 3 +-- kernel/sched/rt.c | 3 +-- kernel/sched/stop_task.c | 3 +-- 6 files changed, 23 insertions(+), 12 deletions(-)
kernel/sched/core.c +17 -1
@@ -4681,6 +4681,22 @@ static void calc_load_migrate(struct rqatomic_long_add (delta, &calc_load_tasks); } +static void put_prev_task_fake (struct rq *rq,struct task_struct *prev) +{ +} + +static const struct sched_class fake_sched_class = { + .put_prev_task = put_prev_task_fake, +}; + +static struct task_struct fake_task = { +/* +* Avoid pull_{rt,dl}_task() +*/ + .prio =MAX_PRIO +1 , + .sched_class = &fake_sched_class, +}; +/* * Migrate all tasks from the rq, sleeping tasks will be migrated by * try_to_wake_up()->select_task_rq().
@@ -4721,7 +4737,7 @@ static void migrate_tasks(unsigned int dif (rq->nr_running ==1 )break ; - next =pick_next_task (rq,NULL ); + next =pick_next_task (rq, &fake_task);BUG_ON (!next); next->sched_class->put_prev_task (rq, next);
kernel/sched/deadline.c +1 -2
@@ -1008,8 +1008,7 @@ struct task_struct *pick_next_task_dl(stif (unlikely (!dl_rq->dl_nr_running))return NULL ; -if (prev) - prev->sched_class->put_prev_task (rq, prev); + prev->sched_class->put_prev_task (rq, prev); dl_se =pick_next_dl_entity (rq, dl_rq);BUG_ON (!dl_se);
kernel/sched/fair.c +2 -3
@@ -4690,7 +4690,7 @@ pick_next_task_fair(struct rq *rq, strucif (!cfs_rq->nr_running) goto idle; -if (!prev || prev->sched_class != &fair_sched_class) +if (prev->sched_class != &fair_sched_class) goto simple;/*
@@ -4766,8 +4766,7 @@ pick_next_task_fair(struct rq *rq, strucif (!cfs_rq->nr_running) goto idle; -if (prev) - prev->sched_class->put_prev_task (rq, prev); + prev->sched_class->put_prev_task (rq, prev); do { se = pick_next_entity(cfs_rq, NULL);
kernel/sched/idle_task.c +1 -2
@@ -26,8 +26,7 @@ static void check_preempt_curr_idle(strustatic struct task_struct *pick_next_task_idle (struct rq *rq,struct task_struct *prev) { -if (prev) - prev->sched_class->put_prev_task (rq, prev); + prev->sched_class->put_prev_task (rq, prev);schedstat_inc (rq, sched_goidle);#ifdef CONFIG_SMP
kernel/sched/rt.c +1 -2
@@ -1344,8 +1344,7 @@ pick_next_task_rt(struct rq *rq, structif (rt_rq_throttled (rt_rq))return NULL ; -if (prev) - prev->sched_class->put_prev_task (rq, prev); + prev->sched_class->put_prev_task (rq, prev); p =_pick_next_task_rt (rq);
kernel/sched/stop_task.c +1 -2
@@ -31,8 +31,7 @@ pick_next_task_stop(struct rq *rq, strucif (!stop || !stop->on_rq)return NULL ; -if (prev) - prev->sched_class->put_prev_task (rq, prev); + prev->sched_class->put_prev_task (rq, prev); stop->se.exec_start =rq_clock_task (rq);
Re: [tip:sched/core] sched: Push put_prev_task() into pick_next_task( )
12.02.2014, 18:06, "Peter Zijlstra" <[email protected]>:
Quoted 6 lines · Kirill Tkhai
Quoted 5 lines
Quoted 5 lines
@@ -4748,7 +4743,7 @@ static void
migrate_tasks(unsigned int dead_cpu)if (rq->nr_running== 1)
break;
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
- next =
pick_next_task(rq);
+ next =pick_next_task(rq, NULL);pick_next_task() firstly checks for
prev->sched_class, doesn't it ???The same for
pick_next_task_rt().OK, how about something like this?
Good for me.
Maybe pack prev->sched_class->put_prev_task() into inline function?
Kirill
Quoted 146 lines
---
Subject: sched: Fix hotplug task migration
From: Peter Zijlstra <[email protected]>
Date: Wed, 12 Feb 2014 10:49:30 +0100Dan Carpenter reported:
Quoted 2 lines
kernel/sched/rt.c:1347
pick_next_task_rt()warn: variable dereferenced before check 'prev' (see line 1338)kernel/sched/deadline.c:1011pick_next_task_dl()warn: variable dereferenced before check 'prev' (see line 1005)Kirill also spotted that
migrate_tasks()will have an instant NULL deref becausepick_next_task()will immediately deref prev.Instead of fixing all the corner cases because
migrate_tasks()can pass in a NULL prev task in the unlikely case of hot-un-plug, provide a fake task such that we can remove all the NULL checks from the far more common paths.A further problem; not previously spotted; is that because we pushed
pre_schedule()andidle_balance()intopick_next_task()we now need to avoid those getting called and pulling more tasks on our dying CPU.We avoid pull_{dl,rt}_task() by setting fake_task.prio to MAX_PRIO+1. We also note that since we call
pick_next_task()exactly the amount of times we have runnable tasks present, we should never land inidle_balance().Fixes 38033c37faab ("sched: Push down pre_schedule() and idle_balance()")Cc Steven Rostedt <[email protected]>Cc Juri Lelli <[email protected]>Cc Ingo Molnar <[email protected]>Reported-by Kirill Tkhai <[email protected]>Reported-by Dan Carpenter <[email protected]>Signed-off-by Peter Zijlstra <[email protected]>---
kernel/sched/core.c | 18 +++++++++++++++++-kernel/sched/deadline.c| 3 +--kernel/sched/fair.c| 5 ++---kernel/sched/idle_task.c| 3 +--kernel/sched/rt.c| 3 +--kernel/sched/stop_task.c| 3 +--6 files changed, 23 insertions(+), 12 deletions(-)kernel/sched/core.c +17
-1@@ -4681,6 +4681,22 @@ static void calc_load_migrate(struct rq atomic_long_add(delta, &calc_load_tasks); } +static void put_prev_task_fake (struct rq *rq,struct task_struct *prev) +{ +} + +static const struct sched_class fake_sched_class = { + .put_prev_task = put_prev_task_fake, +}; + +static struct task_struct fake_task = { +/* +* Avoid pull_{rt,dl}_task() +*/ + .prio =MAX_PRIO +1 , + .sched_class = &fake_sched_class, +}; + /** Migrate all tasks from the rq, sleeping tasks will be migrated by * try_to_wake_up()->select_task_rq(). @@ -4721,7 +4737,7 @@ static void migrate_tasks(unsigned int d if (rq->nr_running == 1) break; - next =pick_next_task (rq,NULL ); + next =pick_next_task (rq, &fake_task); BUG_ON(!next); next->sched_class->put_prev_task(rq, next);kernel/sched/deadline.c +1
-2@@ -1008,8 +1008,7 @@ struct task_struct *pick_next_task_dl(st if (unlikely(!dl_rq->dl_nr_running)) return NULL; -if (prev) - prev->sched_class->put_prev_task (rq, prev); + prev->sched_class->put_prev_task (rq, prev); dl_se = pick_next_dl_entity(rq, dl_rq); BUG_ON(!dl_se);kernel/sched/fair.c +2
-3@@ -4690,7 +4690,7 @@ pick_next_task_fair(struct rq *rq, struc if (!cfs_rq->nr_running) goto idle; -if (!prev || prev->sched_class != &fair_sched_class) +if (prev->sched_class != &fair_sched_class) goto simple; /*@@ -4766,8 +4766,7 @@ pick_next_task_fair(struct rq *rq, struc if (!cfs_rq->nr_running) goto idle; -if (prev) - prev->sched_class->put_prev_task (rq, prev); + prev->sched_class->put_prev_task (rq, prev); do { se = pick_next_entity(cfs_rq, NULL);kernel/sched/idle_task.c +0
-0@@ -26,8 +26,7 @@ static void check_preempt_curr_idle(strustatic struct
task_struct*pick_next_task_idle(struct rq *rq, struct task_struct *prev){
- if (prev)
-prev->sched_class->put_prev_task(rq, prev);
+prev->sched_class->put_prev_task(rq, prev);schedstat_inc(rq,
sched_goidle);
#ifdefCONFIG_SMPkernel/sched/rt.c +1
-2@@ -1344,8 +1344,7 @@ pick_next_task_rt(struct rq *rq, struct if (rt_rq_throttled(rt_rq)) return NULL; -if (prev) - prev->sched_class->put_prev_task (rq, prev); + prev->sched_class->put_prev_task (rq, prev); p = _pick_next_task_rt(rq);kernel/sched/stop_task.c +1
-2@@ -31,8 +31,7 @@ pick_next_task_stop(struct rq *rq, struc if (!stop || !stop->on_rq) return NULL; -if (prev) - prev->sched_class->put_prev_task (rq, prev); + prev->sched_class->put_prev_task (rq, prev); stop->se.exec_start = rq_clock_task(rq);
Peter Zijlstra
maintainerRe: [tip:sched/core] sched: Push put_prev_task() into pick_next_task( )
Quoted 1 line · Kirill Tkhai
Maybe pack
prev->sched_class->put_prev_task()into inline function?
Good suggestion, done.
tip-bot for Peter Zijlstra
merge bot[tip:sched/core] sched/fair: Clean up the __clear_buddies_*() functions
In reply to Peter Zijlstrasched/fair: Clean up the __clear_buddies_*() functions
Commit-ID: f10447998a59b97747c16258a9c6e6a1512f27f3 Gitweb: http://git.kernel.org/tip/f10447998a59b97747c16258a9c6e6a1512f27f3 Author: Peter Zijlstra <[email protected]> AuthorDate: Sat, 11 Feb 2012 06:05:00 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 10 Feb 2014 16:17:16 +0100
sched/fair: Clean up the __clear_buddies_*() functions
Slightly easier code flow, no functional changes.
--- kernel/sched/fair.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
kernel/sched/fair.c +9 -9
@@ -2739,10 +2739,10 @@ static void __clear_buddies_last(struct sched_entity *se) {for_each_sched_entity (se) {struct cfs_rq *cfs_rq =cfs_rq_of (se); -if (cfs_rq->last == se) - cfs_rq->last =NULL ; -else +if (cfs_rq->last != se)break ; + + cfs_rq->last =NULL ; } }
@@ -2750,10 +2750,10 @@ static void __clear_buddies_next(struct sched_entity *se) {for_each_sched_entity (se) {struct cfs_rq *cfs_rq =cfs_rq_of (se); -if (cfs_rq->next == se) - cfs_rq->next =NULL ; -else +if (cfs_rq->next != se)break ; + + cfs_rq->next =NULL ; } }
@@ -2761,10 +2761,10 @@ static void __clear_buddies_skip(struct sched_entity *se) {for_each_sched_entity (se) {struct cfs_rq *cfs_rq =cfs_rq_of (se); -if (cfs_rq->skip == se) - cfs_rq->skip =NULL ; -else +if (cfs_rq->skip != se)break ; + + cfs_rq->skip =NULL ; } }
tip-bot for Peter Zijlstra
merge bot[tip:sched/core] sched/fair: Optimize cgroup pick_next_task_fair( )
In reply to Peter Zijlstrasched/fair: Optimize cgroup pick_next_task_fair()
Commit-ID: 678d5718d8d099421b0dd54c01b0528f4aaf5919 Gitweb: http://git.kernel.org/tip/678d5718d8d099421b0dd54c01b0528f4aaf5919 Author: Peter Zijlstra <[email protected]> AuthorDate: Sat, 11 Feb 2012 06:05:00 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Mon, 10 Feb 2014 16:17:19 +0100
sched/fair: Optimize cgroup pick_next_task_fair()
Since commit 2f36825b1 ("sched: Next buddy hint on sleep and preempt path") it is likely we pick a new task from the same cgroup, doing a put and then set on all intermediate entities is a waste of time, so try to avoid this.
Measured using:
mount nodev /cgroup -t cgroup -o cpu
cd /cgroup
mkdir a; cd a
mkdir b; cd b
mkdir c; cd c
echo $$ > tasks
perf stat --repeat 10 -- taskset 1 perf bench sched pipe
PRE : 4.542422684 seconds time elapsed ( +- 0.33% ) POST: 4.389409991 seconds time elapsed ( +- 0.32% )
Which shows a significant improvement of ~3.5%
--- kernel/sched/fair.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 110 insertions(+), 12 deletions(-)
kernel/sched/fair.c +110 -12
@@ -2907,17 +2907,36 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se);* 3) pick the "last" process, for cache locality * 4) do not run the "skip" process, if something else is available */ -static struct sched_entity *pick_next_entity (struct cfs_rq *cfs_rq) +static struct sched_entity * +pick_next_entity (struct cfs_rq *cfs_rq,struct sched_entity *curr) { -struct sched_entity *se =__pick_first_entity (cfs_rq); -struct sched_entity *left = se; +struct sched_entity *left =__pick_first_entity (cfs_rq); +struct sched_entity *se; + +/* +* If curr is set we have to see if its left of the leftmost entity +* still in the tree, provided there was anything in the tree at all. +*/ +if (!left || (curr &&entity_before (curr, left))) + left = curr; + + se = left;/* ideally we run the leftmost entity */ /* * Avoid running the skip buddy, if running something else can * be done without getting too unfair. */ if (cfs_rq->skip == se) { -struct sched_entity *second =__pick_next_entity (se); +struct sched_entity *second; + +if (se == curr) { + second =__pick_first_entity (cfs_rq); + }else { + second =__pick_next_entity (se); +if (!second || (curr &&entity_before (curr, second))) + second = curr; + } +if (second &&wakeup_preempt_entity (second, left) <1 ) se = second; }
@@ -2939,7 +2958,7 @@ static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)return se; } -static void check_cfs_rq_runtime (struct cfs_rq *cfs_rq); +static bool check_cfs_rq_runtime (struct cfs_rq *cfs_rq);static void put_prev_entity (struct cfs_rq *cfs_rq,struct sched_entity *prev) {
@@ -3594,22 +3613,23 @@ static void check_enqueue_throttle(struct cfs_rq *cfs_rq) }/* conditionally throttle active cfs_rq's from put_prev_entity() */ -static void check_cfs_rq_runtime (struct cfs_rq *cfs_rq) +static bool check_cfs_rq_runtime (struct cfs_rq *cfs_rq) {if (!cfs_bandwidth_used ()) -return ; +return false;if (likely (!cfs_rq->runtime_enabled || cfs_rq->runtime_remaining >0 )) -return ; +return false;/* * it's possible for a throttled entity to be forced into a running * state (e.g. set_curr_task), in this case we're finished. */ if (cfs_rq_throttled (cfs_rq)) -return ; +return true;throttle_cfs_rq (cfs_rq); +return true; }static enum hrtimer_restart sched_cfs_slack_timer (struct hrtimer *timer)
@@ -3719,7 +3739,7 @@ static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq) }static void account_cfs_rq_runtime (struct cfs_rq *cfs_rq,u64 delta_exec) {} -static void check_cfs_rq_runtime (struct cfs_rq *cfs_rq) {} +static bool check_cfs_rq_runtime (struct cfs_rq *cfs_rq) {return false; }static void check_enqueue_throttle (struct cfs_rq *cfs_rq) {} static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq) {}
@@ -4658,9 +4678,86 @@ preempt:static struct task_struct *pick_next_task_fair (struct rq *rq,struct task_struct *prev) { -struct task_struct *p;struct cfs_rq *cfs_rq = &rq->cfs;struct sched_entity *se; +struct task_struct *p; + +#ifdef CONFIG_FAIR_GROUP_SCHED +if (!cfs_rq->nr_running) +return NULL ; + +if (!prev || prev->sched_class != &fair_sched_class) + goto simple; + +/* +* Because of the set_next_buddy() in dequeue_task_fair() it is rather +* likely that a next task is from the same cgroup as the current. +* +* Therefore attempt to avoid putting and setting the entire cgroup +* hierarchy, only change the part that actually changes. +*/ + +do { +struct sched_entity *curr = cfs_rq->curr; + +/* +* Since we got here without doing put_prev_entity() we also +* have to consider cfs_rq->curr. If it is still a runnable +* entity, update_curr() will update its vruntime, otherwise +* forget we've ever seen it. +*/ +if (curr && curr->on_rq) +update_curr (cfs_rq); +else + curr =NULL ; + +/* +* This call to check_cfs_rq_runtime() will do the throttle and +* dequeue its entity in the parent(s). Therefore the 'simple' +* nr_running test will indeed be correct. +*/ +if (unlikely (check_cfs_rq_runtime (cfs_rq))) + goto simple; + + se =pick_next_entity (cfs_rq, curr); + cfs_rq =group_cfs_rq (se); + }while (cfs_rq); + + p =task_of (se); + +/* +* Since we haven't yet done put_prev_entity and if the selected task +* is a different task than we started out with, try and touch the +* least amount of cfs_rqs. +*/ +if (prev != p) { +struct sched_entity *pse = &prev->se; + +while (!(cfs_rq =is_same_group (se, pse))) { +int se_depth = se->depth; +int pse_depth = pse->depth; + +if (se_depth <= pse_depth) { +put_prev_entity (cfs_rq_of (pse), pse); + pse =parent_entity (pse); + } +if (se_depth >= pse_depth) { +set_next_entity (cfs_rq_of (se), se); + se =parent_entity (se); + } + } + +put_prev_entity (cfs_rq, pse); +set_next_entity (cfs_rq, se); + } + +if (hrtick_enabled (rq)) +hrtick_start_fair (rq, p); + +return p; +simple: + cfs_rq = &rq->cfs; +#endif if (!cfs_rq->nr_running)return NULL ;
@@ -4669,12 +4766,13 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev) prev->sched_class->put_prev_task (rq, prev);do { - se =pick_next_entity (cfs_rq); + se =pick_next_entity (cfs_rq,NULL );set_next_entity (cfs_rq, se); cfs_rq =group_cfs_rq (se); }while (cfs_rq); p =task_of (se); +if (hrtick_enabled (rq))hrtick_start_fair (rq, p);