多核编程与CPU亲和力

多核编程

多核编程和多线程编程还是有一些差异的,对于多线程编程,我们可以创建多个线程去处理业务,但是不会关心具体哪个进程运行在哪个CPU上,而多核的意思则是可以把特定任务绑定到特定的CPU上运行。这样的好处是什么?能够把重要的任务独立到一个CPU上运行,从而不受其他任务影响,提升该任务的响应速度。通过CPU绑定也能提升cache命中率,从而提高性能。具体到使用上,就是利用如下API绑定CPU:

int sched_setaffinity(pid_t pid, size_t cpusetsize,
 cpu_set_t *mask);

int sched_getaffinity(pid_t pid, size_t cpusetsize,
 cpu_set_t *mask);

内核实现

long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
{

......
	cpuset_cpus_allowed(p, cpus_allowed);
	cpumask_and(new_mask, in_mask, cpus_allowed);
	retval = set_cpus_allowed_ptr(p, new_mask);
......
}

这个函数中有关键的3个步骤,取出当前task进程中的cpus_allowed bitmap mask,然后通过cpumask_and与in_mask进行位与操作,最后把cpuset mask设置到对应的task进程结构体中set_cpus_allowed_ptr,这个函数的目的就是把pid对应进程绑定到in_mask中指定的cpu上运行。下面看一下cpus_allowed是在哪里生效的:

static inline
int select_task_rq(struct task_struct *p, int cpu, int sd_flags, int wake_flags)
{
    if (p->nr_cpus_allowed > 1)
        cpu = p->sched_class->select_task_rq(p, cpu, sd_flags, wake_flags);

    /*
     * In order not to call set_task_cpu() on a blocking task we need
     * to rely on ttwu() to place the task on a valid ->cpus_allowed
     * cpu.
     *
     * Since this is common to all placement strategies, this lives here.
     *
     * [ this allows ->select_task() to simply return task_cpu(p) and
     *   not worry about this generic constraint ]
     */
    if (unlikely(!cpumask_test_cpu(cpu, tsk_cpus_allowed(p)) ||
             !cpu_online(cpu)))
        cpu = select_fallback_rq(task_cpu(p), p);

    return cpu;
}

这里当进程wakeup或者fork时,内核会执行到select_task_rq函数,该函数中会对cpus_allowed进行检测,对于当前进程不允许的cpu,会对该进程重新选择runqueue,把当前进程放到允许运行的cpu runqueue上:

if (unlikely(!cpumask_test_cpu(cpu, tsk_cpus_allowed(p)) ||
             !cpu_online(cpu)))
        cpu = select_fallback_rq(task_cpu(p), p);

你可能感兴趣的:(内核笔记)