Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/linux/sched/sd_flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ SD_FLAG(SD_ASYM_CPUCAPACITY_FULL, SDF_SHARED_PARENT | SDF_NEEDS_GROUPS)
*/
SD_FLAG(SD_SHARE_CPUCAPACITY, SDF_SHARED_CHILD | SDF_NEEDS_GROUPS)

/*
* Domain members share CPU cluster (LLC tags or L2 cache)
*
* NEEDS_GROUPS: Clusters are shared between groups.
*/
SD_FLAG(SD_CLUSTER, SDF_NEEDS_GROUPS)

/*
* Domain members share CPU package resources (i.e. caches)
*
Expand Down
8 changes: 7 additions & 1 deletion include/linux/sched/topology.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ static inline int cpu_smt_flags(void)
#ifdef CONFIG_SCHED_CLUSTER
static inline int cpu_cluster_flags(void)
{
return SD_SHARE_PKG_RESOURCES;
return SD_CLUSTER | SD_SHARE_PKG_RESOURCES;
}
#endif

Expand Down Expand Up @@ -179,6 +179,7 @@ cpumask_var_t *alloc_sched_domains(unsigned int ndoms);
void free_sched_domains(cpumask_var_t doms[], unsigned int ndoms);

bool cpus_share_cache(int this_cpu, int that_cpu);
bool cpus_share_resources(int this_cpu, int that_cpu);

typedef const struct cpumask *(*sched_domain_mask_f)(int cpu);
typedef int (*sched_domain_flags_f)(void);
Expand Down Expand Up @@ -232,6 +233,11 @@ static inline bool cpus_share_cache(int this_cpu, int that_cpu)
return true;
}

static inline bool cpus_share_resources(int this_cpu, int that_cpu)
{
return true;
}

#endif /* !CONFIG_SMP */

#if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL)
Expand Down
12 changes: 12 additions & 0 deletions kernel/sched/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -3962,6 +3962,18 @@ bool cpus_share_cache(int this_cpu, int that_cpu)
return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu);
}

/*
* Whether CPUs are share cache resources, which means LLC on non-cluster
* machines and LLC tag or L2 on machines with clusters.
*/
bool cpus_share_resources(int this_cpu, int that_cpu)
{
if (this_cpu == that_cpu)
return true;

return per_cpu(sd_share_id, this_cpu) == per_cpu(sd_share_id, that_cpu);
}

static inline bool ttwu_queue_cond(struct task_struct *p, int cpu)
{
/*
Expand Down
57 changes: 52 additions & 5 deletions kernel/sched/fair.c
Original file line number Diff line number Diff line change
Expand Up @@ -7437,14 +7437,38 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, bool
}
}

if (static_branch_unlikely(&sched_cluster_active)) {
struct sched_group *sg = sd->groups;

if (sg->flags & SD_CLUSTER) {
for_each_cpu_wrap(cpu, sched_group_span(sg), target + 1) {
if (!cpumask_test_cpu(cpu, cpus))
continue;

if (has_idle_core) {
i = select_idle_core(p, cpu, cpus, &idle_cpu);
if ((unsigned int)i < nr_cpumask_bits)
return i;
} else {
if (--nr <= 0)
return -1;
idle_cpu = __select_idle_cpu(cpu, p);
if ((unsigned int)idle_cpu < nr_cpumask_bits)
return idle_cpu;
}
}
cpumask_andnot(cpus, cpus, sched_group_span(sg));
}
}

for_each_cpu_wrap(cpu, cpus, target + 1) {
if (has_idle_core) {
i = select_idle_core(p, cpu, cpus, &idle_cpu);
if ((unsigned int)i < nr_cpumask_bits)
return i;

} else {
if (!--nr)
if (--nr <= 0)
return -1;
idle_cpu = __select_idle_cpu(cpu, p);
if ((unsigned int)idle_cpu < nr_cpumask_bits)
Expand Down Expand Up @@ -7546,7 +7570,7 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
bool has_idle_core = false;
struct sched_domain *sd;
unsigned long task_util, util_min, util_max;
int i, recent_used_cpu;
int i, recent_used_cpu, prev_aff = -1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Initialize recent_used_cpu to a safe default

Explicitly initialize recent_used_cpu to -1 at declaration to clarify its default state and prevent accidental use before assignment.

Suggested change
int i, recent_used_cpu, prev_aff = -1;
int i, recent_used_cpu = -1, prev_aff = -1;


/*
* On asymmetric system, update task utilization because we will check
Expand All @@ -7573,8 +7597,14 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
*/
if (prev != target && cpus_share_cache(prev, target) &&
(available_idle_cpu(prev) || sched_idle_cpu(prev)) &&
asym_fits_cpu(task_util, util_min, util_max, prev))
return prev;
asym_fits_cpu(task_util, util_min, util_max, prev)) {

if (!static_branch_unlikely(&sched_cluster_active) ||
cpus_share_resources(prev, target))
return prev;

prev_aff = prev;
}

/*
* Allow a per-cpu kthread to stack with the wakee if the
Expand All @@ -7601,7 +7631,13 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
(available_idle_cpu(recent_used_cpu) || sched_idle_cpu(recent_used_cpu)) &&
cpumask_test_cpu(recent_used_cpu, p->cpus_ptr) &&
asym_fits_cpu(task_util, util_min, util_max, recent_used_cpu)) {
return recent_used_cpu;

if (!static_branch_unlikely(&sched_cluster_active) ||
cpus_share_resources(recent_used_cpu, target))
return recent_used_cpu;

} else {
recent_used_cpu = -1;
}

/*
Expand Down Expand Up @@ -7642,6 +7678,17 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
if ((unsigned)i < nr_cpumask_bits)
return i;

/*
* For cluster machines which have lower sharing cache like L2 or
* LLC Tag, we tend to find an idle CPU in the target's cluster
* first. But prev_cpu or recent_used_cpu may also be a good candidate,
* use them if possible when no idle CPU found in select_idle_cpu().
*/
if ((unsigned int)prev_aff < nr_cpumask_bits)
return prev_aff;
if ((unsigned int)recent_used_cpu < nr_cpumask_bits)
return recent_used_cpu;

return target;
}

Expand Down
2 changes: 2 additions & 0 deletions kernel/sched/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -1898,11 +1898,13 @@ static inline struct sched_domain *lowest_flag_domain(int cpu, int flag)
DECLARE_PER_CPU(struct sched_domain __rcu *, sd_llc);
DECLARE_PER_CPU(int, sd_llc_size);
DECLARE_PER_CPU(int, sd_llc_id);
DECLARE_PER_CPU(int, sd_share_id);
DECLARE_PER_CPU(struct sched_domain_shared __rcu *, sd_llc_shared);
DECLARE_PER_CPU(struct sched_domain __rcu *, sd_numa);
DECLARE_PER_CPU(struct sched_domain __rcu *, sd_asym_packing);
DECLARE_PER_CPU(struct sched_domain __rcu *, sd_asym_cpucapacity);
extern struct static_key_false sched_asym_cpucapacity;
extern struct static_key_false sched_cluster_active;

static __always_inline bool sched_asym_cpucap_active(void)
{
Expand Down
25 changes: 25 additions & 0 deletions kernel/sched/topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -666,11 +666,14 @@ static void destroy_sched_domains(struct sched_domain *sd)
DEFINE_PER_CPU(struct sched_domain __rcu *, sd_llc);
DEFINE_PER_CPU(int, sd_llc_size);
DEFINE_PER_CPU(int, sd_llc_id);
DEFINE_PER_CPU(int, sd_share_id);
DEFINE_PER_CPU(struct sched_domain_shared __rcu *, sd_llc_shared);
DEFINE_PER_CPU(struct sched_domain __rcu *, sd_numa);
DEFINE_PER_CPU(struct sched_domain __rcu *, sd_asym_packing);
DEFINE_PER_CPU(struct sched_domain __rcu *, sd_asym_cpucapacity);

DEFINE_STATIC_KEY_FALSE(sched_asym_cpucapacity);
DEFINE_STATIC_KEY_FALSE(sched_cluster_active);

static void update_top_cache_domain(int cpu)
{
Expand All @@ -691,6 +694,17 @@ static void update_top_cache_domain(int cpu)
per_cpu(sd_llc_id, cpu) = id;
rcu_assign_pointer(per_cpu(sd_llc_shared, cpu), sds);

sd = lowest_flag_domain(cpu, SD_CLUSTER);
if (sd)
id = cpumask_first(sched_domain_span(sd));

/*
* This assignment should be placed after the sd_llc_id as
* we want this id equals to cluster id on cluster machines
* but equals to LLC id on non-Cluster machines.
*/
per_cpu(sd_share_id, cpu) = id;

sd = lowest_flag_domain(cpu, SD_NUMA);
rcu_assign_pointer(per_cpu(sd_numa, cpu), sd);

Expand Down Expand Up @@ -1548,6 +1562,7 @@ static struct cpumask ***sched_domains_numa_masks;
*/
#define TOPOLOGY_SD_FLAGS \
(SD_SHARE_CPUCAPACITY | \
SD_CLUSTER | \
SD_SHARE_PKG_RESOURCES | \
SD_NUMA | \
SD_ASYM_PACKING)
Expand Down Expand Up @@ -2369,6 +2384,7 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att
struct rq *rq = NULL;
int i, ret = -ENOMEM;
bool has_asym = false;
bool has_cluster = false;

if (WARN_ON(cpumask_empty(cpu_map)))
goto error;
Expand Down Expand Up @@ -2508,12 +2524,18 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att
WRITE_ONCE(d.rd->max_cpu_capacity, capacity);

cpu_attach_domain(sd, d.rd, i);

if (lowest_flag_domain(i, SD_CLUSTER))
has_cluster = true;
}
rcu_read_unlock();

if (has_asym)
static_branch_inc_cpuslocked(&sched_asym_cpucapacity);

if (has_cluster)
static_branch_inc_cpuslocked(&sched_cluster_active);

if (rq && sched_debug_verbose) {
pr_info("root domain span: %*pbl (max cpu_capacity = %lu)\n",
cpumask_pr_args(cpu_map), rq->rd->max_cpu_capacity);
Expand Down Expand Up @@ -2613,6 +2635,9 @@ static void detach_destroy_domains(const struct cpumask *cpu_map)
if (rcu_access_pointer(per_cpu(sd_asym_cpucapacity, cpu)))
static_branch_dec_cpuslocked(&sched_asym_cpucapacity);

if (static_branch_unlikely(&sched_cluster_active))
static_branch_dec_cpuslocked(&sched_cluster_active);

rcu_read_lock();
for_each_cpu(i, cpu_map)
cpu_attach_domain(NULL, &def_root_domain, i);
Expand Down
Loading