在新建一个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