|
@@ -6855,6 +6855,19 @@ static int need_active_balance(struct lb_env *env)
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * The dst_cpu is idle and the src_cpu CPU has only 1 CFS task.
|
|
|
|
+ * It's worth migrating the task if the src_cpu's capacity is reduced
|
|
|
|
+ * because of other sched_class or IRQs if more capacity stays
|
|
|
|
+ * available on dst_cpu.
|
|
|
|
+ */
|
|
|
|
+ if ((env->idle != CPU_NOT_IDLE) &&
|
|
|
|
+ (env->src_rq->cfs.h_nr_running == 1)) {
|
|
|
|
+ if ((check_cpu_capacity(env->src_rq, sd)) &&
|
|
|
|
+ (capacity_of(env->src_cpu)*sd->imbalance_pct < capacity_of(env->dst_cpu)*100))
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
return unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2);
|
|
return unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -6954,6 +6967,9 @@ redo:
|
|
|
|
|
|
schedstat_add(sd, lb_imbalance[idle], env.imbalance);
|
|
schedstat_add(sd, lb_imbalance[idle], env.imbalance);
|
|
|
|
|
|
|
|
+ env.src_cpu = busiest->cpu;
|
|
|
|
+ env.src_rq = busiest;
|
|
|
|
+
|
|
ld_moved = 0;
|
|
ld_moved = 0;
|
|
if (busiest->nr_running > 1) {
|
|
if (busiest->nr_running > 1) {
|
|
/*
|
|
/*
|
|
@@ -6963,8 +6979,6 @@ redo:
|
|
* correctly treated as an imbalance.
|
|
* correctly treated as an imbalance.
|
|
*/
|
|
*/
|
|
env.flags |= LBF_ALL_PINNED;
|
|
env.flags |= LBF_ALL_PINNED;
|
|
- env.src_cpu = busiest->cpu;
|
|
|
|
- env.src_rq = busiest;
|
|
|
|
env.loop_max = min(sysctl_sched_nr_migrate, busiest->nr_running);
|
|
env.loop_max = min(sysctl_sched_nr_migrate, busiest->nr_running);
|
|
|
|
|
|
more_balance:
|
|
more_balance:
|
|
@@ -7664,22 +7678,25 @@ end:
|
|
|
|
|
|
/*
|
|
/*
|
|
* Current heuristic for kicking the idle load balancer in the presence
|
|
* Current heuristic for kicking the idle load balancer in the presence
|
|
- * of an idle cpu is the system.
|
|
|
|
|
|
+ * of an idle cpu in the system.
|
|
* - This rq has more than one task.
|
|
* - This rq has more than one task.
|
|
- * - At any scheduler domain level, this cpu's scheduler group has multiple
|
|
|
|
- * busy cpu's exceeding the group's capacity.
|
|
|
|
|
|
+ * - This rq has at least one CFS task and the capacity of the CPU is
|
|
|
|
+ * significantly reduced because of RT tasks or IRQs.
|
|
|
|
+ * - At parent of LLC scheduler domain level, this cpu's scheduler group has
|
|
|
|
+ * multiple busy cpu.
|
|
* - For SD_ASYM_PACKING, if the lower numbered cpu's in the scheduler
|
|
* - For SD_ASYM_PACKING, if the lower numbered cpu's in the scheduler
|
|
* domain span are idle.
|
|
* domain span are idle.
|
|
*/
|
|
*/
|
|
-static inline int nohz_kick_needed(struct rq *rq)
|
|
|
|
|
|
+static inline bool nohz_kick_needed(struct rq *rq)
|
|
{
|
|
{
|
|
unsigned long now = jiffies;
|
|
unsigned long now = jiffies;
|
|
struct sched_domain *sd;
|
|
struct sched_domain *sd;
|
|
struct sched_group_capacity *sgc;
|
|
struct sched_group_capacity *sgc;
|
|
int nr_busy, cpu = rq->cpu;
|
|
int nr_busy, cpu = rq->cpu;
|
|
|
|
+ bool kick = false;
|
|
|
|
|
|
if (unlikely(rq->idle_balance))
|
|
if (unlikely(rq->idle_balance))
|
|
- return 0;
|
|
|
|
|
|
+ return false;
|
|
|
|
|
|
/*
|
|
/*
|
|
* We may be recently in ticked or tickless idle mode. At the first
|
|
* We may be recently in ticked or tickless idle mode. At the first
|
|
@@ -7693,38 +7710,46 @@ static inline int nohz_kick_needed(struct rq *rq)
|
|
* balancing.
|
|
* balancing.
|
|
*/
|
|
*/
|
|
if (likely(!atomic_read(&nohz.nr_cpus)))
|
|
if (likely(!atomic_read(&nohz.nr_cpus)))
|
|
- return 0;
|
|
|
|
|
|
+ return false;
|
|
|
|
|
|
if (time_before(now, nohz.next_balance))
|
|
if (time_before(now, nohz.next_balance))
|
|
- return 0;
|
|
|
|
|
|
+ return false;
|
|
|
|
|
|
if (rq->nr_running >= 2)
|
|
if (rq->nr_running >= 2)
|
|
- goto need_kick;
|
|
|
|
|
|
+ return true;
|
|
|
|
|
|
rcu_read_lock();
|
|
rcu_read_lock();
|
|
sd = rcu_dereference(per_cpu(sd_busy, cpu));
|
|
sd = rcu_dereference(per_cpu(sd_busy, cpu));
|
|
-
|
|
|
|
if (sd) {
|
|
if (sd) {
|
|
sgc = sd->groups->sgc;
|
|
sgc = sd->groups->sgc;
|
|
nr_busy = atomic_read(&sgc->nr_busy_cpus);
|
|
nr_busy = atomic_read(&sgc->nr_busy_cpus);
|
|
|
|
|
|
- if (nr_busy > 1)
|
|
|
|
- goto need_kick_unlock;
|
|
|
|
|
|
+ if (nr_busy > 1) {
|
|
|
|
+ kick = true;
|
|
|
|
+ goto unlock;
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
- sd = rcu_dereference(per_cpu(sd_asym, cpu));
|
|
|
|
|
|
+ sd = rcu_dereference(rq->sd);
|
|
|
|
+ if (sd) {
|
|
|
|
+ if ((rq->cfs.h_nr_running >= 1) &&
|
|
|
|
+ check_cpu_capacity(rq, sd)) {
|
|
|
|
+ kick = true;
|
|
|
|
+ goto unlock;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ sd = rcu_dereference(per_cpu(sd_asym, cpu));
|
|
if (sd && (cpumask_first_and(nohz.idle_cpus_mask,
|
|
if (sd && (cpumask_first_and(nohz.idle_cpus_mask,
|
|
- sched_domain_span(sd)) < cpu))
|
|
|
|
- goto need_kick_unlock;
|
|
|
|
-
|
|
|
|
- rcu_read_unlock();
|
|
|
|
- return 0;
|
|
|
|
|
|
+ sched_domain_span(sd)) < cpu)) {
|
|
|
|
+ kick = true;
|
|
|
|
+ goto unlock;
|
|
|
|
+ }
|
|
|
|
|
|
-need_kick_unlock:
|
|
|
|
|
|
+unlock:
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
-need_kick:
|
|
|
|
- return 1;
|
|
|
|
|
|
+ return kick;
|
|
}
|
|
}
|
|
#else
|
|
#else
|
|
static void nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle) { }
|
|
static void nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle) { }
|