Re: [PATCH v2 3/6] sched/deadline: Add dl_bw_capacity()

From: Dietmar Eggemann
Date: Wed May 06 2020 - 06:55:05 EST


On 27/04/2020 10:37, Dietmar Eggemann wrote:

[...]

> diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
> index 4ae22bfc37ae..eb23e6921d94 100644
> --- a/kernel/sched/deadline.c
> +++ b/kernel/sched/deadline.c
> @@ -69,6 +69,25 @@ static inline int dl_bw_cpus(int i)
>
> return cpus;
> }
> +
> +static inline unsigned long dl_bw_capacity(int i)
> +{
> + struct root_domain *rd = cpu_rq(i)->rd;
> + unsigned long cap;
> +
> + RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(),
> + "sched RCU must be held");
> +
> + if (cpumask_subset(rd->span, cpu_active_mask))
> + return rd->sum_cpu_capacity;
> +
> + cap = 0;
> +
> + for_each_cpu_and(i, rd->span, cpu_active_mask)
> + cap += capacity_orig_of(i);
> +
> + return cap;
> +}

There is an issue w/ excl. cpusets and cpuset.sched_load_balance=0. The
latter is needed to demonstrate the problem since DL task affinity can't
be altered.

A CPU in such a cpuset has its rq attached to def_root_domain which does
not have its 'sum_cpu_capacity' properly set.

root@juno:~# bash
root@juno:~# ps -eo comm,pid,class | grep bash
bash 1661 TS
bash 2040 TS
bash 2176 TS <--

root@juno:~# echo 2176 > /sys/fs/cgroup/cpuset/B/tasks

root@juno:~# chrt -d --sched-runtime 8000 --sched-period 16000 -p 0 2176
chrt: failed to set pid 2176's policy: Device or resource busy

...
sched_dl_overflow: [bash 2176] task_cpu=4 cpus_ptr=2,4-5
dl_bw_capacity() CPU4 dflt_rd->sum_cpu_capacity=0 <-- !!! dflt_rd->span=2,4-5 cpu_active_mask=0-5
...

OTHA, rd->span is properly set due to 'cpumask_clear_cpu(rq->cpu,
old_rd->span) and cpumask_set_cpu(rq->cpu, rd->span)' in rq_attach_root().

It's not possible to treat 'rd->sum_cpu_capacity' like 'rd->span' since
the former changes between sched domain teardown/bringup w/ asymmetric
CPU capacity.

What could be done is to return 'dl_bw_cpus(i) << SCHED_CAPACITY_SHIFT'
w/ symmetric CPU capacity (of 1024) and to loop over rd->span otherwise.
Latter includes symmetric cpusets w/ only little CPUs.

---8<---
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 575b7d88d839..6d17748cb7a1 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -70,24 +70,28 @@ static inline int dl_bw_cpus(int i)
return cpus;
}

-static inline unsigned long dl_bw_capacity(int i)
-{
+static inline unsigned long __dl_bw_capacity(int i) {
struct root_domain *rd = cpu_rq(i)->rd;
- unsigned long cap;
+ unsigned long cap = 0;

RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(),
"sched RCU must be held");

- if (cpumask_subset(rd->span, cpu_active_mask))
- return rd->sum_cpu_capacity;
-
- cap = 0;
-
for_each_cpu_and(i, rd->span, cpu_active_mask)
cap += capacity_orig_of(i);

return cap;
}
+
+static inline unsigned long dl_bw_capacity(int i)
+{
+ if (!static_branch_unlikely(&sched_asym_cpucapacity) &&
+ capacity_orig_of(i) == SCHED_CAPACITY_SCALE) {
+ return dl_bw_cpus(i) << SCHED_CAPACITY_SHIFT;
+ } else {
+ return __dl_bw_capacity(i);
+ }
+}
#else
static inline struct dl_bw *dl_bw_of(int i)
{
--
2.17.1