目前cpu亲缘性设置有两种方式:
- 通过sched_setaffinity()函数将进程绑定到某些cpu上运行
- 讲进程加入到cpuset控制组,通过修改cpuset.cpus参数来实现亲缘性设置
但是有一点需要注意的是,通过sched_setaffinity设置的cpu_mask不允许超出cpuset.cpus的范围,超出部分是无效的。
举例,进程A所在的cpuset控制组cpuset.cpus参数值是0,1,2,3,4,但是进程运行期间调用sched_setaffinity()修改cpu_mask为0,1,2,4,7。因为7并不在cpuset.cpus范围里,所以内核会把7忽略掉,最终进程只能在0,1,2,4这几个CPU上运行。
// linux-3.10.82/kernel/sched/core.c
long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
{
cpumask_var_t cpus_allowed, new_mask;
struct task_struct *p;
int retval;
get_online_cpus();
rcu_read_lock();
p = find_process_by_pid(pid);
if (!p) {
rcu_read_unlock();
put_online_cpus();
return -ESRCH;
}
/* Prevent p going away */
get_task_struct(p);
rcu_read_unlock();
if (p->flags & PF_NO_SETAFFINITY) {
retval = -EINVAL;
goto out_put_task;
}
if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) {
retval = -ENOMEM;
goto out_put_task;
}
if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) {
retval = -ENOMEM;
goto out_free_cpus_allowed;
}
retval = -EPERM;
if (!check_same_owner(p)) {
rcu_read_lock();
if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) {
rcu_read_unlock();
goto out_unlock;
}
rcu_read_unlock();
}
retval = security_task_setscheduler(p);
if (retval)
goto out_unlock;
cpuset_cpus_allowed(p, cpus_allowed);
cpumask_and(new_mask, in_mask, cpus_allowed);
again:
retval = set_cpus_allowed_ptr(p, new_mask);
if (!retval) {
cpuset_cpus_allowed(p, cpus_allowed);
if (!cpumask_subset(new_mask, cpus_allowed)) {
/*
* We must have raced with a concurrent cpuset
* update. Just reset the cpus_allowed to the
* cpuset's cpus_allowed
*/
cpumask_copy(new_mask, cpus_allowed);
goto again;
}
}
out_unlock:
free_cpumask_var(new_mask);
out_free_cpus_allowed:
free_cpumask_var(cpus_allowed);
out_put_task:
put_task_struct(p);
put_online_cpus();
return retval;
}
如上所见,当调用sched_setaffinity系统调用时,内核会将in_mask与 cpuset_cpus_allowed 做一次与操作