1

I can allocate a cpu core to a process, by running it like this:

taskset -c 21 ./wait xx

Here, ./wait is an executable, whose code is shown below, and I am trying to assign the core=21 to this process.

But when I try to do the same from another process (using execl), it does not work. Eg, the following code executes the process (no errors reported), but the core allocation to that process is not done:

// run as: ./a.out name 21
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>

int main(int argc, char* argv[]) {
    printf("scheduling\n");
    int status = execl("/usr/bin/taskset", "-c", argv[2], "./wait", argv[1], NULL);
    if(status<0) perror("Err:");
}

Here is the code for the wait program, it just waits for user to give some input, so that I get time to check the cpu status from another terminal:

// run as: ./wait name
#include <stdio.h>
#include <stdarg.h>

int main(int argc, char* argv[]) {
    printf("%s:asking for user input\n", argv[1]);
    int x;
    scanf("%d", &x);
    printf("got-%d\n", x);
}

So, my question is: how to allocate the cpu-core using execl when running a process? (BTW, if the process is already running and I have its pid, then exec of taskset on that pid will change that process's core allocation. It does not work only when it is done in the way shown here.)

R71
  • 4,283
  • 7
  • 32
  • 60
  • 3
    Your call to `execl()` has a bug: it's missing the arg0 parameter, so it interprets `-c` as arg0, which causes taskset to take argv[2] as a bitmask rather than a list of cpus. Change the call to `execl("/usr/bin/taskset", "taskset", "-c", ...)` and it will work as intended. – Cuspy Code Sep 20 '21 at 17:14
  • @CuspyCode That sounds like a full on Answer. It would be great if you'd make it one, so that it we could upvote it, and the OP could accept it. – trlkly Sep 21 '21 at 08:54
  • @CuspyCode: actually that's what I did, otherwise the program would not even run. It was a typo in my question, I have fixed it now. But if you had first tried out your own solution, you would have noticed that the program is running, but the core is not getting allocated, and that is what I am asking, why the core is not getting allocated this way. – R71 Sep 22 '21 at 00:43
  • @R71 That's strange, because your original code ran when I tried. `taskset` needs to be found in `$PATH` of course, but it executed without error messsages. The core allocation was incorrect, but that was corrected after the bug fix. I tested both versions on an old 8-core AMD Opteron 4284. – Cuspy Code Sep 22 '21 at 06:27

2 Answers2

3

You need to supply the process name to be argv[0] in the child:

int status = execl("/usr/bin/taskset",
                   "taskset", "-c", argv[2], "./wait", argv[1], NULL);

With the name missing, the program is invoked as -c 21 ./wait xx instead of taskset -c 21 ./wait xx that we intended, meaning that it won't see the -c as argument, and will instead interpret 21 as a mask (processors 0 and 5) rather than a list (processor 21 only).

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
  • Pls see my comment in the main question. It was a typo in my question, without the path the code would not even run. But.my code runs, only not on the core that I am allocating, and that is my question. – R71 Sep 22 '21 at 00:53
  • @R71 You need both the path to the executable, e.g. `/usr/bin/taskset`, and also a separate value for arg0 to be used for the process name, e.g. `taskset`. If you omit this separate value, arg0 will be `-c` and this will taken as the process name instead of being interpreted as a command option. So the options sent to taskset will then be `21 ./wait xx`. And without the `-c`, 21 is a bitmask, not a list of cpu numbers. – Cuspy Code Sep 22 '21 at 09:27
  • @R71 If it's a typo in the question, why not fix it? As it stands now, the first two argments to `execl()` are `"/usr/bin/taskset", "-c"` rather than `"/usr/bin/taskset", "taskset"` as here. Meaning that the program is invoked as `-c 21 ./wait xx` instead of `taskset -c 21 ./wait xx` as desired. – Toby Speight Sep 22 '21 at 09:44
  • @TobySpeight: my bad, I had missed the 2nd argument, ie "taskset". It works now, I will accept your answer. – R71 Sep 23 '21 at 07:43
0

It might be easier to fork the process and then set your CPU affinity before executing the command.

Something like the following.

Linux:

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <sys/sysinfo.h>

int main()
{
    cpu_set_t  mask;
    CPU_ZERO(&mask);
   
    CPU_SET(0, &mask);
    CPU_SET(1, &mask);
    CPU_SET(2, &mask);
    CPU_SET(3, &mask);
    sched_setaffinity(0, sizeof(mask), &mask);
}

Windows:

#include <Windows.h>

int main()
{
           ::SetProcessAffinityMask(GetCurrentProcess(), 0xf/*first 4 cpus*/);
}

Code examples found in How to Set CPU Affinity of a Process.

harrymc
  • 1,069
  • 8
  • 33
  • That is what I said in my last para, that works. My question was, how do I do the allocation when I start the process itself? – R71 Sep 20 '21 at 15:51
  • @R71: You do it in the process _that's starting this process_, before you call exec(). – user1686 Sep 20 '21 at 17:14
  • 1
    The CPU affinity is *inherited* by the child process. – harrymc Sep 21 '21 at 10:12
  • I am not sure I am understanding what you are saying. Are you saying first I need to allocate core, then call exec? But if I have not yet exec'd the process, then how do I know the pid to allocate? Secondly, inheriting the affinity does not help, I will be forking multiple children from the parent and want each of them to get a different cpu core (in this small code I have not shown the multiple forks). – R71 Sep 22 '21 at 00:50