Man page - sched_setaffinity(2)

Packages contains this manual

Available languages:

en fr ja ru

Manual

sched_setaffinity

НАИМЕНОВАНИЕ
БИБЛИОТЕКА
ОБЗОР
ОПИСАНИЕ
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
ОШИБКИ
СТАНДАРТЫ
ИСТОРИЯ
ПРИМЕЧАНИЯ
Отличия между библиотекой C и ядром
Работа систем с масками увязывания ЦП большого размера
ПРИМЕРЫ
Исходный код программы
СМОТРИТЕ ТАКЖЕ
ПЕРЕВОД

НАИМЕНОВАНИЕ

sched_setaffinity, sched_getaffinity - устанавливает и получает процессорную маску увязывания для нити

БИБЛИОТЕКА

Стандартная библиотека языка C ( libc , -lc )

ОБЗОР

#define _GNU_SOURCE /* Смотрите feature_test_macros(7) */
#include <sched.h>

int sched_setaffinity(pid_t pid , size_t cpusetsize ,
const cpu_set_t *
mask );
int sched_getaffinity(pid_t
pid , size_t cpusetsize ,
cpu_set_t *
mask );

ОПИСАНИЕ

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

Маска увязывания ЦП представляется в виде структуры cpu_set_t , «набором процессоров», на которую указывает mask . В CPU_SET (3) описаны макросы для изменения набора ЦП.

Вызов sched_setaffinity () устанавливает маску увязывания ЦП mask для нити, чей ID указан в pid . Если значение pid равно нулю, то используется вызывающая нить. В аргументе cpusetsize задаётся количество данных (в байтах), на которые указывает mask . Обычно его значение указывается как sizeof(cpu_set_t) .

Если нить, указанная в pid , в данный момент не выполняется на одном из ЦП, заданном в mask , то эта нить переносится на один из процессоров, назначаемых mask .

Вызов sched_getaffinity () записывает в структуру cpu_set_t , на которую указывает mask , значение маски увязывания ЦП для нити, чей ID указан в pid . В аргументе cpusetsize задаётся размер mask (в байтах). Если значение pid равно нулю, то возвращается маска вызывающей нити.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

On success, sched_setaffinity () and sched_getaffinity () return 0 (but see "C library/kernel differences" below, which notes that the underlying sched_getaffinity () differs in its return value). On failure, -1 is returned, and errno is set to indicate the error.

ОШИБКИ

EFAULT

Указан некорректный адрес памяти.

EINVAL

В маске увязывания ЦП mask указаны процессоры, которых физически нет в системе, и которые разрешены нити согласно любым ограничениям, которые могут налагаться cpuset cgroups или механизмом «cpuset», описанном в cpuset (7).

EINVAL

( sched_getaffinity () and, before Linux 2.6.9, sched_setaffinity ()) cpusetsize is smaller than the size of the affinity mask used by the kernel.

EPERM

( sched_setaffinity ()) Вызывающая нить не имеет достаточно прав. Вызывающему требуется иметь эффективный пользовательский ID равный реальному пользовательскому ID или эффективному пользовательскому ID нити, указанной в pid , или он должен обладать мандатом CAP_SYS_NICE в пространстве имён пользователя нити pid .

ESRCH

Нить с идентификатором pid не найдена.

СТАНДАРТЫ

Linux.

ИСТОРИЯ

Linux 2.5.8, glibc 2.3.

Initially, the glibc interfaces included a cpusetsize argument, typed as unsigned int . In glibc 2.3.3, the cpusetsize argument was removed, but was then restored in glibc 2.3.4, with type size_t .

ПРИМЕЧАНИЯ

После вызова sched_setaffinity () набор процессоров, на которых действительно будет выполняться нить, вычисляется пересечением набора из аргумента mask и набором процессоров, присутствующих в системе. В дальнейшем, система может ограничить набор процессоров нити, если задействован механизм «cpuset», описанный в cpuset (7). Эти ограничения на действительный набор процессоров, используемых для нити, без уведомления налагаются ядром.

Есть несколько способов определения количества процессоров в системе: по содержимому /proc/cpuinfo ; с помощью sysconf (3) получить значение параметров _SC_NPROCESSORS_CONF и _SC_NPROCESSORS_ONLN ; посчитать количество подкаталогов cpu в /sys/devices/system/cpu/ .

В sched (7) приведено описание схемы планирования Linux.

Маска увязывания является атрибутом нити, которая может изменяться независимо для каждой нити в группе нитей. В аргументе pid можно передавать значение, возвращаемое вызовом gettid (2). При значении pid равным 0 будет установлен атрибут вызывающей нити, а при передаче значения, возвращаемого вызовом getpid (2), устанавливается атрибут главной нити группы нитей (при работе с программным интерфейсом POSIX используйте функцию pthread_setaffinity_np (3) вместо sched_setaffinity ()).

Параметр начальной загрузки isolcpus можно использовать для изоляции одного и более ЦП во время загрузки, и ни один процесс не будет запланирован к выполнению на этих ЦП. После использования этого параметра единственный способ запланировать процессы на изолированных ЦП — использовать sched_setaffinity () или механизм cpuset (7). Подробности смотрите в файле исходного кода ядра Documentation/admin-guide/kernel-parameters.txt . Согласно тексту файла, isolcpus является предпочтительным механизмом изоляции ЦП (по сравнению с ручным увязыванием ЦП всех процессов в системе).

Потомок, создаваемый с помощью fork (2), наследует маску увязывания ЦП. Маска увязывания сохраняется при вызове execve (2).

Отличия между библиотекой C и ядром

В данной справочной странице описан интерфейс glibc для вызовов увязывания ЦП. Интерфейс реальных системных вызов чуть отличается: аргумент mask имеет тип unsigned long * , отражая факт того, что используемая реализация наборов ЦП представляет собой просто битовую маску.

При успешном выполнении ядерный системный вызов sched_getaffinity () возвращает количество скопированных в буфер mask байт; минимальным значением будет cpusetsize и размер (в байтах) типа данных cpumask_t , который используется в ядре для представления процессорной битовой маски.

Работа систем с масками увязывания ЦП большого размера

Лежащие в основе системные вызовы (которые представляют маски ЦП в виде маски битов с типом unsigned long * ) не накладывают ограничений на размер маски ЦП. Однако, тип данных cpu_set_t , используемый в glibc, имеет постоянный размер 128 байт, то есть максимальный номер представляемых ЦП равен 1023. Если ядерная маска увязывания ЦП больше 1024, то вызовы вида:

sched_getaffinity(pid, sizeof(cpu_set_t), &mask);

завершается ошибкой EINVAL ; ошибка выдаётся подлежащим системным вызовом в случае, когда размер mask , указанный в cpusetsize , меньше чем размер маски увязывания используемой ядром (в зависимости от топологии ЦП системы, ядерная маска увязывания может быть значительно больше, чем количество активных ЦП в системе).

При работе в системах с ядерными масками увязывания ЦП большого размера, место под аргумент mask должно выделяться динамически (смотрите CPU_ALLOC (3)). В настоящее время единственный способ сделать это — определить размер требуемой маски с помощью вызовов sched_getaffinity () с увеличиваемым размером маски (пока вызов не перестанет выдавать ошибку EINVAL ).

Учтите, что CPU_ALLOC (3) может выделить несколько больший набор ЦП, чем запрашивается (так как наборы ЦП реализованы как битовые маски, выделяемые в объёмах sizeof(long) ). Следовательно, sched_getaffinity () может задать биты за границами запрашиваемого выделяемого размера, так как ядро видит несколько дополнительных бит. Поэтому вызывающий должен пройтись по всем возвращённым битам, считая установленные и остановиться при достижении значения, полученного от CPU_COUNT (3) (а не останавливаться на количестве запрошенных к выделению бит).

ПРИМЕРЫ

Программа, представленная ниже, создаёт дочерний процесс. Затем родитель и потомок назначают выполнение себя на указанных ЦП и выполняют одинаковые циклы, которые выполняются на ЦП какое-то время. Перед завершением, родитель ждёт завершения потомка. Программа имеет три аргумента командной строки: номер ЦП для родителя, номер ЦП для потомка и количество итераций цикла, который будут выполнять оба процесса.

В примере работы, показанном ниже, количество реального времени и времени использованного ЦП при работе программы, будет зависеть он меж ядерного кэширования и будут ли процессы использовать одинаковый ЦП.

Сначала запустим lscpu (1) для определения, что эта система (x86) имеет по два потока выполнения в двух ЦП:

$ lscpu | egrep -i 'core.*:|socket'
Thread(s) per core: 2
Core(s) per socket: 2
Socket(s): 1

Затем запустим подсчёт времени выполнения программы для трёх случаев: оба процесс выполняются на одном ЦП; оба процесса выполняются на разных ЦП одного ядра; оба процесса выполняются на разных ЦП разных ядер.

$ time -p ./a.out 0 0 100000000
real 14.75
user 3.02
sys 11.73
$ time -p ./a.out 0 1 100000000
real 11.52
user 3.98
sys 19.06
$ time -p ./a.out 0 3 100000000
real 7.89
user 3.29
sys 12.07

Исходный код программы

#define _GNU_SOURCE
#include <err.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
int parentCPU, childCPU;
cpu_set_t set;
unsigned int nloops;
if (argc != 4) {
fprintf(stderr, "Usage: %s parent-cpu child-cpu num-loops\n",
argv[0]);
exit(EXIT_FAILURE);
}
parentCPU = atoi(argv[1]);
childCPU = atoi(argv[2]);
nloops = atoi(argv[3]);
CPU_ZERO(&set);
switch (fork()) {
case -1: /* Error */
err(EXIT_FAILURE, "fork");
case 0: /* Child */
CPU_SET(childCPU, &set);
if (sched_setaffinity(getpid(), sizeof(set), &set) == -1)
err(EXIT_FAILURE, "sched_setaffinity");
for (unsigned int j = 0; j < nloops; j++)
getppid();
exit(EXIT_SUCCESS);
default: /* Parent */
CPU_SET(parentCPU, &set);
if (sched_setaffinity(getpid(), sizeof(set), &set) == -1)
err(EXIT_FAILURE, "sched_setaffinity");
for (unsigned int j = 0; j < nloops; j++)
getppid();
wait(NULL); /* Wait for child to terminate */
exit(EXIT_SUCCESS);
}
}

СМОТРИТЕ ТАКЖЕ

lscpu (1), nproc (1), taskset (1), clone (2), getcpu (2), getpriority (2), gettid (2), nice (2), sched_get_priority_max (2), sched_get_priority_min (2), sched_getscheduler (2), sched_setscheduler (2), setpriority (2), CPU_SET (3), get_nprocs (3), pthread_setaffinity_np (3), sched_getcpu (3), capabilities (7), cpuset (7), sched (7), numactl (8)

ПЕРЕВОД

Русский перевод этой страницы руководства разработал(и) Alexander Golubev <fatzer2@gmail.com>, Azamat Hackimov <azamat.hackimov@gmail.com>, Hotellook, Nikita <zxcvbnm3230@mail.ru>, Spiros Georgaras <sng@hellug.gr>, Vladislav <ivladislavefimov@gmail.com>, Yuri Kozlov <yuray@komyakino.ru>, Иван Павлов <pavia00@gmail.com> и Kirill Rekhov <krekhov.dev@gmail.com>

Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков .