#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 следует выделить? Во-вторых, наследование сходства не помогает, я буду разветвлять несколько дочерних элементов от родителя и хочу, чтобы каждый из них получил другое ядро процессора (в этом небольшом коде я не показал несколько разветвлений).