как выделить процессор для выполнения процесса

#linux #ubuntu #exec #taskset

Вопрос:

Я могу выделить процессорное ядро для процесса, запустив его следующим образом:

 taskset -c 21 ./wait xx
 

Здесь ./wait-это исполняемый файл, код которого показан ниже, и я пытаюсь присвоить этому процессу core=21.

Но когда я пытаюсь сделать то же самое из другого процесса (используя execl), это не работает. Например, следующий код выполняет процесс (об ошибках не сообщается), но выделение ядра для этого процесса не выполняется:

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

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

Вот код для программы ожидания, она просто ждет, пока пользователь введет некоторые данные, чтобы у меня было время проверить состояние процессора с другого терминала:

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

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

Итак, мой вопрос: как выделить ядро процессора с помощью execl при запуске процесса? (Кстати, если процесс уже запущен и у меня есть его pid, то исполнитель набора задач для этого pid изменит распределение ядра этого процесса. Это работает не только тогда, когда это делается так, как показано здесь.)

Комментарии:

1. В вашем вызове execl() есть ошибка: в нем отсутствует параметр arg0, поэтому он интерпретируется -c как arg0, что приводит к тому, что набор задач принимает argv[2] как битовую маску, а не список процессоров. Измените вызов на execl("/usr/bin/taskset", "taskset", "-c", ...) , и он будет работать так, как задумано.

2. @CuspyCode, Это звучит как полный ответ. Было бы здорово, если бы вы сделали это так, чтобы мы могли проголосовать за это, и ОП мог бы принять это.

3. @CuspyCode: на самом деле именно это я и сделал, иначе программа даже не запустилась бы. Это была опечатка в моем вопросе, теперь я ее исправил. Но если бы вы сначала опробовали свое собственное решение, вы бы заметили, что программа запущена, но ядро не выделяется, и именно это я спрашиваю, почему ядро не выделяется таким образом.

4. @R71 Это странно, потому что ваш исходный код запустился, когда я попытался. taskset $PATH конечно, его нужно найти, но он выполнен без ошибок. Распределение ядра было неправильным, но это было исправлено после исправления ошибки. Я протестировал обе версии на старом 8-ядерном AMD Opteron 4284.

Ответ №1:

Вам необходимо указать имя процесса, чтобы оно было argv[0] в дочернем:

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

Если имя отсутствует, программа вызывается как -c 21 ./wait xx вместо taskset -c 21 ./wait xx того, что мы намеревались, что означает, что она не будет видеть аргумент -c as и вместо этого будет интерпретировать 21 как маску (процессоры 0 и 5), а не список (только процессор 21).

Комментарии:

1. Пожалуйста, посмотрите мой комментарий в главном вопросе. Это была опечатка в моем вопросе, без пути код даже не запустился бы. But.my код выполняется, только не на ядре, которое я выделяю, и это мой вопрос.

2. @R71 Вам нужен как путь к исполняемому файлу, например /usr/bin/taskset , так и отдельное значение для arg0, которое будет использоваться для имени процесса, например taskset . Если вы опустите это отдельное значение, будет arg0 -c , и оно будет приниматься как имя процесса, а не интерпретироваться как параметр команды. Таким образом, параметры, отправленные в набор задач, будут следующими 21 ./wait xx . И без -c этого 21-это битовая маска, а не список номеров процессоров.

3. @R71 Если это опечатка в вопросе, почему бы ее не исправить? Как это происходит сейчас, первые два аргумента execl() "/usr/bin/taskset", "-c" скорее, чем "/usr/bin/taskset", "taskset" здесь. Это означает, что программа вызывается как -c 21 ./wait xx , а taskset -c 21 ./wait xx не как требуется.

4. @TobySpeight: плохо, что я пропустил 2-й аргумент, т. е. «набор задач». Это работает сейчас, я приму ваш ответ.

Ответ №2:

Возможно, будет проще разветвить процесс, а затем установить соответствие процессора перед выполнением команды.

Что-то вроде следующего.

Линукс:

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

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

Windows:

 #include <Windows.h>

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

Примеры кода, приведенные в
разделе Как установить соответствие ЦП процесса.

Комментарии:

1. Вот что я сказал в своем последнем параграфе, это работает. Мой вопрос состоял в том, как мне выполнить распределение, когда я начинаю сам процесс?

2. @R71: Вы делаете это в процессе, который запускает этот процесс , прежде чем вызывать exec().

3. Сходство ЦП наследуется дочерним процессом.

4. Я не уверен, что понимаю, о чем вы говорите. Вы хотите сказать, что сначала мне нужно выделить ядро, а затем позвонить исполнителю? Но если я еще не выполнил процесс, то как мне узнать, какой pid следует выделить? Во-вторых, наследование сходства не помогает, я буду разветвлять несколько дочерних элементов от родителя и хочу, чтобы каждый из них получил другое ядро процессора (в этом небольшом коде я не показал несколько разветвлений).