diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index c4c3afa6e7b4f51f39445da63a161e876366a285..71661d6c5b5488d9cb9a698cf8b8b84cbd4cf1fb 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9106,6 +9106,19 @@ static inline unsigned long taskgroup_cpu_util(struct task_group *tg, return cpu_util_cfs(cpu); } +static unsigned long scale_rt_capacity(int cpu); + +static inline unsigned long calc_cpu_capacity(int cpu) +{ + unsigned long capacity; + + capacity = scale_rt_capacity(cpu); + if (!capacity) + capacity = 1; + + return capacity; +} + /* * set_task_select_cpus: select the cpu range for task * @p: the task whose available cpu range will to set @@ -9128,6 +9141,7 @@ static void set_task_select_cpus(struct task_struct *p, int *idlest_cpu, struct task_group *tg; long spare; int cpu, mode; + int nr_cpus_valid = 0; p->select_cpus = p->cpus_ptr; if (!prefer_cpus_valid(p)) @@ -9149,7 +9163,7 @@ static void set_task_select_cpus(struct task_struct *p, int *idlest_cpu, /* manual mode */ tg = task_group(p); - for_each_cpu(cpu, p->prefer_cpus) { + for_each_cpu_and(cpu, p->prefer_cpus, cpu_online_mask) { if (idlest_cpu && (available_idle_cpu(cpu) || sched_idle_cpu(cpu))) { *idlest_cpu = cpu; } else if (idlest_cpu) { @@ -9170,15 +9184,28 @@ static void set_task_select_cpus(struct task_struct *p, int *idlest_cpu, } util_avg_sum += taskgroup_cpu_util(tg, cpu); - tg_capacity += capacity_of(cpu); + nr_cpus_valid++; + + if (cpu_rq(cpu)->rt.rt_nr_running) + tg_capacity += calc_cpu_capacity(cpu); + else + tg_capacity += capacity_of(cpu); } rcu_read_unlock(); - if (tg_capacity > cpumask_weight(p->prefer_cpus) && + /* + * Follow cases should select cpus_ptr, checking by condition of + * tg_capacity > nr_cpus_valid: + * 1. all prefer_cpus offline; + * 2. all prefer_cpus has no cfs capaicity(tg_capacity = nr_cpus_valid * 1) + */ + if (tg_capacity > nr_cpus_valid && util_avg_sum * 100 <= tg_capacity * sysctl_sched_util_low_pct) { p->select_cpus = p->prefer_cpus; if (sd_flag & SD_BALANCE_WAKE) schedstat_inc(p->stats.nr_wakeups_preferred_cpus); + } else if (idlest_cpu) { + *idlest_cpu = -1; } } #endif