sched: fine tune task placement for prioritized tasks

The prioritized task is defined as prefer high capacity with prio <=
120. We found on the chipset with 2 big cores only, when one big core
is occupied by busy non-prioritized tasks, prioritized tasks could be
scheduled to the other big core. This may affect UX because the
prioritized tasks are mostly UI related. Address this problem by put
at least one prioritized task to the cpu which has no prioritized task
running on it. Besides, if both big cores have prioritized tasks on them
already, then schedule arriving prioritized tasks to idle little core if
there is in the hope of not being blocked by existing prioritized tasks.

Bug: 161190988
Bug: 160663228
Test: tasks scheduled as expected
Signed-off-by: Rick Yiu <rickyiu@google.com>
Change-Id: I880e3a68a5c8fbfd0902e1b571a83bfd88ce1b96
This commit is contained in:
Rick Yiu 2020-07-11 11:45:54 +08:00 committed by spakkkk
parent dcbacf46fa
commit aa57fb3819
3 changed files with 89 additions and 12 deletions

View File

@ -7207,6 +7207,8 @@ static struct kmem_cache *task_group_cache __read_mostly;
DECLARE_PER_CPU(cpumask_var_t, load_balance_mask);
DECLARE_PER_CPU(cpumask_var_t, select_idle_mask);
DECLARE_PER_CPU(unsigned long *, prioritized_task_mask);
DECLARE_PER_CPU(int, prioritized_task_nr);
void __init sched_init(void)
{
@ -7279,6 +7281,9 @@ void __init sched_init(void)
rq = cpu_rq(i);
raw_spin_lock_init(&rq->lock);
rq->nr_running = 0;
per_cpu(prioritized_task_mask, i) =
bitmap_zalloc(TASK_BITS, GFP_KERNEL);
per_cpu(prioritized_task_nr, i) = 0;
rq->calc_load_active = 0;
rq->calc_load_update = jiffies + LOAD_FREQ;
init_cfs_rq(&rq->cfs);

View File

@ -167,9 +167,11 @@ unsigned int sysctl_sched_cfs_bandwidth_slice = 5000UL;
*/
unsigned int capacity_margin = 1280;
unsigned int sched_capacity_margin_up[CPU_NR] = {
[0 ... CPU_NR-1] = 1078}; /* ~5% margin */
[0 ... CPU_NR - 1] = 1078
}; /* ~5% margin */
unsigned int sched_capacity_margin_down[CPU_NR] = {
[0 ... CPU_NR-1] = 1205}; /* ~15% margin */
[0 ... CPU_NR - 1] = 1078
}; /* ~5% margin */
unsigned int sched_capacity_margin_up_boosted[CPU_NR] = {
3658, 3658, 3658, 3658, 3658, 3658, 1078, 1024
}; /* 72% margin for small, 5% for big, 0% for big+ */
@ -2830,6 +2832,47 @@ static inline void update_scan_period(struct task_struct *p, int new_cpu)
#endif /* CONFIG_NUMA_BALANCING */
DEFINE_PER_CPU(unsigned long *, prioritized_task_mask);
DEFINE_PER_CPU(int, prioritized_task_nr);
static bool bitmap_testbit(unsigned long *map, unsigned long bit)
{
if (*(map + BIT_WORD(bit)) & BIT_MASK(bit))
return true;
return false;
}
static void inc_prioritized_task_count(struct rq *rq, struct task_struct *p)
{
bool bitset = bitmap_testbit(per_cpu(prioritized_task_mask, cpu_of(rq)),
p->pid);
if (schedtune_prefer_high_cap(p) && p->prio <= DEFAULT_PRIO) {
if (likely(!bitset)) {
__bitmap_set(per_cpu(prioritized_task_mask, cpu_of(rq)),
p->pid, 1);
per_cpu(prioritized_task_nr, cpu_of(rq))++;
}
} else if (unlikely(bitset)) {
__bitmap_clear(per_cpu(prioritized_task_mask, cpu_of(rq)),
p->pid, 1);
if (per_cpu(prioritized_task_nr, cpu_of(rq)) > 0)
per_cpu(prioritized_task_nr, cpu_of(rq))--;
}
}
static void dec_prioritized_task_count(struct rq *rq, struct task_struct *p)
{
if (bitmap_testbit(per_cpu(prioritized_task_mask, cpu_of(rq)),
p->pid)) {
__bitmap_clear(per_cpu(prioritized_task_mask, cpu_of(rq)),
p->pid, 1);
if (per_cpu(prioritized_task_nr, cpu_of(rq)) > 0)
per_cpu(prioritized_task_nr, cpu_of(rq))--;
}
}
static void
account_entity_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
@ -2845,6 +2888,9 @@ account_entity_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
}
#endif
cfs_rq->nr_running++;
if (likely(entity_is_task(se))) {
inc_prioritized_task_count(rq_of(cfs_rq), task_of(se));
}
}
static void
@ -2860,6 +2906,9 @@ account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
}
#endif
cfs_rq->nr_running--;
if (likely(entity_is_task(se))) {
dec_prioritized_task_count(rq_of(cfs_rq), task_of(se));
}
}
/*
@ -3936,7 +3985,7 @@ static inline bool cpu_is_in_target_set(struct task_struct *p, int cpu)
struct root_domain *rd = cpu_rq(cpu)->rd;
int first_cpu, next_usable_cpu;
#ifdef CONFIG_SCHED_TUNE
if (schedtune_prefer_high_cap(p)) {
if (schedtune_prefer_high_cap(p) && p->prio <= DEFAULT_PRIO) {
#else
if (uclamp_boosted(p)) {
#endif
@ -7068,6 +7117,7 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus,
struct sched_group *sg;
int best_active_cpu = -1;
int best_idle_cpu = -1;
int best_prioritized_cpu = -1;
int target_cpu = -1;
int backup_cpu = -1;
int i, start_cpu;
@ -7080,6 +7130,7 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus,
bool rtg_high_prio_task = task_rtg_high_prio(p);
int mid_cap_orig_cpu = cpu_rq(smp_processor_id())->rd->mid_cap_orig_cpu;
struct task_struct *curr_tsk;
bool prioritized_task = prefer_high_cap && p->prio <= DEFAULT_PRIO;
/*
* In most cases, target_capacity tracks capacity_orig of the most
@ -7126,6 +7177,7 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus,
unsigned long wake_util, new_util, new_util_cuml;
long spare_cap;
int idle_idx = INT_MAX;
bool best_prioritized_candidate;
trace_sched_cpu_util(i);
@ -7187,7 +7239,12 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus,
* capacity margin.
*/
new_util = max(min_util, new_util);
best_prioritized_candidate =
prioritized_task && !is_min_capacity_cpu(i) &&
per_cpu(prioritized_task_nr, i) == 0;
if ((!(prefer_idle && idle_cpu(i)) &&
!best_prioritized_candidate &&
new_util > capacity_orig) ||
(is_min_capacity_cpu(i) &&
!task_fits_capacity(p, capacity_orig, i)))
@ -7284,6 +7341,11 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus,
if (best_idle_cpu != -1)
continue;
if (best_prioritized_candidate) {
best_prioritized_cpu = i;
continue;
}
/*
* Case A.2: Target ACTIVE CPU
* Favor CPUs with max spare capacity.
@ -7465,10 +7527,11 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus,
* accommodated in the higher capacity CPUs.
*/
if ((prefer_idle && best_idle_cpu != -1) ||
(prefer_high_cap &&
(best_idle_cpu != -1 || target_cpu != -1 ||
(prioritized_task && best_prioritized_cpu != -1) ||
(prefer_high_cap && p->prio > DEFAULT_PRIO &&
(target_cpu != -1 ||
(fbt_env->strict_max && most_spare_cap_cpu != -1)))) {
if (prefer_high_cap && p->prio <= DEFAULT_PRIO) {
if (prioritized_task) {
/*
* For prefer_high_cap task, stop searching when
* an idle cpu is found in mid cluster.
@ -7490,6 +7553,11 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus,
goto target;
}
if (prioritized_task && (best_prioritized_cpu != -1)) {
target_cpu = best_prioritized_cpu;
goto target;
}
adjust_cpus_for_packing(p, &target_cpu, &best_idle_cpu,
shallowest_idle_cstate,
fbt_env, prefer_high_cap);
@ -8894,9 +8962,11 @@ static inline int migrate_degrades_locality(struct task_struct *p,
static inline bool can_migrate_boosted_task(struct task_struct *p,
int src_cpu, int dst_cpu)
{
if (per_task_boost(p) == TASK_BOOST_STRICT_MAX &&
if ((per_task_boost(p) == TASK_BOOST_STRICT_MAX &&
task_in_related_thread_group(p) &&
(capacity_orig_of(dst_cpu) < capacity_orig_of(src_cpu)))
(capacity_orig_of(dst_cpu) < capacity_orig_of(src_cpu))) ||
(schedtune_prefer_high_cap(p) && p->prio <= DEFAULT_PRIO &&
is_min_capacity_cpu(dst_cpu)))
return false;
return true;
}

View File

@ -89,6 +89,8 @@ struct cpuidle_state;
#define CPU_NR 8
#define TASK_BITS (PID_MAX_DEFAULT + BITS_PER_LONG)
extern __read_mostly bool sched_predl;
extern unsigned int sched_capacity_margin_up[CPU_NR];
extern unsigned int sched_capacity_margin_down[CPU_NR];