sched/deadline: support dl task migration during cpu hotplug
RFC PATCH v2 1/1 sched/deadline: support dl task migration during cpu hotplug
I observe that dl task can't be migrated to other cpus during cpu hotplug, in addition, task may/may not be running again if cpu is added back. The root cause which I found is that dl task will be throtted and removed from dl rq after comsuming all budget, which leads to stop task can't pick it up from dl rq and migrate to other cpus during hotplug.
The method to reproduce:
schedtool -E -t 50000:100000 -e ./test
Actually test is just a simple for loop. Then observe which cpu the test task is on.
echo 0 > /sys/devices/system/cpu/cpuN/online
This patch fix it by push the task to another cpu in dl_task_timer() if rq is offline.
Note: dl task can be migrated successfully if rq is offline currently, however, I'm still not sure why task_rq(task)->rd->span just include the cpu which the dl task previous running on, so cpu_active_mask is used in the patch.
Peterz, Juri?
---
v1 -> v2:
* push the task to another cpu in dl_task_timer() if rq is offline.
kernel/sched/deadline.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-)
kernel/sched/deadline.c +36 -3
@@ -487,6 +487,7 @@ static int start_dl_timer(struct sched_dl_entity *dl_se, bool boosted)return hrtimer_active (&dl_se->dl_timer); } +static struct rq *find_lock_later_rq (struct task_struct *task,struct rq *rq);/* * This is the bandwidth enforcement timer callback. If here, we know * a task is not on its dl_rq, since the fact that the timer was running
@@ -538,6 +539,39 @@ again:update_rq_clock (rq); dl_se->dl_throttled =0 ; dl_se->dl_yielded =0 ; + +/* +* So if we find that the rq the task was on is no longer +* available, we need to select a new rq. +*/ +if (!rq->online) { +struct rq *later_rq =NULL ; + +/* We will release rq lock */ +get_task_struct (p); + +raw_spin_unlock (&rq->lock); + + later_rq =find_lock_later_rq (p, rq); + +if (!later_rq) { +put_task_struct (p); + goto out; + } + +deactivate_task (rq, p,0 ); +set_task_cpu (p, later_rq->cpu); +activate_task (later_rq, p,0 ); + +resched_curr (later_rq); + +double_unlock_balance (rq, later_rq); + +put_task_struct (p); + + goto out; + } +if (task_on_rq_queued (p)) {enqueue_task_dl (rq, p,ENQUEUE_REPLENISH );if (dl_task (rq->curr))
@@ -555,7 +589,7 @@ again: } unlock:raw_spin_unlock (&rq->lock); - +out:return HRTIMER_NORESTART ; }
@@ -1182,8 +1216,7 @@ static int find_later_rq(struct task_struct *task)* We have to consider system topology and task affinity * first, then we can look for a suitable cpu. */ -cpumask_copy (later_mask,task_rq (task)->rd->span); -cpumask_and (later_mask, later_mask, cpu_active_mask); +cpumask_copy (later_mask, cpu_active_mask);cpumask_and (later_mask, later_mask, &task->cpus_allowed); best_cpu =cpudl_find (&task_rq (task)->rd->cpudl, task, later_mask);
Signature · 1 line
1.9.1
Hi,
Quoted 91 lines · Wanpeng Li
I observe that dl task can't be migrated to other cpus during cpu hotplug, in addition, task may/may not be running again if cpu is added back. The root cause which I found is that dl task will be throtted and removed from dl rq after comsuming all budget, which leads to stop task can't pick it up from dl rq and migrate to other cpus during hotplug.
The method to reproduce:
schedtool -E -t 50000:100000 -e ./test
Actually test is just a simple for loop. Then observe which cpu the test task is on.
echo 0 >/sys/devices/system/cpu/cpuN/onlineThis patch fix it by push the task to another cpu in
dl_task_timer()if rq is offline.Note: dl task can be migrated successfully if rq is offline currently, however, I'm still not sure why task_rq(task)->rd->span just include the cpu which the dl task previous running on, so
cpu_active_maskis used in the patch.Peterz, Juri?
Signed-off-by Wanpeng Li <[email protected]>---
v1 -> v2:
* push the task to another cpu indl_task_timer()if rq is offline.kernel/sched/deadline.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-)kernel/sched/deadline.c +35
-1@@ -487,6 +487,7 @@ static int start_dl_timer(struct sched_dl_entity *dl_se, bool boosted)return hrtimer_active (&dl_se->dl_timer); } +static struct rq *find_lock_later_rq (struct task_struct *task,struct rq *rq);/* * This is the bandwidth enforcement timer callback. If here, we know * a task is not on its dl_rq, since the fact that the timer was running @@ -538,6 +539,39 @@ again:update_rq_clock (rq); dl_se->dl_throttled =0 ; dl_se->dl_yielded =0 ; + +/* +* So if we find that the rq the task was on is no longer +* available, we need to select a new rq. +*/ +if (!rq->online) { +struct rq *later_rq =NULL ; + +/* We will release rq lock */ +get_task_struct (p); + +raw_spin_unlock (&rq->lock); + + later_rq =find_lock_later_rq (p, rq); + +if (!later_rq) { +put_task_struct (p); + goto out; + } + +deactivate_task (rq, p,0 ); +set_task_cpu (p, later_rq->cpu); +activate_task (later_rq, p,0 ); + +resched_curr (later_rq); + +double_unlock_balance (rq, later_rq); + +put_task_struct (p); + + goto out; + } +if (task_on_rq_queued (p)) {enqueue_task_dl (rq, p,ENQUEUE_REPLENISH );if (dl_task (rq->curr))@@ -555,7 +589,7 @@ again: } unlock:raw_spin_unlock (&rq->lock); - +out:return HRTIMER_NORESTART ; }
kernel/sched/deadline.c static int find_later_rq(struct task_struct *task) · line 1219
Quoted 6 lines
kernel/sched/deadline.c +1
-2@@ -1182,8 +1216,7 @@ static int find_later_rq(struct task_struct *task)* We have to consider system topology and task affinity * first, then we can look for a suitable cpu. */ -cpumask_copy (later_mask,task_rq (task)->rd->span); -cpumask_and (later_mask, later_mask, cpu_active_mask); +cpumask_copy (later_mask, cpu_active_mask);
I fear this breaks what I lately fixed in commit 91ec6778ec4f ("sched/deadline: Fix inter- exclusive cpusets migrations"), as we first have to consider exclusive cpusets topology in looking for a cpu. But, I'd have to test this to see if I'm right, and I'll try to do it soon.
Thanks,
- Juri
Quoted 4 lines
kernel/sched/deadline.c +0
-0cpumask_and (later_mask, later_mask, &task->cpus_allowed); best_cpu =cpudl_find (&task_rq (task)->rd->cpudl, task, later_mask);
Hi Juri,
Quoted 93 lines · Juri Lelli
Hi,
Quoted 90 lines · Wanpeng Li
I observe that dl task can't be migrated to other cpus during cpu hotplug, in addition, task may/may not be running again if cpu is added back. The root cause which I found is that dl task will be throtted and removed from dl rq after comsuming all budget, which leads to stop task can't pick it up from dl rq and migrate to other cpus during hotplug.
The method to reproduce:
schedtool -E -t 50000:100000 -e ./test
Actually test is just a simple for loop. Then observe which cpu the test task is on.
echo 0 >/sys/devices/system/cpu/cpuN/onlineThis patch fix it by push the task to another cpu in
dl_task_timer()if rq is offline.Note: dl task can be migrated successfully if rq is offline currently, however, I'm still not sure why task_rq(task)->rd->span just include the cpu which the dl task previous running on, so
cpu_active_maskis used in the patch.Peterz, Juri?
Signed-off-by Wanpeng Li <[email protected]>---
v1 -> v2:
* push the task to another cpu indl_task_timer()if rq is offline.kernel/sched/deadline.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-)kernel/sched/deadline.c +35
-1@@ -487,6 +487,7 @@ static int start_dl_timer(struct sched_dl_entity *dl_se, bool boosted)return hrtimer_active (&dl_se->dl_timer); } +static struct rq *find_lock_later_rq (struct task_struct *task,struct rq *rq);/* * This is the bandwidth enforcement timer callback. If here, we know * a task is not on its dl_rq, since the fact that the timer was running @@ -538,6 +539,39 @@ again:update_rq_clock (rq); dl_se->dl_throttled =0 ; dl_se->dl_yielded =0 ; + +/* +* So if we find that the rq the task was on is no longer +* available, we need to select a new rq. +*/ +if (!rq->online) { +struct rq *later_rq =NULL ; + +/* We will release rq lock */ +get_task_struct (p); + +raw_spin_unlock (&rq->lock); + + later_rq =find_lock_later_rq (p, rq); + +if (!later_rq) { +put_task_struct (p); + goto out; + } + +deactivate_task (rq, p,0 ); +set_task_cpu (p, later_rq->cpu); +activate_task (later_rq, p,0 ); + +resched_curr (later_rq); + +double_unlock_balance (rq, later_rq); + +put_task_struct (p); + + goto out; + } +if (task_on_rq_queued (p)) {enqueue_task_dl (rq, p,ENQUEUE_REPLENISH );if (dl_task (rq->curr))@@ -555,7 +589,7 @@ again: } unlock:raw_spin_unlock (&rq->lock); - +out:return HRTIMER_NORESTART ; }
Quoted 9 lines
kernel/sched/deadline.c static int find_later_rq(struct task_struct *task) · line 1219
Quoted 7 lines
kernel/sched/deadline.c +1
-2@@ -1182,8 +1216,7 @@ static int find_later_rq(struct task_struct *task)* We have to consider system topology and task affinity * first, then we can look for a suitable cpu. */ -cpumask_copy (later_mask,task_rq (task)->rd->span); -cpumask_and (later_mask, later_mask, cpu_active_mask); +cpumask_copy (later_mask, cpu_active_mask);I fear this breaks what I lately fixed in commit
91ec6778ec4f("sched/deadline: Fix inter- exclusive cpusets migrations"), as
As I mentioned in the patch description:
Note: dl task can be migrated successfully if rq is offline currently, however, I'm still not sure why task_rq(task)->rd->span just include the cpu which the dl task previous running on, so cpu_active_mask is used in the patch.
Any explantion after your test is a great approciated. ;-)
Quoted 3 lines
we first have to consider exclusive cpusets topology in looking for a cpu. But, I'd have to test this to see if I'm right, and I'll try to do it soon.
Thanks for your help. ;-)
Regards,
Wanpeng Li
Quoted 14 lines
Thanks,
- Juri
kernel/sched/deadline.c static int find_later_rq(struct task_struct *task) · line 1222
Quoted 4 lines
kernel/sched/deadline.c +0
-0cpumask_and (later_mask, later_mask, &task->cpus_allowed); best_cpu =cpudl_find (&task_rq (task)->rd->cpudl, task, later_mask);--
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
maintainerQuoted 5 lines · Wanpeng Li
Note: dl task can be migrated successfully if rq is offline currently, however, I'm still not sure why task_rq(task)->rd->span just include the cpu which the dl task previous running on, so
cpu_active_maskis used in the patch.Peterz, Juri?
So the root domain span is for exclusive cpusets (Documentation/cgroups/cpusets.txt) where we fully separate sets of CPUs and have no load-balancing between the sets.
For 'normal' setups the rd->span is the entire machine, but using cpusets you can create more (smaller) domains.
Is this what you were asking?
Hi Peter,
Quoted 5 lines · Peter Zijlstra
Quoted 4 lines · Wanpeng Li
Note: dl task can be migrated successfully if rq is offline currently, however, I'm still not sure why task_rq(task)->rd->span just include the cpu which the dl task previous running on, so
cpu_active_maskis used in the patch.
Quoted 7 lines
Quoted 1 line
Peterz, Juri?
So the root domain span is for exclusive cpusets (
Documentation/cgroups/cpusets.txt) where we fully separate sets of CPUs and have no load-balancing between the sets.For 'normal' setups the
rd->spanis the entire machine, but using cpusets you can create more (smaller) domains.
I don't setup any cpusets related stuff, however, task_rq(task)->rd->span just include the cpu which the dl task previous running on instead of the entire machine in find_later_rq().
Regards,
Wanpeng Li
Quoted 7 lines
Is this what you were asking?
--
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
maintainerQuoted 12 lines · Wanpeng Li
Hi Peter,
Quoted 10 lines · Peter Zijlstra
Quoted 5 lines · Wanpeng Li
Note: dl task can be migrated successfully if rq is offline currently, however, I'm still not sure why task_rq(task)->rd->span just include the cpu which the dl task previous running on, so
cpu_active_maskis used in the patch.Peterz, Juri?
So the root domain span is for exclusive cpusets (
Documentation/cgroups/cpusets.txt) where we fully separate sets of CPUs and have no load-balancing between the sets.
Quoted 6 lines
Quoted 2 lines
For 'normal' setups the
rd->spanis the entire machine, but using cpusets you can create more (smaller) domains.I don't setup any cpusets related stuff, however, task_rq(task)->rd->span just include the cpu which the dl task previous running on instead of the entire machine in
find_later_rq().
Ah, it could be that for offline cpus we have a singleton rd. Lemme try and remember wth we did there.
Hi Peter,
Quoted 13 lines · Peter Zijlstra
Quoted 12 lines · Wanpeng Li
Hi Peter,
Quoted 10 lines · Peter Zijlstra
Quoted 5 lines · Wanpeng Li
Note: dl task can be migrated successfully if rq is offline currently, however, I'm still not sure why task_rq(task)->rd->span just include the cpu which the dl task previous running on, so
cpu_active_maskis used in the patch.Peterz, Juri?
So the root domain span is for exclusive cpusets (
Documentation/cgroups/cpusets.txt) where we fully separate sets of CPUs and have no load-balancing between the sets.
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
For 'normal' setups the
rd->spanis the entire machine, but using cpusets you can create more (smaller) domains.I don't setup any cpusets related stuff, however, task_rq(task)->rd->span just include the cpu which the dl task previous running on instead of the entire machine in
find_later_rq().Ah, it could be that for offline cpus we have a singleton rd. Lemme try
I still cannot find where build the singleton rd in the codes, could you point out?
Regards,
Wanpeng Li
Quoted 1 line
and remember wth we did there.
Peter Zijlstra
maintainerQuoted 4 lines · Wanpeng Li
Quoted 1 line
Ah, it could be that for offline cpus we have a singleton rd. Lemme try
I still cannot find where build the singleton rd in the codes, could you point out?
So this is all quite horrible code, but what I think happens is that:
sched_cpu_inactive() -> set_cpu_active(cpu, false); cpuset_cpu_inactive() -> cpuset_update_active_cpus(false) -> partition_sched_domains(1, NULL, NULL) -> build_sched_domains(cpu_active_mask) -> for_each_cpu() cpu_attach_domain() -> rq_attach_root()
Now, that will detach all active cpus from the current root domain and attach them to the new root domain. Which leaves behind the old root domain attached to only the one 'dead' cpu.
Quoted 14 lines · Peter Zijlstra
Quoted 3 lines · Wanpeng Li
Quoted 1 line
Ah, it could be that for offline cpus we have a singleton rd. Lemme try
I still cannot find where build the singleton rd in the codes, could you point out?
So this is all quite horrible code, but what I think happens is that:
sched_cpu_inactive() -> set_cpu_active(cpu, false); cpuset_cpu_inactive() -> cpuset_update_active_cpus(false) -> partition_sched_domains(1, NULL, NULL) -> build_sched_domains(cpu_active_mask) -> for_each_cpu() cpu_attach_domain() -> rq_attach_root()
Quoted 3 lines
Now, that will detach all active cpus from the current root domain and attach them to the new root domain. Which leaves behind the old root domain attached to only the one 'dead' cpu.
Got it, thanks for your great explanation. ;-)
Regards,
Wanpeng Li
Hi, all,
В Ср, 05/11/2014 в 16:51 +0800, Wanpeng Li пишет:
Quoted 91 lines
I observe that dl task can't be migrated to other cpus during cpu hotplug, in addition, task may/may not be running again if cpu is added back. The root cause which I found is that dl task will be throtted and removed from dl rq after comsuming all budget, which leads to stop task can't pick it up from dl rq and migrate to other cpus during hotplug.
The method to reproduce:
schedtool -E -t 50000:100000 -e ./test
Actually test is just a simple for loop. Then observe which cpu the test task is on.
echo 0 >/sys/devices/system/cpu/cpuN/onlineThis patch fix it by push the task to another cpu in
dl_task_timer()if rq is offline.Note: dl task can be migrated successfully if rq is offline currently, however, I'm still not sure why task_rq(task)->rd->span just include the cpu which the dl task previous running on, so
cpu_active_maskis used in the patch.Peterz, Juri?
Signed-off-by Wanpeng Li <[email protected]>---
v1 -> v2:
* push the task to another cpu indl_task_timer()if rq is offline.kernel/sched/deadline.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-)kernel/sched/deadline.c +35
-1@@ -487,6 +487,7 @@ static int start_dl_timer(struct sched_dl_entity *dl_se, bool boosted)return hrtimer_active (&dl_se->dl_timer); } +static struct rq *find_lock_later_rq (struct task_struct *task,struct rq *rq);/* * This is the bandwidth enforcement timer callback. If here, we know * a task is not on its dl_rq, since the fact that the timer was running @@ -538,6 +539,39 @@ again:update_rq_clock (rq); dl_se->dl_throttled =0 ; dl_se->dl_yielded =0 ; + +/* +* So if we find that the rq the task was on is no longer +* available, we need to select a new rq. +*/ +if (!rq->online) { +struct rq *later_rq =NULL ; + +/* We will release rq lock */ +get_task_struct (p); + +raw_spin_unlock (&rq->lock); + + later_rq =find_lock_later_rq (p, rq); + +if (!later_rq) { +put_task_struct (p); + goto out; + } + +deactivate_task (rq, p,0 ); +set_task_cpu (p, later_rq->cpu); +activate_task (later_rq, p,0 ); + +resched_curr (later_rq); + +double_unlock_balance (rq, later_rq); + +put_task_struct (p); + + goto out; + } +if (task_on_rq_queued (p)) {enqueue_task_dl (rq, p,ENQUEUE_REPLENISH );if (dl_task (rq->curr))@@ -555,7 +589,7 @@ again: } unlock:raw_spin_unlock (&rq->lock); - +out:return HRTIMER_NORESTART ; }
kernel/sched/deadline.c static int find_later_rq(struct task_struct *task) · line 1222
Quoted 9 lines
kernel/sched/deadline.c +1
-2@@ -1182,8 +1216,7 @@ static int find_later_rq(struct task_struct *task)* We have to consider system topology and task affinity * first, then we can look for a suitable cpu. */ -cpumask_copy (later_mask,task_rq (task)->rd->span); -cpumask_and (later_mask, later_mask, cpu_active_mask); +cpumask_copy (later_mask, cpu_active_mask);cpumask_and (later_mask, later_mask, &task->cpus_allowed); best_cpu =cpudl_find (&task_rq (task)->rd->cpudl, task, later_mask);
isn't this too complicated?
Can't we simply queue throttled tasks in rq_offline_dl() (without clearing of dl_throttled() status)? migrate_tasks() will do the migration right.
This case the patch from the topic may be simply transformed in:
kernel/sched/deadline.c +1 -1
@@ -531,7 +531,7 @@ static enum hrtimer_restart dl_task_timer(struct hrtimer *timer)* in the runqueue or is going to be enqueued back anyway. */ if (!dl_task (p) || dl_se->dl_new || - dl_se->dl_boosted || !dl_se->dl_throttled) + dl_se->dl_boosted || !dl_se->dl_throttled ||on_dl_rq (dl_se)) goto unlock;sched_clock_tick ();
Peter Zijlstra
maintainerQuoted 6 lines · Kirill Tkhai
Quoted 6 lines
(quoted diff) +2
-0@@ -538,6 +539,39 @@ again: update_rq_clock(rq); dl_se->dl_throttled = 0; dl_se->dl_yielded = 0; + + /*
Quoted 8 lines
Review again: · line 551
Quoted 8 lines
(quoted diff) +8
-0+ * So if we find that the rq the task was on is no longer + * available, we need to select a new rq. + */ + if (!rq->online) { + struct rq *later_rq = NULL; + + /* We will release rq lock */ + get_task_struct(p);
No need for this, due to task_dead_dl() -> hrtimer_cancel() this task cannot go away while the timer callback is running.
Quoted 8 lines
Review again: · line 559
Quoted 8 lines
(quoted diff) +8
-0+ raw_spin_unlock(&rq->lock); + + later_rq = find_lock_later_rq(p, rq); + + if (!later_rq) { + put_task_struct(p); + goto out; + }
This is wrong I think, we _must_ migrate the task, if we let it reside on this offline rq it will never come back to us.
find_lock_later_rq() will fail for tasks that aren't currently eligible to run. You could either try and change/parameterize it to return the latest rq in that case, or just punt and pick any online cpu.
Quoted 4 lines
isn't this too complicated?
Can't we simply queue throttled tasks in
rq_offline_dl()(without clearing ofdl_throttled()status)?migrate_tasks()will do the migration right.
We can't find these tasks, we'd have to add extra lists etc. And it seems consistent with the normal ttwu thing, which migrates tasks when they wake up.