【内核调度、负载均衡】【select_task_rq_fair】

本文详细解析了Linux内核调度器中的负载均衡机制,重点介绍了select_task_rq_fair函数如何选择目标运行队列,以及find_idlest_cpu和find_idlest_group_cpu函数在寻找最空闲CPU过程中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在新建一个task或者block的task被唤醒的时候,也会执行负载均衡,调用的函数是select_task_rq_fair

和内核周期性调度相似(寻找最忙的cpu上的任务,然后把该任务pull过来执行。或者从最忙的cpu上将当时正在执行的任务停掉,然后放到local cpu上去执行)。只是他寻找的是最idlest的cpu来运行task

select_task_rq_fair

/*
 * select_task_rq_fair: Select target runqueue for the waking task in domains
 * that have the 'sd_flag' flag set. In practice, this is SD_BALANCE_WAKE,
 * SD_BALANCE_FORK, or SD_BALANCE_EXEC.
 *
 * Balances load by selecting the idlest cpu in the idlest group, or under
 * certain conditions an idle sibling cpu if the domain has SD_WAKE_AFFINE set.
 *
 * Returns the target cpu number.
 *
 * preempt must be disabled.
 */
static int
select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_flags,
		    int sibling_count_hint)
{
	struct sched_domain *tmp, *affine_sd = NULL;
	struct sched_domain *sd = NULL, *energy_sd = NULL;
	int cpu = smp_processor_id();
	int new_cpu = prev_cpu;/* 默认new_cpu为prev_cpu */
	int want_affine = 0;
	int want_energy = 0;
	int sync = wake_flags & WF_SYNC;

	if (energy_aware()) {//使用EAS做负载均衡
		rcu_read_lock();
		new_cpu = find_energy_efficient_cpu(energy_sd, p,
				cpu, prev_cpu, sync);

		if (new_cpu == -1)
			new_cpu = prev_cpu;

		rcu_read_unlock();
		return new_cpu;
	}

	rcu_read_lock();

	if (sd_flag & SD_BALANCE_WAKE) {
		record_wakee(p);
		want_energy = wake_energy(p, prev_cpu, sd_flag, wake_flags);
		want_affine = !want_energy &&
				//!wake_wide(p)  当前cpu的唤醒次数没有超标
			      !wake_wide(p, sibling_count_hint) &&//
			      !wake_cap(p, cpu, prev_cpu) &&
				  //pumask_test_cpu(cpu, tsk_cpus_allowed(p)) // 当前cpu在进程在P的affinity中
			      cpumask_test_cpu(cpu, &p->cpus_allowed);
	}
	/* (4) 从下往上遍历当前cpu的sd,查询在哪个层次的sd进行负载均衡 */
	for_each_domain(cpu, tmp) {
		if (!(tmp->flags & SD_LOAD_BALANCE))
			break;

		/*
		 * If both cpu and prev_cpu are part of this domain,
		 * cpu is a valid SD_WAKE_AFFINE target.
		 */
		if (want_affine && (tmp->flags & SD_WAKE_AFFINE) &&
		    cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) {
			affine_sd = tmp;
			brea
### CPU选核调度栈中`select_task_rq_fair`函数的作用及调用链分析 #### 1. `select_task_rq_fair` 函数作用 `select_task_rq_fair` 是 Linux 内核公平调度类 (`fair_sched_class`) 的一部分,主要用于为即将运行的任务选择最适合的运行队列 (Run Queue, RQ)。该函数综合考虑了多种因素,例如任务的历史迁移成本、目标CPU的负载均衡状态以及能量效率等因素[^3]。 以下是 `select_task_rq_fair` 的主要功能分解: - **负载均衡**: 它会尝试将任务分配到负载较低的CPU上,从而提高整体系统的吞吐量。 - **亲和性约束**: 尊重任务的CPU亲和性设置 (`task_struct::cpus_ptr`),确保任务仅在允许的范围内运行。 - **节能策略**: 结合能耗模型,优先选择能效更高的CPU核心以降低功耗[^2]。 ```c int select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flags) { ... if (sched_feat(LB_BIAS)) new_cpu = cpumask_any_and(p->cpus_ptr, imbalance_mask); // 如果启用了节能策略,则尝试找到更高效的cpu if (sd && !(wake_flags & WF_TTWU)) { new_cpu = mtk_find_energy_efficient_cpu(p); } ... return new_cpu; } ``` --- #### 2. 调用链分析 ##### (1)`try_to_wake_up` 当一个任务被唤醒时,`try_to_wake_up` 函数会被调用。它是任务唤醒的核心入口之一,负责更新任务的状态并将任务放入适当的运行队列中。在此过程中,`try_to_wake_up` 会调用 `select_task_rq` 来确定目标任务应该运行在哪一个CPU上[^1]。 ```c int try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) { ... next_cpu = select_task_rq(p, SD_BALANCE_WAKE, wake_flags); set_task_cpu(p, next_cpu); enqueue_task(rq, p, ENQUEUE_WAKING | ENQUEUE_MIGRATED); ... } ``` ##### (2)`wake_up_new_task` 对于新建的任务,`wake_up_new_task` 函数会在初始化完成后将其加入到运行队列中。同样地,它也会调用 `select_task_rq` 来完成CPU的选择工作。 ```c void wake_up_new_task(struct task_struct *p) { ... cpu = select_task_rq(p, SD_BALANCE_FORK, 0); set_task_cpu(p, cpu); enqueue_task(rq_of(cpu), p, ENQUEUE_NOCLOCK); ... } ``` ##### (3)`futex_wake` Futex机制是Linux内核提供的一种轻量级同步工具,广泛应用于用户态线程库(如pthread)。当某个条件变量满足时,`futex_wake` 会唤醒等待的线程,并通过调用 `sys_futex` 系统调用间接触发 `try_to_wake_up` 和 `select_task_rq_fair` 的执行链条[^1]。 ```c long sys_futex(u32 __user *uaddr, int op, u32 val, ...) { ... ret = futex_wait_setup(...); if (!ret) { queue_me(...); if (!(flags & FLAGS_SHARED)) current->robust_list = NULL; schedule(); // 唤醒其他进程时发生的调度行为 unqueue_me_pi(...); } return ret; } ``` ##### (4)`__traceiter_sched_runnable_boost` 从日志信息来看,`__traceiter_sched_runnable_boost` 是跟踪可运行任务提升的关键点之一。它可以记录任务是否具备运行资格以及是否有足够的资源支持其运行。这一部分通常与性能监控和调试密切相关。 --- ### 总结说明 在整个CPU选核的过程中,`select_task_rq_fair` 扮演着至关重要的角色。它不仅决定了任务的初始放置位置,还直接影响了系统的负载分布和能源消耗状况。通过对上述调用链的分析可以看出,无论是任务创建、唤醒还是同步操作,都离不开这一核心函数的支持。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值