diff options
Diffstat (limited to 'kernel/sched/fair.c')
| -rw-r--r-- | kernel/sched/fair.c | 143 |
1 files changed, 63 insertions, 80 deletions
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index c52c29dcb6a2..cfc982205b98 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -998,71 +998,17 @@ static inline bool __entity_less(struct rb_node *a, const struct rb_node *b) return entity_before(__node_2_se(a), __node_2_se(b)); } -static inline void __min_vruntime_update(struct sched_entity *se, struct rb_node *node) +/* min() for wrapping vruntimes */ +static inline u64 __min_vruntime(u64 a, u64 b) { - if (node) { - struct sched_entity *rse = __node_2_se(node); - - if (vruntime_cmp(se->min_vruntime, ">", rse->min_vruntime)) - se->min_vruntime = rse->min_vruntime; - } -} - -static inline void __min_slice_update(struct sched_entity *se, struct rb_node *node) -{ - if (node) { - struct sched_entity *rse = __node_2_se(node); - if (rse->min_slice < se->min_slice) - se->min_slice = rse->min_slice; - } -} - -static inline void __max_slice_update(struct sched_entity *se, struct rb_node *node) -{ - if (node) { - struct sched_entity *rse = __node_2_se(node); - if (rse->max_slice > se->max_slice) - se->max_slice = rse->max_slice; - } -} - -static inline void min_vruntime_copy(struct sched_entity *new, struct sched_entity *old) -{ - new->min_vruntime = old->min_vruntime; - new->min_slice = old->min_slice; - new->max_slice = old->max_slice; -} - -/* - * se->min_vruntime = min(se->vruntime, {left,right}->min_vruntime) - */ -static inline bool min_vruntime_update(struct sched_entity *se, bool exit) -{ - u64 old_min_vruntime = se->min_vruntime; - u64 old_min_slice = se->min_slice; - u64 old_max_slice = se->max_slice; - struct rb_node *node = &se->run_node; - - se->min_vruntime = se->vruntime; - __min_vruntime_update(se, node->rb_right); - __min_vruntime_update(se, node->rb_left); - - se->min_slice = se->slice; - __min_slice_update(se, node->rb_right); - __min_slice_update(se, node->rb_left); - - se->max_slice = se->slice; - __max_slice_update(se, node->rb_right); - __max_slice_update(se, node->rb_left); - - return se->min_vruntime == old_min_vruntime && - se->min_slice == old_min_slice && - se->max_slice == old_max_slice; + return vruntime_cmp(a, "<", b) ? a : b; } - -RB_DECLARE_CALLBACKS_MULTI(static, min_vruntime_cb, struct sched_entity, - run_node, min_vruntime_copy, min_vruntime_update); +RB_DECLARE_CALLBACKS(static, min_vruntime_cb, + struct sched_entity, run_node, + RB_AUG(vruntime, min_vruntime, __min_vruntime), + RB_AUG(slice, min_slice, min), + RB_AUG(slice, max_slice, max)); /* * Enqueue an entity into the rb-tree: @@ -1142,13 +1088,8 @@ static inline void set_protect_slice(struct cfs_rq *cfs_rq, struct sched_entity static inline void update_protect_slice(struct cfs_rq *cfs_rq, struct sched_entity *se) { u64 vruntime = min_vruntime(se->vruntime, avg_vruntime(cfs_rq)); - u64 slice = normalized_sysctl_sched_base_slice; - u64 vprot; - - if (sched_feat(RUN_TO_PARITY)) - slice = cfs_rq_min_slice(cfs_rq); - - vprot = min_vruntime(se->vprot, vruntime + calc_delta_fair(slice, se)); + u64 slice = cfs_rq_min_slice(cfs_rq); + u64 vprot = min_vruntime(se->vprot, vruntime + calc_delta_fair(slice, se)); if (sched_feat(PREEMPT_SHORT) && slice != se->slice) vprot = min_vruntime(vprot, ineligible_vruntime(cfs_rq)); @@ -2196,7 +2137,7 @@ void init_sched_mm(struct task_struct *p) { } static void task_tick_cache(struct rq *rq, struct task_struct *p) { } static inline int get_pref_llc(struct task_struct *p, - struct mm_struct *mm) + struct sched_cache_group *grp) { return -1; } @@ -6468,12 +6409,20 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) load = cfs_rq->sum_weight; if (curr && curr->on_rq) load += avg_vruntime_weight(cfs_rq, curr->h_load.weight); - - weight = avg_vruntime_weight(cfs_rq, se->h_load.weight); - lag *= load + weight; if (WARN_ON_ONCE(!load)) load = 1; - lag = div64_long(lag, load); + + weight = avg_vruntime_weight(cfs_rq, se->h_load.weight); + + /* + * Rewrite, because the product (W + w_i)*vl'_i might + * overflow s64: + * + * vl_i = (W + w_i)*vl'_i / W + * = (W*vl'_i + w_i*vl'_i) / W + * = vl'_i + w_i*vl'_i/W + */ + lag += div64_long(lag * weight, load); /* * A heavy entity (relative to the tree) will pull the @@ -8214,6 +8163,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) struct sched_entity *se = &p->se; struct cfs_rq *cfs_rq = &rq->cfs; unsigned long weight; + bool curr; if (task_is_throttled(p) && enqueue_throttled_task(p)) return; @@ -8242,14 +8192,25 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) if (p->in_iowait) cpufreq_update_util(rq, SCHED_CPUFREQ_IOWAIT); + curr = (cfs_rq->curr == se); + /* + * This can actually happen with CFS_BANDWIDTH, a task can be throttled + * and dequeued, unthrottled from another CPU and then enqueued again + * before schedule(). + */ + if (curr) + place_entity(cfs_rq, se, flags); if (se->on_rq && se->sched_delayed) requeue_delayed_entity(cfs_rq, se); weight = enqueue_hierarchy(p, flags); - reweight_eevdf(cfs_rq, se, weight, false); - place_entity(cfs_rq, se, flags | ENQUEUE_QUEUED); - __enqueue_entity(cfs_rq, se); + + if (!curr) { + reweight_eevdf(cfs_rq, se, weight, false); + place_entity(cfs_rq, se, flags | ENQUEUE_QUEUED); + __enqueue_entity(cfs_rq, se); + } if (!rq_h_nr_queued && rq->cfs.h_nr_queued) dl_server_start(&rq->fair_server); @@ -10978,6 +10939,8 @@ static inline bool task_misfits_asym_cpu(struct lb_env *env, struct task_struct return false; } +static inline bool sched_asym(struct sched_domain *sd, int dst_cpu, int src_cpu); + /* * Check if task p can migrate from source LLC to * destination LLC in terms of cache aware load balance. @@ -11002,6 +10965,10 @@ static enum llc_mig can_migrate_llc_task(struct lb_env *env, if (cpu < 0 || cpus_share_cache(src_cpu, dst_cpu)) return mig_unrestricted; + /* Prioritize asym packing to idle core over cache awareness */ + if (env->idle && sched_asym(env->sd, dst_cpu, src_cpu)) + return mig_unrestricted; + /* skip cache aware load balance for too many threads */ if (invalid_llc_nr(grp, p, dst_cpu) || exceed_llc_capacity(grp, dst_cpu)) { @@ -12142,6 +12109,14 @@ static void record_sg_llc_stats(struct lb_env *env, return; /* + * A redo repeats stats published on the first pass. Hotplug can + * still leave env->cpus partial, so util would not match capacity. + */ + if ((env->flags & LBF_ALL_PINNED) || + !cpumask_subset(sched_group_span(group), env->cpus)) + return; + + /* * At this point we know this group spans a LLC domain. * Record the statistic of this group in its corresponding * shared LLC domain. @@ -12185,6 +12160,14 @@ static inline bool llc_balance(struct lb_env *env, struct sg_lb_stats *sgs, return false; /* + * On asym packing domains, if the destination CPU + * has higher priority than all CPUs in the source group, + * prioritize asym packing. + */ + if (sgs->group_asym_packing) + return false; + + /* * Skip cache aware tagging if nr_balanced_failed is sufficiently high. * Threshold of cache_nice_tries is set to 1 higher than nr_balance_failed * to avoid excessive task migration at the same time. @@ -13599,12 +13582,12 @@ static int need_active_balance(struct lb_env *env) { struct sched_domain *sd = env->sd; - if (alb_break_llc(env)) - return 0; - if (asym_active_balance(env)) return 1; + if (alb_break_llc(env)) + return 0; + if (imbalanced_active_balance(env)) return 1; |
