cpu的调度域初始化

cpu的调度域可以分为下面3类。目前arm都是用的mc
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;

在下面的函数中都cpu的域进行初始化
可以看到域的初始化分为4部分
static int
build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *attr)
{
	enum s_alloc alloc_state;
	struct sched_domain *sd;
	struct s_data d;
	struct rq *rq = NULL;
	int i, ret = -ENOMEM;

	alloc_state = __visit_domain_allocation_hell(&d, cpu_map);
	if (alloc_state != sa_rootdomain)
		goto error;

	/* Set up domains for CPUs specified by the cpu_map: */
	#针对cpu_map中的cpu 来是指cpu domain
	for_each_cpu(i, cpu_map) {
		struct sched_domain_topology_level *tl;

		sd = NULL;
		for_each_sd_topology(tl) {
			#为每个cpubuild 调度域
			sd = build_sched_domain(tl, cpu_map, attr, sd, i);
			#正常情况下sched_domain_topology应该等于default_topology,这里每个cpu设置调度域
			if (tl == sched_domain_topology)
				*per_cpu_ptr(d.sd, i) = sd;
			if (tl->flags & SDTL_OVERLAP)
				sd->flags |= SD_OVERLAP;
			#cpu_map中每个cpu 都是指调度域后,退出这个for循环
			if (cpumask_equal(cpu_map, sched_domain_span(sd)))
				break;
		}
	}

	/* Build the groups for the domains */
	#为每个cpu 设置group
	for_each_cpu(i, cpu_map) {
		for (sd = *per_cpu_ptr(d.sd, i); sd; sd = sd->parent) {
			sd->span_weight = cpumask_weight(sched_domain_span(sd));
			if (sd->flags & SD_OVERLAP) {
				if (build_overlap_sched_groups(sd, i))
					goto error;
			} else {
			#主要是设置sd->group
				if (build_sched_groups(sd, i))
					goto error;
			}
		}
	}
#从上面可知每个cpu都有一个domain->groups
	/* Calculate CPU capacity for physical packages and nodes */
	for (i = nr_cpumask_bits-1; i >= 0; i--) {
		if (!cpumask_test_cpu(i, cpu_map))
			continue;

		for (sd = *per_cpu_ptr(d.sd, i); sd; sd = sd->parent) {
			claim_allocations(i, sd);
			#设置调度域中group中的每个cpu的能力
			init_sched_groups_capacity(i, sd);
		}
	}
#下面为么个rq attach domain
	/* Attach the domains */
	rcu_read_lock();
	for_each_cpu(i, cpu_map) {
	#得到每个cpu的running queue
		rq = cpu_rq(i);
		#每个cpu的调度域
		sd = *per_cpu_ptr(d.sd, i);

		/* Use READ_ONCE()/WRITE_ONCE() to avoid load/store tearing: */
		#如rq中表示cpucapacity的值大于调度域中表示cpu capacity,则更新调度域中的cpu的capacity
		if (rq->cpu_capacity_orig > READ_ONCE(d.rd->max_cpu_capacity))
			WRITE_ONCE(d.rd->max_cpu_capacity, rq->cpu_capacity_orig);
		#将sd 作为cpu的base domain
		cpu_attach_domain(sd, d.rd, i);
	}
	rcu_read_unlock();
	#用于debug是显示cpu的最大的capacity
	if (rq && sched_debug_enabled) {
		pr_info("span: %*pbl (max cpu_capacity = %lu)\n",
			cpumask_pr_args(cpu_map), rq->rd->max_cpu_capacity);
	}

	ret = 0;
error:
	__free_domain_allocs(&d, alloc_state, cpu_map);
	return ret;
}

猜你喜欢

转载自blog.csdn.net/tiantao2012/article/details/80396509