When load_avg is much higher than util_avg, then it indicates either the task have higher priority with more weight value for load_avg or because the task have much longer time in "runnable" state rather than "running" state.
This patch changes to use load metrics rather than util metrics if meet any of below condition: - load * capacity_margin > SCHED_CAPACITY_SCALE * SCHED_LOAD_SCALE, this means tasks require CPU computation reach CPU 80% capacity; - util * capacity_margin > capacity_of(cpu) * SCHED_LOAD_SCALE, this means tasks CPU reach 80% utilization; - load is 20% higher than util, so task have extra 20% time for runnable state and waiting to run; Or the task has higher prioirty than nice 0; then consider to use load signal rather than util signal.
At last, we need constraint util value in the range of [0..arch_scale_cpu_capacity(cpu)] so can ensure tweaked value can fall into correct range.
This patch has another side effect for misfit flag. After apply this patch, if task with remarkable runnable time then it can more easily to set true for misfit: rq->misfit_task = !task_fits_max(p, rq->cpu); this will benefit for the case if if there have two tasks on the little CPU, then the task utilization value just half of CPU capacity value so EAS wrongly considers CPU can meet task requirement and don't migrate task to higher capacity CPU. After apply this patch, the task will change to use load metric and the issue also will be fixed.
Signed-off-by: Leo Yan leo.yan@linaro.org --- kernel/sched/fair.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 747d27d..54d80908 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4198,6 +4198,8 @@ static inline void hrtick_update(struct rq *rq) #endif
static inline unsigned long boosted_cpu_util(int cpu); +static inline unsigned long boosted_task_util(struct task_struct *task); +static inline unsigned long schedtune_task_margin(struct task_struct *task);
static void update_capacity_of(int cpu) { @@ -5249,15 +5251,66 @@ static inline unsigned long task_util(struct task_struct *p) return p->se.avg.util_avg; }
+static inline unsigned long task_load(struct task_struct *p) +{ + return p->se.avg.load_avg; +} + unsigned int capacity_margin = 1280; /* ~20% margin */
-static inline unsigned long boosted_task_util(struct task_struct *task); +/* + * Change to use load metrics if can meet two conditions: + * + * - load * capacity_margin > SCHED_CAPACITY_SCALE * SCHED_LOAD_SCALE, + * this means tasks require CPU computation reach CPU 80% capacity; + * - util * capacity_margin > capacity_of(cpu) * SCHED_LOAD_SCALE, + * this means tasks CPU reach 80% utilization; + * - load is 20% higher than util, so task have extra 20% time for + * runnable state and waiting to run; Or the task has higher prioirty + * than nice 0; then consider to use load signal rather than util signal. + * + */ +static inline bool task_has_big_load(struct task_struct *p) +{ + unsigned long util = task_util(p); + unsigned long load = task_load(p); + int cpu = task_cpu(p); + + if (load * capacity_margin > SCHED_CAPACITY_SCALE * SCHED_LOAD_SCALE) + return true; + + if (util * capacity_margin > capacity_of(cpu) * SCHED_LOAD_SCALE) + return true; + + if (util * capacity_margin < load * SCHED_LOAD_SCALE) + return true; + + return false; +} + +static inline unsigned long task_tweaked_util(struct task_struct *p) +{ + int cpu = task_cpu(p); + unsigned long util = task_util(p); + unsigned long load = task_load(p); + unsigned long scale_cpu = arch_scale_cpu_capacity(NULL, cpu); + + if (task_has_big_load(p)) + util = max_t(unsigned long, util, load); + + util = clamp(util, 0UL, (unsigned long)scale_cpu); + return util; +}
static inline bool __task_fits(struct task_struct *p, int cpu, int util) { unsigned long capacity = capacity_of(cpu); + unsigned long margin = schedtune_task_margin(p);
- util += boosted_task_util(p); + if (margin) + util += boosted_task_util(p); + else + util += task_tweaked_util(p);
return (capacity * 1024) > (util * capacity_margin); } @@ -5393,7 +5446,7 @@ schedtune_cpu_margin(unsigned long util, int cpu) return 0; }
-static inline unsigned int +static inline unsigned long schedtune_task_margin(struct task_struct *task) { return 0; -- 1.9.1