2
votes

Let's say I want to programmatically pin the current process to a single CPU, but I don't care which CPU that is.

One easy way to use sched_setaffinity with a fixed CPU number, probably 0 since there should always be a "CPU 0"1.

However, this approach fails if the affinity of the process has been set to a subset of the existing CPUs, not including the one you picked, e.g., by launching it with taskset.

So I want to pick "any CPU" to pin to, but only out of the CPUs that the current affinity mask allows. Here's one approach:

cpu_set_t cpu_set;
if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set)) {
    err("failed while getting existing cpu affinity");
}
for (int cpu = 0; cpu < CPU_SETSIZE; cpu++) {
    if (CPU_ISSET(cpu, &cpu_set)) {
        CPU_ZERO(cpu_set);
        CPU_SET(cpu, &cpu_set);
    }
}
int result = sched_setaffinity(0, sizeof(cpu_set), &cpu_set);

Basically we get the current affinity mask, then loop over every possible CPU looking for the first one that is allowed, then pass a mask with only this CPU set to sched_setaffinity.

However, if the current affinity mask has changed between the get and set calls the set call will fail. Any way around this race condition?


1 Although CPU zero won't always be online.

2

2 Answers

1
votes

You could use getcpu() to discover the cpu that your process is running within, and use the result to set affinity to that cpu:

unsigned mycpu=0;
if( -1 == getcpu(&mycpu,NULL,NULL) ) {
   // handle error
}

Presumably any CPU affinity rules that are in place would be honored by the scheduler, thus the getcpu() call would return a CPU that the process is allowed to run on.

There's still the potential that the affinity set might change, but that seems like a very unlikely case, and the allowed CPUs might be affected at some point in the future, outside the control of the process in question.

I suppose you could detect the error in the sched_setaffinity() call, and retry the process until the setaffinity call works...

0
votes

Considering that the affinity mask of the process can change at any moment, you can iteratively try to pin the process to the current CPU and stop when it is successful.

cpu_set_t cpu_set;

int cpu = 0;
int result = -1;

while (result<0){

    cpu = sched_getcpu();
    if (cpu>0){
        CPU_ZERO(&cpu_set);
        CPU_SET(cpu, &cpu_set);
        result = sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
    }
}