diff options
author | Peter Zijlstra <peterz@infradead.org> | 2019-05-29 16:36:43 -0400 |
---|---|---|
committer | Peter Zijlstra <peterz@infradead.org> | 2019-08-08 03:09:31 -0400 |
commit | 5f2a45fc9e89e022233085e6f0f352eb6ff770bb (patch) | |
tree | 6f619f4db2fe3ab531d4a27807af7f6a8e7d2fe9 | |
parent | 5ba553eff0c3a7c099b1e29a740277a82c0c3314 (diff) |
sched: Allow put_prev_task() to drop rq->lock
Currently the pick_next_task() loop is convoluted and ugly because of
how it can drop the rq->lock and needs to restart the picking.
For the RT/Deadline classes, it is put_prev_task() where we do
balancing, and we could do this before the picking loop. Make this
possible.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Valentin Schneider <valentin.schneider@arm.com>
Cc: Aaron Lu <aaron.lwe@gmail.com>
Cc: mingo@kernel.org
Cc: Phil Auld <pauld@redhat.com>
Cc: Julien Desfossez <jdesfossez@digitalocean.com>
Cc: Nishanth Aravamudan <naravamudan@digitalocean.com>
Link: https://lkml.kernel.org/r/e4519f6850477ab7f3d257062796e6425ee4ba7c.1559129225.git.vpillai@digitalocean.com
-rw-r--r-- | kernel/sched/core.c | 2 | ||||
-rw-r--r-- | kernel/sched/deadline.c | 14 | ||||
-rw-r--r-- | kernel/sched/fair.c | 2 | ||||
-rw-r--r-- | kernel/sched/idle.c | 2 | ||||
-rw-r--r-- | kernel/sched/rt.c | 14 | ||||
-rw-r--r-- | kernel/sched/sched.h | 4 | ||||
-rw-r--r-- | kernel/sched/stop_task.c | 2 |
7 files changed, 32 insertions, 8 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 0c4220789092..7bbe78a31ba5 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -6090,7 +6090,7 @@ static struct task_struct *__pick_migrate_task(struct rq *rq) | |||
6090 | for_each_class(class) { | 6090 | for_each_class(class) { |
6091 | next = class->pick_next_task(rq, NULL, NULL); | 6091 | next = class->pick_next_task(rq, NULL, NULL); |
6092 | if (next) { | 6092 | if (next) { |
6093 | next->sched_class->put_prev_task(rq, next); | 6093 | next->sched_class->put_prev_task(rq, next, NULL); |
6094 | return next; | 6094 | return next; |
6095 | } | 6095 | } |
6096 | } | 6096 | } |
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 6eae79350303..2872e15a87cd 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c | |||
@@ -1804,13 +1804,25 @@ pick_next_task_dl(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) | |||
1804 | return p; | 1804 | return p; |
1805 | } | 1805 | } |
1806 | 1806 | ||
1807 | static void put_prev_task_dl(struct rq *rq, struct task_struct *p) | 1807 | static void put_prev_task_dl(struct rq *rq, struct task_struct *p, struct rq_flags *rf) |
1808 | { | 1808 | { |
1809 | update_curr_dl(rq); | 1809 | update_curr_dl(rq); |
1810 | 1810 | ||
1811 | update_dl_rq_load_avg(rq_clock_pelt(rq), rq, 1); | 1811 | update_dl_rq_load_avg(rq_clock_pelt(rq), rq, 1); |
1812 | if (on_dl_rq(&p->dl) && p->nr_cpus_allowed > 1) | 1812 | if (on_dl_rq(&p->dl) && p->nr_cpus_allowed > 1) |
1813 | enqueue_pushable_dl_task(rq, p); | 1813 | enqueue_pushable_dl_task(rq, p); |
1814 | |||
1815 | if (rf && !on_dl_rq(&p->dl) && need_pull_dl_task(rq, p)) { | ||
1816 | /* | ||
1817 | * This is OK, because current is on_cpu, which avoids it being | ||
1818 | * picked for load-balance and preemption/IRQs are still | ||
1819 | * disabled avoiding further scheduler activity on it and we've | ||
1820 | * not yet started the picking loop. | ||
1821 | */ | ||
1822 | rq_unpin_lock(rq, rf); | ||
1823 | pull_dl_task(rq); | ||
1824 | rq_repin_lock(rq, rf); | ||
1825 | } | ||
1814 | } | 1826 | } |
1815 | 1827 | ||
1816 | /* | 1828 | /* |
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index e7c27eda9f24..4418c1998e69 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c | |||
@@ -6901,7 +6901,7 @@ idle: | |||
6901 | /* | 6901 | /* |
6902 | * Account for a descheduled task: | 6902 | * Account for a descheduled task: |
6903 | */ | 6903 | */ |
6904 | static void put_prev_task_fair(struct rq *rq, struct task_struct *prev) | 6904 | static void put_prev_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) |
6905 | { | 6905 | { |
6906 | struct sched_entity *se = &prev->se; | 6906 | struct sched_entity *se = &prev->se; |
6907 | struct cfs_rq *cfs_rq; | 6907 | struct cfs_rq *cfs_rq; |
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c index 54194d41035c..8d59de2e4a6e 100644 --- a/kernel/sched/idle.c +++ b/kernel/sched/idle.c | |||
@@ -374,7 +374,7 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int fl | |||
374 | resched_curr(rq); | 374 | resched_curr(rq); |
375 | } | 375 | } |
376 | 376 | ||
377 | static void put_prev_task_idle(struct rq *rq, struct task_struct *prev) | 377 | static void put_prev_task_idle(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) |
378 | { | 378 | { |
379 | } | 379 | } |
380 | 380 | ||
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index f71bcbe1a00c..dbdabd76f192 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c | |||
@@ -1592,7 +1592,7 @@ pick_next_task_rt(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) | |||
1592 | return p; | 1592 | return p; |
1593 | } | 1593 | } |
1594 | 1594 | ||
1595 | static void put_prev_task_rt(struct rq *rq, struct task_struct *p) | 1595 | static void put_prev_task_rt(struct rq *rq, struct task_struct *p, struct rq_flags *rf) |
1596 | { | 1596 | { |
1597 | update_curr_rt(rq); | 1597 | update_curr_rt(rq); |
1598 | 1598 | ||
@@ -1604,6 +1604,18 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p) | |||
1604 | */ | 1604 | */ |
1605 | if (on_rt_rq(&p->rt) && p->nr_cpus_allowed > 1) | 1605 | if (on_rt_rq(&p->rt) && p->nr_cpus_allowed > 1) |
1606 | enqueue_pushable_task(rq, p); | 1606 | enqueue_pushable_task(rq, p); |
1607 | |||
1608 | if (rf && !on_rt_rq(&p->rt) && need_pull_rt_task(rq, p)) { | ||
1609 | /* | ||
1610 | * This is OK, because current is on_cpu, which avoids it being | ||
1611 | * picked for load-balance and preemption/IRQs are still | ||
1612 | * disabled avoiding further scheduler activity on it and we've | ||
1613 | * not yet started the picking loop. | ||
1614 | */ | ||
1615 | rq_unpin_lock(rq, rf); | ||
1616 | pull_rt_task(rq); | ||
1617 | rq_repin_lock(rq, rf); | ||
1618 | } | ||
1607 | } | 1619 | } |
1608 | 1620 | ||
1609 | #ifdef CONFIG_SMP | 1621 | #ifdef CONFIG_SMP |
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 304d98e712bf..e085cffb8004 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h | |||
@@ -1710,7 +1710,7 @@ struct sched_class { | |||
1710 | struct task_struct * (*pick_next_task)(struct rq *rq, | 1710 | struct task_struct * (*pick_next_task)(struct rq *rq, |
1711 | struct task_struct *prev, | 1711 | struct task_struct *prev, |
1712 | struct rq_flags *rf); | 1712 | struct rq_flags *rf); |
1713 | void (*put_prev_task)(struct rq *rq, struct task_struct *p); | 1713 | void (*put_prev_task)(struct rq *rq, struct task_struct *p, struct rq_flags *rf); |
1714 | void (*set_next_task)(struct rq *rq, struct task_struct *p); | 1714 | void (*set_next_task)(struct rq *rq, struct task_struct *p); |
1715 | 1715 | ||
1716 | #ifdef CONFIG_SMP | 1716 | #ifdef CONFIG_SMP |
@@ -1756,7 +1756,7 @@ struct sched_class { | |||
1756 | static inline void put_prev_task(struct rq *rq, struct task_struct *prev) | 1756 | static inline void put_prev_task(struct rq *rq, struct task_struct *prev) |
1757 | { | 1757 | { |
1758 | WARN_ON_ONCE(rq->curr != prev); | 1758 | WARN_ON_ONCE(rq->curr != prev); |
1759 | prev->sched_class->put_prev_task(rq, prev); | 1759 | prev->sched_class->put_prev_task(rq, prev, NULL); |
1760 | } | 1760 | } |
1761 | 1761 | ||
1762 | static inline void set_next_task(struct rq *rq, struct task_struct *next) | 1762 | static inline void set_next_task(struct rq *rq, struct task_struct *next) |
diff --git a/kernel/sched/stop_task.c b/kernel/sched/stop_task.c index 47a3d2a18a9a..8f414018d5e0 100644 --- a/kernel/sched/stop_task.c +++ b/kernel/sched/stop_task.c | |||
@@ -59,7 +59,7 @@ static void yield_task_stop(struct rq *rq) | |||
59 | BUG(); /* the stop task should never yield, its pointless. */ | 59 | BUG(); /* the stop task should never yield, its pointless. */ |
60 | } | 60 | } |
61 | 61 | ||
62 | static void put_prev_task_stop(struct rq *rq, struct task_struct *prev) | 62 | static void put_prev_task_stop(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) |
63 | { | 63 | { |
64 | struct task_struct *curr = rq->curr; | 64 | struct task_struct *curr = rq->curr; |
65 | u64 delta_exec; | 65 | u64 delta_exec; |