cpu核数和内存大小怎么搭配 cpu核数( 五 )


GFP_KERNEL, cpu_to_node(j));
if (!sds)
return -ENOMEM;
*per_cpu_ptr(sdd->sds, j) = sds;
sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(),
GFP_KERNEL, cpu_to_node(j));
if (!sg)
return -ENOMEM;
sg->next = sg;
*per_cpu_ptr(sdd->sg, j) = sg;
sgc = kzalloc_node(sizeof(struct sched_group_capacity) + cpumask_size(),
GFP_KERNEL, cpu_to_node(j));
if (!sgc)
return -ENOMEM;
#ifdef CONFIG_SCHED_DEBUG
sgc->id = j;
#endif
*per_cpu_ptr(sdd->sgc, j) = sgc;
}
}
return 0;
}
在这个函数中我们接触到第一个比较关键的数据结构struct sched_domain_topology_level 。
struct sched_domain_topology_level {
sched_domain_mask_f mask;
sched_domain_flags_f sd_flags;
intflags;
intnuma_level;
struct sd_datadata;
#ifdef CONFIG_SCHED_DEBUG
char*name;
#endif
};
static struct sched_domain_topology_level default_topology[] = {
#ifdef CONFIG_SCHED_SMT
{ cpu_smt_mask, cpu_smt_flags, SD_INIT_NAME(SMT) },
#endif
#ifdef CONFIG_SCHED_MC
{ cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
#endif
{ cpu_cpu_mask, SD_INIT_NAME(DIE) },
{ NULL, },
};
static struct sched_domain_topology_level *sched_domain_topology =
default_topology;
#define for_each_sd_topology(tl)\\
for (tl = sched_domain_topology; tl->mask; tl++)
void set_sched_topology(struct sched_domain_topology_level *tl)
{
if (WARN_ON_ONCE(sched_smp_initialized))
return;
sched_domain_topology = tl;
}
可以看到,struct sched_domain_topology_level使用一个数组default_topology给出,当然各个体系结构下也可以修改该数组 。该数组一般按照CPU层次从低到高排列 。
struct sched_domain_toplogy_level的前两个成员mask和flag分别是两个函数,用于指定该CPU层次下的兄弟cpumask和flag标志位 。而struct sd_data是该数据结构的核心,其成员将在后续完成赋值 。
这里简单看下物理核心层的mask成员cpu_coregroup_mask 。
const struct cpumask *cpu_coregroup_mask(int cpu)
{
const cpumask_t *core_mask = cpumask_of_node(cpu_to_node(cpu));
/* Find the smaller of NUMA, core or LLC siblings */
if (cpumask_subset(&cpu_topology[cpu].core_sibling, core_mask)) {
/* not numa in package, lets use the package siblings */
core_mask = &cpu_topology[cpu].core_sibling;
}
if (cpu_topology[cpu].llc_id != -1) {
if (cpumask_subset(&cpu_topology[cpu].llc_sibling, core_mask))
core_mask = &cpu_topology[cpu].llc_sibling;
}
return core_mask;
}
可以看到,本质上是利用cpu_topology数组来获得core_sibling的值,到这里就和物理层级联系起来了 。
struct sd_data {
struct sched_domain *__percpu *sd;
struct sched_domain_shared *__percpu *sds;
struct sched_group *__percpu *sg;
struct sched_group_capacity *__percpu *sgc;
};
分析__sdt_alloc,可以看到为每个层次的struct sched_domain_topology_level的sd_data分配percpu的sched_domain、sched_domain_shared、sched_group和sched_group_capacity 。这样每个CPU可以通过default_topology数组轻易找到自己的sched_domain等数据 。
接下来,继续分析build_sched_domains的第2个核心函数build_sched_domain,该函数在每个CPU的每个层次上都要去调用一次 。
static struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl,
const struct cpumask *cpu_map, struct sched_domain_attr *attr,
struct sched_domain *child, int dflags, int cpu)
{
struct sched_domain *sd = sd_init(tl, cpu_map, child, dflags, cpu);
if (child) {