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

Reply via email to