Skip to content

Commit 6769243

Browse files
author
Peter Zijlstra
committed
sched: Rework pick_next_task() slow-path
Avoid the RETRY_TASK case in the pick_next_task() slow path. By doing the put_prev_task() early, we get the rt/deadline pull done, and by testing rq->nr_running we know if we need newidle_balance(). This then gives a stable state to pick a task from. Since the fast-path is fair only; it means the other classes will always have pick_next_task(.prev=NULL, .rf=NULL) and we can simplify. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Cc: Aaron Lu <[email protected]> Cc: Valentin Schneider <[email protected]> Cc: [email protected] Cc: Phil Auld <[email protected]> Cc: Julien Desfossez <[email protected]> Cc: Nishanth Aravamudan <[email protected]> Link: https://lkml.kernel.org/r/aa34d24b36547139248f32a30138791ac6c02bd6.1559129225.git.vpillai@digitalocean.com
1 parent 5f2a45f commit 6769243

File tree

7 files changed

+34
-73
lines changed

7 files changed

+34
-73
lines changed

kernel/sched/core.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3791,7 +3791,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
37913791

37923792
p = fair_sched_class.pick_next_task(rq, prev, rf);
37933793
if (unlikely(p == RETRY_TASK))
3794-
goto again;
3794+
goto restart;
37953795

37963796
/* Assumes fair_sched_class->next == idle_sched_class */
37973797
if (unlikely(!p))
@@ -3800,14 +3800,19 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
38003800
return p;
38013801
}
38023802

3803-
again:
3803+
restart:
3804+
/*
3805+
* Ensure that we put DL/RT tasks before the pick loop, such that they
3806+
* can PULL higher prio tasks when we lower the RQ 'priority'.
3807+
*/
3808+
prev->sched_class->put_prev_task(rq, prev, rf);
3809+
if (!rq->nr_running)
3810+
newidle_balance(rq, rf);
3811+
38043812
for_each_class(class) {
3805-
p = class->pick_next_task(rq, prev, rf);
3806-
if (p) {
3807-
if (unlikely(p == RETRY_TASK))
3808-
goto again;
3813+
p = class->pick_next_task(rq, NULL, NULL);
3814+
if (p)
38093815
return p;
3810-
}
38113816
}
38123817

38133818
/* The idle class should always have a runnable task: */

kernel/sched/deadline.c

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1761,39 +1761,13 @@ pick_next_task_dl(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
17611761
struct task_struct *p;
17621762
struct dl_rq *dl_rq;
17631763

1764-
dl_rq = &rq->dl;
1765-
1766-
if (need_pull_dl_task(rq, prev)) {
1767-
/*
1768-
* This is OK, because current is on_cpu, which avoids it being
1769-
* picked for load-balance and preemption/IRQs are still
1770-
* disabled avoiding further scheduler activity on it and we're
1771-
* being very careful to re-start the picking loop.
1772-
*/
1773-
rq_unpin_lock(rq, rf);
1774-
pull_dl_task(rq);
1775-
rq_repin_lock(rq, rf);
1776-
/*
1777-
* pull_dl_task() can drop (and re-acquire) rq->lock; this
1778-
* means a stop task can slip in, in which case we need to
1779-
* re-start task selection.
1780-
*/
1781-
if (rq->stop && task_on_rq_queued(rq->stop))
1782-
return RETRY_TASK;
1783-
}
1764+
WARN_ON_ONCE(prev || rf);
17841765

1785-
/*
1786-
* When prev is DL, we may throttle it in put_prev_task().
1787-
* So, we update time before we check for dl_nr_running.
1788-
*/
1789-
if (prev->sched_class == &dl_sched_class)
1790-
update_curr_dl(rq);
1766+
dl_rq = &rq->dl;
17911767

17921768
if (unlikely(!dl_rq->dl_nr_running))
17931769
return NULL;
17941770

1795-
put_prev_task(rq, prev);
1796-
17971771
dl_se = pick_next_dl_entity(rq, dl_rq);
17981772
BUG_ON(!dl_se);
17991773

kernel/sched/fair.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6770,7 +6770,7 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
67706770
goto idle;
67716771

67726772
#ifdef CONFIG_FAIR_GROUP_SCHED
6773-
if (prev->sched_class != &fair_sched_class)
6773+
if (!prev || prev->sched_class != &fair_sched_class)
67746774
goto simple;
67756775

67766776
/*
@@ -6847,8 +6847,8 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
68476847
goto done;
68486848
simple:
68496849
#endif
6850-
6851-
put_prev_task(rq, prev);
6850+
if (prev)
6851+
put_prev_task(rq, prev);
68526852

68536853
do {
68546854
se = pick_next_entity(cfs_rq, NULL);
@@ -6876,6 +6876,9 @@ done: __maybe_unused;
68766876
return p;
68776877

68786878
idle:
6879+
if (!rf)
6880+
return NULL;
6881+
68796882
new_tasks = newidle_balance(rq, rf);
68806883

68816884
/*

kernel/sched/idle.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,9 @@ pick_next_task_idle(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
389389
{
390390
struct task_struct *next = rq->idle;
391391

392-
put_prev_task(rq, prev);
392+
if (prev)
393+
put_prev_task(rq, prev);
394+
393395
set_next_task_idle(rq, next);
394396

395397
return next;

kernel/sched/rt.c

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,38 +1553,11 @@ pick_next_task_rt(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
15531553
struct task_struct *p;
15541554
struct rt_rq *rt_rq = &rq->rt;
15551555

1556-
if (need_pull_rt_task(rq, prev)) {
1557-
/*
1558-
* This is OK, because current is on_cpu, which avoids it being
1559-
* picked for load-balance and preemption/IRQs are still
1560-
* disabled avoiding further scheduler activity on it and we're
1561-
* being very careful to re-start the picking loop.
1562-
*/
1563-
rq_unpin_lock(rq, rf);
1564-
pull_rt_task(rq);
1565-
rq_repin_lock(rq, rf);
1566-
/*
1567-
* pull_rt_task() can drop (and re-acquire) rq->lock; this
1568-
* means a dl or stop task can slip in, in which case we need
1569-
* to re-start task selection.
1570-
*/
1571-
if (unlikely((rq->stop && task_on_rq_queued(rq->stop)) ||
1572-
rq->dl.dl_nr_running))
1573-
return RETRY_TASK;
1574-
}
1575-
1576-
/*
1577-
* We may dequeue prev's rt_rq in put_prev_task().
1578-
* So, we update time before rt_queued check.
1579-
*/
1580-
if (prev->sched_class == &rt_sched_class)
1581-
update_curr_rt(rq);
1556+
WARN_ON_ONCE(prev || rf);
15821557

15831558
if (!rt_rq->rt_queued)
15841559
return NULL;
15851560

1586-
put_prev_task(rq, prev);
1587-
15881561
p = _pick_next_task_rt(rq);
15891562

15901563
set_next_task_rt(rq, p);

kernel/sched/sched.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,12 +1700,15 @@ struct sched_class {
17001700
void (*check_preempt_curr)(struct rq *rq, struct task_struct *p, int flags);
17011701

17021702
/*
1703-
* It is the responsibility of the pick_next_task() method that will
1704-
* return the next task to call put_prev_task() on the @prev task or
1705-
* something equivalent.
1703+
* Both @prev and @rf are optional and may be NULL, in which case the
1704+
* caller must already have invoked put_prev_task(rq, prev, rf).
17061705
*
1707-
* May return RETRY_TASK when it finds a higher prio class has runnable
1708-
* tasks.
1706+
* Otherwise it is the responsibility of the pick_next_task() to call
1707+
* put_prev_task() on the @prev task or something equivalent, IFF it
1708+
* returns a next task.
1709+
*
1710+
* In that case (@rf != NULL) it may return RETRY_TASK when it finds a
1711+
* higher prio class has runnable tasks.
17091712
*/
17101713
struct task_struct * (*pick_next_task)(struct rq *rq,
17111714
struct task_struct *prev,

kernel/sched/stop_task.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@ pick_next_task_stop(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
3333
{
3434
struct task_struct *stop = rq->stop;
3535

36+
WARN_ON_ONCE(prev || rf);
37+
3638
if (!stop || !task_on_rq_queued(stop))
3739
return NULL;
3840

39-
put_prev_task(rq, prev);
4041
set_next_task_stop(rq, stop);
4142

4243
return stop;

0 commit comments

Comments
 (0)