Provided by: manpages-ru-dev_4.27.0-1_all bug

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

       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 или
       более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

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

Справочные страницы Linux 6.9.1                  15 июня 2024 г.                            sched_setaffinity(2)