sched_setaffinity(2) System Calls Manual sched_setaffinity(2) NAZWA sched_setaffinity, sched_getaffinity - ustawia i pobiera maske koligacji procesora dla watku BIBLIOTEKA Standardowa biblioteka C (libc, -lc) SKLADNIA #define _GNU_SOURCE /* Patrz feature_test_macros(7) */ #include 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); OPIS Maska koligacji procesora watku okresla zbior procesorow, na ktorych moze on dzialac. W systemach wieloprocesorowych ustawiajac maske koligacji procesora mozna, w okreslonych sytuacjach, zyskac na wydajnosci. Na przyklad przeznaczajac jeden procesor na dany watek (tj. ustawiajac maske koligacji tego watku tak, aby okreslala pojedynczy procesor i ustawiajac maske koligacji wszystkich innych watkow tak, aby pomijala ten procesor) mozna zapewnic maksymalna szybkosc wykonywania danego watku. Ograniczenie mozliwosci dzialania watku do pojedynczego procesora pozwala tez na unikniecie narzutu wynikajacego z uniewazniania bufora zachodzacego, gdy watek przestaje byc wykonywany na jednym procesorze, a nastepnie wznawia wykonywanie na kolejnym. Maska koligacji procesora jest reprezentowana przez strukture cpu_set_t, ,,zbior procesorow", na ktora wskazuje mask. Zbior makr do operowania na zbiorach procesorow opisano w podreczniku CPU_SET(3). sched_setaffinity() ustawia maske koligacji procesora watku o identyfikatorze pid, na wartosc okreslona przez mask. Jesli pid wynosi zero, uzywany jest watek wywolujacy. Argument cpusetsize jest dlugoscia (w bajtach) danych, na ktore wskazuje mask. Argument ten zwykle nalezy podac jako sizeof(cpu_set_t). Jesli watek podany w pid nie dziala obecnie na jednym z procesorow okreslonych w mask, to watek ten zostanie zmigrowany na jeden z procesorow okreslonych w mask. sched_getaffinity() zapisuje maske koligacji procesora watku o identyfikatorze pid do struktury cpu_set_t, na ktora wskazuje mask. Argument cpusetsize okresla rozmiar mask (w bajtach). Jesli pid wynosi zero, wywolanie zwraca maske watku wywolujacego. WARTOSC ZWRACANA W przypadku powodzenia, sched_setaffinity() i sched_getaffinity() zwracaja 0 (lecz zob. ,,Roznice biblioteki C/jadra" ponizej, gdzie opisano roznice w zwracanej wartosci w podleglym sched_getaffinity()). W razie wystapienia bledu zwracane jest -1 i ustawiane errno, wskazujac blad. BLEDY EFAULT Podany adres pamieci byl nieprawidlowy. EINVAL Maska bitowa koligacji mask nie zawierala zadnego procesora obecnego fizycznie w systemie, ktory jest jednoczesnie dozwolony do uzycia przez watek, biorac pod uwage wszelkie ograniczenia, jakie moga wynikac z grup kontrolnych cpuset i mechanizmu ,,cpuset" opisanego w podreczniku cpuset(7). EINVAL (sched_getaffinity() i, przed Linuksem 2.6.9, sched_setaffinity()) cpusetsize jest mniejszy od rozmiaru maski koligacji uzywanego przez jadro. EPERM (sched_setaffinity()) Watek wywolujacy nie ma odpowiednich przywilejow. Wywolujacy musi miec efektywny identyfikator uzytkownika rowny rzeczywistemu identyfikatorowi uzytkownika albo efektywnemu identyfikatorowi uzytkownika watku podanego w pid, albo musi posiadac przywilej CAP_SYS_NICE w przestrzeni nazw uzytkownika watku podanego w pid. ESRCH Nie znaleziono watku o identyfikatorze rownym pid. STANDARDY Linux. HISTORIA Linux 2.5.8, glibc 2.3. Poczatkowo, intefejsy glibc ujete w argumencie cpusetsize byly typu unsigned int. W glibc 2.3.3, usunieto argument cpusetsize, jednak przywrocono go w glibc 2.3.4, tym razem jako size_t. UWAGI Po wywolaniu do sched_setaffinity(), zbior procesorow, na ktorych watek faktycznie bedzie uruchomiony, jest iloczynem zbioru podanego w argumencie mask oraz zbioru procesorow faktycznie obecnych w systemie. System moze dodatkowo ograniczyc zbior procesorow, na ktorych dziala watek, jesli uzywany jest mechanizm ,,cpuset" opisany w podreczniku cpuset(7). Ograniczenia te, dotyczace faktycznego zbioru procesorow, na ktorych watek bedzie dzialal, sa ezgekwowane po cichu przez jadro. Istnieje wiele sposobow na sprawdzenie liczby procesorow dostepnych w systemie, w tym: sprawdzenie zawartosci /proc/cpuinfo; skorzystanie z sysconf(3) do pozyskania wartosci parametrow _SC_NPROCESSORS_CONF i _SC_NPROCESSORS_ONLN oraz sprawdzenie listy katalogow procesorow w /sys/devices/system/cpu/. Podrecznik sched(7) zawiera opis szeregowania zadan w Linuksie. Maska koligacji procesora jest atrybutem przynaleznym watkowi, ktory mozna dostosowac niezaleznie dla kazdego watku w grupie watkow. Wartosc zwracana z wywolania do gettid(2) mozna przekazac w argumencie pid. Okreslenie pid jako 0 ustawi atrybut watku wywolujacego, a przekazanie wartosci zwroconej z wywolania do getpid(2) ustawi atrybut glownego watku w grupie watkow. Jesli korzysta sie z interfejsu watkow POSIX, zamiast sched_setaffinity() nalezy stosowac pthread_setaffinity_np(3). Za pomoca opcji rozruchowej isolcpus mozna wyizolowac jeden lub wiecej procesorow przy rozruchu, dzieki czemu zadne procesy nie zostana na nich uruchomione. Po zastosowaniu tej opcji rozruchowej, jedynym sposobem przydzielenia watkow na wyizolowane procesory jest mechanizm cpuset(7) lub sched_setaffinity(). Wiecej informacji znajduje sie w pliku Documentation/admin-guide/kernel-parameters.txt w zrodlach jadra. Jak wskazano w tym pliku, preferowanym sposobem izolowania procesorow jest isolcpus (w porownaniu do alternatywy, w postaci recznego ustawiania koligacji procesorow dla wszystkich procesow w systemie). Potomek utworzony za pomoca fork(2) dziedziczy maske koligacji procesora swojego rodzica. Maska koligacji jest zachowywana poprzez execve(2). Roznice biblioteki C/jadra Niniejszy podrecznik opisuje interfejs glibc wywolan koligacji procesora. Rzeczywisty interfejs wywolania systemowego jest nieco odmienny, poniewaz mask jest typu unsigned long *, odzwierciedlajac fakt, ze podlegla implementacja zbiorow procesorow jest prosta maska bitowa. W przypadku powodzenia, surowe wywolanie systemowe sched_getaffinity() zwraca liczbe umieszczonych bajtow, skopiowanych do bufora mask; bedzie to mniejsza z: cpusetsize oraz rozmiaru (w bajtach) typu danych cpumask_t, ktory sluzy wewnetrznie w jadrze do reprezentacji maski bitowej zbioru procesorow. Obsluga systemow z duzymi maskami koligacji procesora Podlegle wywolanie systemowe (reprezentujace maski procesorow jako maski bitowe typu unsigned long *) nie nakladaja ograniczen na rozmiar masek procesorow. Jednak typ danych cpu_set_t uzywany przez biblioteke glibc ma staly rozmiar 128 bajtow co oznacza, ze maksymalny numer procesora jaki moze odwzorowac to 1023. Jesli maska koligacji procesora jest wieksza niz 1024, wywolanie w postaci: sched_getaffinity(pid, sizeof(cpu_set_t), &mask); zawiedzie z bledem EINVAL, bledem z poziomu podleglego wywolania systemowego stosowanym w przypadku, gdy rozmiar mask podany w cpusetsize jest mniejszy od rozmiaru maski koligacji uzywanego przez jadro (w zaleznosci od systemowej topologii procesorow, maska koligacji jadra moze byc znacznie wieksza od liczby aktywnych procesorow w systemie). Przy pracy w systemach o duzych maskach koligacji procesora w jadrze, nalezy dynamicznie przydzielac argument mask (zob. CPU_ALLOC(3)). Obecnie, jedynym sposobem na to, jest sprawdzenie rozmiaru wymaganej maski za pomoca wywolan sched_getaffinity() o coraz wiekszych rozmiarach masek (do momentu zwrocenia przez wywolanie bledu EINVAL). Prosze zauwazyc, ze CPU_ALLOC(3) moze przydzielic nieco wiekszy zbior procesorow niz zazadano (poniewaz zbiory procesorow zaimplementowano jako maski bitowe, korzystajace z sizeof(long) jako jednostki). Zatem sched_getaffinity() moze ustawiac bity poza zazadanym rozmiarem alokacji, poniewaz jadro widzi kilka dodatkowych bitow. Wywolujacy powinien zatem iterowac bity w zwroconym zbiorze, liczac ktore z nich sa ustawione i zatrzymujac sie po osiagnieciu wartosci zwroconej przez CPU_COUNT(3) (zamiast iterowac po liczbie bitow, ktorych alokacji zazadano). PRZYKLADY Ponizszy program tworzy proces potomny. Procesy macierzysty i potomny nastepnie przydzielaja sie na okreslony procesor i wykonuja identyczne petle, ktore zabieraja jakis czas procesora. Przed zakonczeniem, rodzic czeka na ukonczenie procesu potomnego. Program przyjmuje trzy argumenty wiersza polecen: numer procesora dla rodzica, numer procesora dla potomka i liczbe iteracji petli, jakie maja wykonac oba procesy. Jak pokazuje nizej przykladowe wykonanie, ilosc czasu rzeczywistego i czasu procesora dzialajacego programu zalezy od buforowania na poziomie wewnatrz rdzenia i od tego, czy procesy uzywaja tego samego procesora. Najpierw korzystamy z lscpu(1) sprawdzajac, ze dany system (x86) ma dwa rdzenie, kazdy z dwoma procesorami: $ lscpu | egrep -i 'core.*:|socket'; Watkow na rdzen: 2 Rdzeni na gniazdo: 2 Gniazd: 1 Nastepnie mierzymy czas dzialania przykladowego programu dla trzech przypadkow: gdy oba procesy dzialaja na tym samym procesorze; gdy procesy dzialaja na roznych procesorach na tym samym rdzeniu; gdy procesy dzialaja na roznych procesorach na roznych rdzeniach. $ 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 Kod zrodlowy programu #define _GNU_SOURCE #include #include #include #include #include #include int main(int argc, char *argv[]) { int parentCPU, childCPU; cpu_set_t set; unsigned int nloops; if (argc != 4) { fprintf(stderr, "Uzycie: %s cpu-rodzica cpu-potomka l-petli\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: /* Blad */ err(EXIT_FAILURE, "fork"); case 0: /* Potomek */ CPU_SET(childCPU, &set); if (sched_setaffinity(0, sizeof(set), &set) == -1) err(EXIT_FAILURE, "sched_setaffinity"); for (unsigned int j = 0; j < nloops; j++) getppid(); exit(EXIT_SUCCESS); default: /* Rodzic */ CPU_SET(parentCPU, &set); if (sched_setaffinity(0, sizeof(set), &set) == -1) err(EXIT_FAILURE, "sched_setaffinity"); for (unsigned int j = 0; j < nloops; j++) getppid(); wait(NULL); /* Oczekiwanie na zakonczenie potomka */ exit(EXIT_SUCCESS); } } ZOBACZ TAKZE 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) TLUMACZENIE Tlumaczenie niniejszej strony podrecznika: Michal Kulach Niniejsze tlumaczenie jest wolna dokumentacja. Blizsze informacje o warunkach licencji mozna uzyskac zapoznajac sie z GNU General Public License w wersji 3 lub nowszej. Nie przyjmuje sie ZADNEJ ODPOWIEDZIALNOSCI. Bledy w tlumaczeniu strony podrecznika prosimy zglaszac na adres listy dyskusyjnej . Linux man-pages 6.18 8 lutego 2026 r. sched_setaffinity(2)