nohz load balance选择cpu

如果开启了nohz,在busy的cpu上,每次时钟中断的时候会发起nohz load balance。它的一个关键点是选择一个idle cpu。

static void nohz_balancer_kick(struct rq *rq)
{
...
out:
        if (flags)
                kick_ilb(flags);
}

static void kick_ilb(unsigned int flags)
{
        int ilb_cpu;

...
        ilb_cpu = find_new_ilb();

  ...
        smp_call_function_single_async(ilb_cpu, &cpu_rq(ilb_cpu)->nohz_csd);
}

可见find_new_ilb负责找和是的idle cpu。

static inline int find_new_ilb(void)
{
        int ilb;

        for_each_cpu_and(ilb, nohz.idle_cpus_mask,
                              housekeeping_cpumask(HK_FLAG_MISC)) {
                if (idle_cpu(ilb))
                        return ilb;
        }  
                
        return nr_cpu_ids;
}

idle cpu是从nohz.idle_cpus_mask和HK_FLAG_MISC 类型的housekeeping cpu的交集中得到的。nohz是一个全局变量。

static struct {
    cpumask_var_t idle_cpus_mask;
    atomic_t nr_cpus;
    int has_blocked;        /* Idle CPUS has blocked load */
    int needs_update;        /* Newly idle CPUs need their next_balance collated */
    unsigned long next_balance;     /* in jiffy units */
    unsigned long next_blocked;    /* Next update of blocked load in jiffies */
} nohz ____cacheline_aligned;

idle_cpus_mask表示可以用于nohz idle balance的cpumask,nr_cpus表示idle_cpus_mask所包含的cpu的数量。has_blocked表示???

哪些cpu会加入idle_cpus_mask?

void nohz_balance_enter_idle(int cpu)
{
...
        cpumask_set_cpu(cpu, nohz.idle_cpus_mask);
        atomic_inc(&nohz.nr_cpus);
...
        WRITE_ONCE(nohz.has_blocked, 1);
}

该函数会在cpu进入idle状态前调用。

那么housekeeping cpu又是做什么的?

housekeeping cpu是为了减少系统中断,内核线程的影响,将这些内核任务隔离到housekeeping cpu上去。默认情况下所有cpu都被认为是housekeeping cpu。

const struct cpumask *housekeeping_cpumask(enum hk_type type)
{
    if (static_branch_unlikely(&housekeeping_overridden))
        if (housekeeping.flags & BIT(type))
            return housekeeping.cpumasks[type];
    return cpu_possible_mask;
}

一般housekeeping_overridden是没有被设置的,所以所有的cpu都被认为是housekeeping cpu。

了解到nohz balance选cpu的范围,还有一个顺序的问题。for_each_cpu_and会从前往后找cpu,也就是排在前面的idle cpu会被选中的概率更大。

可以使用bpftrace来验证一下nohz选cpu的频率。

#!/usr/bin/env bpftrace

kfunc:smp_call_function_single_async
{
    @cpu[args->cpu, cpu]= count();
}

 

posted on 2025-02-01 18:25  半山随笔  阅读(65)  评论(0)    收藏  举报

导航