smp的负载均衡

在kernel中会注册一个软件中断来做负载均衡
__init void init_sched_fair_class(void)
{
#ifdef CONFIG_SMP
	open_softirq(SCHED_SOFTIRQ, run_rebalance_domains);
endif /* SMP */
}
这个软件中断SCHED_SOFTIRQ 对应的回调函数是run_rebalance_domains
static __latent_entropy void run_rebalance_domains(struct softirq_action *h)
{
	struct rq *this_rq = this_rq();
	#判断当前rg是否是idle
	enum cpu_idle_type idle = this_rq->idle_balance ?
						CPU_IDLE : CPU_NOT_IDLE;
	#开始负载均衡,从这里可以知道负载均衡是在一个domain 内的cpu来做的
	rebalance_domains(this_rq, idle);
}
static void rebalance_domains(struct rq *rq, enum cpu_idle_type idle)
{
	
	#负载均衡的周期,这里很根据当前rq是否idle 会对应不同的时间,也就是说
	#负载均衡的周期有两个值
	interval = get_sd_balance_interval(sd, idle != CPU_IDLE);
	#遍历domain中的每个cpu
	for_each_domain(cpu, sd) {
	
		if (time_after_eq(jiffies, sd->last_balance + interval)) {
		#周期到后开始做负载均衡
			if (load_balance(cpu, rq, sd, idle, &continue_balancing)) {
				/*
				 * The LBF_DST_PINNED logic could have changed
				 * env->dst_cpu, so we can't know our idle
				 * state even if we migrated tasks. Update it.
				 */
				idle = idle_cpu(cpu) ? CPU_IDLE : CPU_NOT_IDLE;
			}
			sd->last_balance = jiffies;
			interval = get_sd_balance_interval(sd, idle != CPU_IDLE);
		}
}
这里首先看看负载均衡的两个周期是如何计算的
static inline unsigned long
get_sd_balance_interval(struct sched_domain *sd, int cpu_busy)
{
	unsigned long interval = sd->balance_interval;
	#关键是这一步,如果cpu busy的话,则做负载均衡的时间会变长
	if (cpu_busy)
		interval *= sd->busy_factor;

	/* scale ms to jiffies */
	interval = msecs_to_jiffies(interval);
	#负载均衡的最大值不能超过1UL和max_load_balance_interval 之间,也就是负载均衡的最大周期不能超过max_load_balance_interval
	interval = clamp(interval, 1UL, max_load_balance_interval);

	return interval;
}
搞清楚负载均衡的周期后,开始看看处理负载均衡的函数load_balance
static int load_balance(int this_cpu, struct rq *this_rq,
			struct sched_domain *sd, enum cpu_idle_type idle,
			int *continue_balancing)
{
	
	#找到domain中最忙的group
	group = find_busiest_group(&env);
	if (!group) {
		schedstat_inc(sd->lb_nobusyg[idle]);
		goto out_balanced;
	}
	#找到最忙group中最忙的rq
	busiest = find_busiest_queue(&env, group);
	if (!busiest) {
		schedstat_inc(sd->lb_nobusyq[idle]);
		goto out_balanced;
	}

	BUG_ON(busiest == env.dst_rq);

	schedstat_add(sd->lb_imbalance[idle], env.imbalance);

	env.src_cpu = busiest->cpu;
	env.src_rq = busiest;

	ld_moved = 0;
	#如果确实存在最忙的rq
	if (busiest->nr_running > 1) {

		 #将task从最忙cpu中的rq迁移出来
		cur_ld_moved = detach_tasks(&env);
		rq_unlock(busiest, &rf);

		if (cur_ld_moved) {
		#将前面从最忙cpu rq中迁出的task 加入到目标cpu上
			attach_tasks(&env);
			ld_moved += cur_ld_moved;
		}

}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值