Man page - sched_setaffinity(2)

Packages contains this manual

Available languages:

en fr ja ru

Manual

sched_setaffinity

NOM
BIBLIOTHÈQUE
SYNOPSIS
DESCRIPTION
VALEUR RENVOYÉE
ERREURS
STANDARDS
HISTORIQUE
NOTES
Différences entre bibliothÚque C et noyau
Gestion des systĂšmes ayant de grands masques d’affinitĂ© de processeur
EXEMPLES
Source du programme
VOIR AUSSI
TRADUCTION

NOM

sched_setaffinity, sched_getaffinity - DĂ©finir et rĂ©cupĂ©rer le masque d’affinitĂ© CPU d’un thread

BIBLIOTHÈQUE

BibliothĂšque C standard ( libc , -lc )

SYNOPSIS

#define _GNU_SOURCE /* Consultez 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 );

DESCRIPTION

Le masque d’affinitĂ© CPU d’un thread dĂ©termine l’ensemble des processeurs sur lesquels il est susceptible de s’exĂ©cuter. Sur un systĂšme multiprocesseur, dĂ©finir le masque d’affinitĂ© CPU permet d’obtenir une meilleure performance. Par exemple, en dĂ©diant un CPU Ă  un thread particulier (c’est-Ă -dire dĂ©finir le masque d’affinitĂ© de ce thread pour indiquer un seul CPU, et dĂ©finir le masque d’affinitĂ© de tous les autres threads pour exclure ce CPU), il est possible d’assurer une vitesse d’exĂ©cution maximale pour ce thread. Restreindre un processus pour qu’il ne s’exĂ©cute que sur un seul CPU rĂ©duit le coĂ»t liĂ© Ă  l’invalidation du cache qui se produit lorsqu’un thread cesse de s’exĂ©cuter sur un CPU puis est relancĂ© sur un autre CPU.

Un masque d’affinitĂ© CPU est reprĂ©sentĂ© par la structure cpu_set_t , un ensemble de CPU (« CPU set »), pointĂ© par mask . Des macros pour manipuler des ensembles de CPU sont dĂ©crites dans CPU_SET (3).

sched_setaffinity () dĂ©finit le masque d’affinitĂ© CPU du thread dont l’identifiant est pid Ă  la valeur donnĂ©e par mask . Si pid est 0, le thread appelant est utilisĂ©. L’argument cpusetsize est la taille (en octets) de la structure pointĂ©e par mask . Normalement, cet argument doit ĂȘtre spĂ©cifiĂ© comme sizeof(cpu_set_t) .

Si le thread indiquĂ© par pid n’est pas actuellement en cours d’exĂ©cution sur l’un des CPU spĂ©cifiĂ©s dans mask , alors ce thread est migrĂ© vers l’un des CPU spĂ©cifiĂ©s dans mask .

La fonction sched_getaffinity () Ă©crit dans la structure cpu_set_t pointĂ©e par mask le masque de prĂ©fĂ©rences du thread pid . L’argument cpusetsize indique la taille (en octets) de mask . Si pid vaut zĂ©ro, le masque du thread en cours est renvoyĂ©.

VALEUR RENVOYÉE

sched_setaffinity () et sched_getaffinity () renvoient 0 s’ils rĂ©ussissent (mais voir « DiffĂ©rences entre la bibliothĂšque C et le noyau » ci-dessous, qui explique que le sched_getaffinity () sous-jacent diffĂšre dans son code de retour). En cas d’échec, -1 est renvoyĂ© et errno est positionnĂ© pour indiquer l’erreur.

ERREURS

EFAULT

Une adresse mĂ©moire fournie n’est pas correcte.

EINVAL

Le masque de bits d’affinitĂ© mask ne contient pas de processeurs qui soient actuellement physiquement sur le systĂšme et autorisĂ©s pour le thread d’aprĂšs les restrictions qui peuvent ĂȘtre imposĂ©es par les cgroups cpuset ou le mĂ©canisme « cpuset » dĂ©crit dans cpuset (7).

EINVAL

( sched_getaffinity () et, avant Linux 2.6.9, sched_setaffinity ()) cpusetsize est plus petit que la taille du masque d’affinitĂ© utilisĂ© par le noyau.

EPERM

( sched_setaffinity ()) Le thread appelant n’a pas les privilĂšges appropriĂ©s. L’appelant doit avoir un UID effectif Ă©gal Ă  l’UID effectif ou rĂ©el du thread identifiĂ© par pid , ou avoir la capacitĂ© CAP_SYS_NICE dans l’espace de noms de l’utilisateur du thread dĂ©signĂ© par pid .

ESRCH

Le thread numĂ©ro pid n’existe pas.

STANDARDS

Linux.

HISTORIQUE

Linux 2.5.8, glibc 2.3.

Au départ, les interfaces de la glibc avaient un paramÚtre cpusetsize de type unsigned int . Dans glibc 2.3.3, ce paramÚtre a été supprimé, mais il a été réintroduit dans glibc 2.3.4, avec pour type size_t .

NOTES

AprĂšs un appel Ă  sched_setaffinity (), l’ensemble des CPU sur lesquels le thread s’exĂ©cutera est l’intersection de l’ensemble spĂ©cifiĂ© dans le paramĂštre mask et l’ensemble des CPU actuellement prĂ©sents sur le systĂšme. Le systĂšme peut restreindre encore plus l’ensemble des CPU sur lesquels le thread peut tourner si le mĂ©canisme « cpuset », dĂ©crit dans cpuset (7), est utilisĂ©. Ces restrictions sur le vĂ©ritable ensemble de CPU sur lesquels le thread peut tourner sont imposĂ©es sans avertissement par le noyau.

Il existe plusieurs maniĂšres de dĂ©terminer le nombre de processeurs disponibles sur le systĂšme, notamment l’inspection du contenu de /proc/cpuinfo , l’utilisation de sysconf (3) pour avoir les valeurs des paramĂštres _SC_NPROCESSORS_CONF et _SC_NPROCESSORS_ONLN , et l’inspection de la liste des rĂ©pertoires de processeur dans /sys/devices/system/cpu/ .

sched (7) dĂ©crit les politiques d’ordonnancement sous Linux.

Le masque d’affinitĂ© est un attribut de thread, qui peut ĂȘtre modifiĂ© indĂ©pendamment pour chacun des threads d’un groupe de threads. La valeur renvoyĂ©e par gettid (2) peut ĂȘtre passĂ©e dans l’argument pid . SpĂ©cifier un pid de 0 dĂ©finira l’attribut pour le thread appelant, et une valeur Ă©gale Ă  celle renvoyĂ©e par getpid (2) dĂ©finira l’attribut pour le thread principal du groupe de threads. (Si vous utilisez l’API POSIX des threads, alors utilisez pthread_setaffinity_np (3) au lieu de sched_setaffinity ().)

L’option d’amorçage isolcpus peut ĂȘtre utilisĂ©e pour isoler un ou plusieurs processeurs au moment du dĂ©marrage, afin qu’aucun processus n’utilise ces processeurs. Suite Ă  l’utilisation de cette option, la seule maniĂšre d’affecter des processus Ă  un processeur isolĂ© est d’utiliser sched_setaffinity () ou le mĂ©canisme cpuset (7). Pour plus d’informations, voir le fichier Documentation/admin-guide/kernel-parameters.txt des sources du noyau. Comme indiquĂ© dans ce fichier, isolcpus est le mĂ©canisme privilĂ©giĂ© d’isolation des processeurs (plutĂŽt que de dĂ©finir Ă  la main l’affinitĂ© processeur de tous les processus du systĂšme).

Un processus enfant créé par fork (2) hĂ©rite du masque d’affinitĂ© CPU de son parent. Le masque d’affinitĂ© est conservĂ© au travers d’un execve (2).

Différences entre bibliothÚque C et noyau

Cette page de manuel dĂ©crit l’interface de la glibc pour les appels liĂ©s Ă  l’affinitĂ© CPU. L’interface des appels systĂšme est lĂ©gĂšrement diffĂ©rente, mask ayant le type unsigned long * , montrant le fait que l’implĂ©mentation des ensembles de CPU est en rĂ©alitĂ© un simple masque de bits.

En cas de succĂšs, l’appel systĂšme sched_getaffinity () brut renvoie le nombre d’octets copiĂ©s dans le tampon mask ; il s’agira de la taille minimale de cpusetsize et de la taille (en octets) du type de donnĂ©es cpumask_t utilisĂ©e en interne par le noyau pour reprĂ©senter le masque de bits du jeu de processeurs.

Gestion des systĂšmes ayant de grands masques d’affinitĂ© de processeur

Les appels systĂšme sous-jacents (qui reprĂ©sentent les masques de processeur par des masques de bits de type unsigned long * ) n’imposent aucune restriction quant Ă  la taille du masque de processeur. Toutefois, le type de donnĂ©es cpu_set_t utilisĂ© par la glibc a une taille fixe de 128 octets, si bien que le nombre maximal de processeurs qui peuvent ĂȘtre reprĂ©sentĂ©s est de 1023. Si le masque d’affinitĂ© de processeur du noyau est plus grand que 1024, les appels sous la forme :

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

Ă©chouent avec l’erreur EINVAL , celle produite par l’appel systĂšme sous-jacent si la taille mask indiquĂ©e dans cpusetsize est infĂ©rieure Ă  celle du masque d’affinitĂ© utilisĂ©e par le noyau (selon la topologie des processeurs du systĂšme, le masque d’affinitĂ© du noyau peut ĂȘtre beaucoup plus grand que le nombre de processeurs actifs sur le systĂšme).

Si vous travaillez sur des systĂšmes ayant de grands masques d’affinitĂ© de processeur, vous pouvez allouer de maniĂšre dynamique l’argument mask (voir CPU_ALLOC (3)). Actuellement, la seule maniĂšre de faire cela est de sonder la taille de masque nĂ©cessaire en utilisant les appels sched_getaffinity () avec des tailles de masque croissantes (jusqu’à ce que l’appel n’échoue pas avec l’erreur EINVAL ).

Gardez en tĂȘte qu’il se peut que CPU_ALLOC (3) alloue un peu plus de processeurs que vous ne l’avez demandĂ© (car les ensembles de processeurs sont implĂ©mentĂ©s sous forme de masques de bits allouĂ©s par unitĂ©s de sizeof(long) ). Par consĂ©quent, sched_getaffinity () peut positionner des bits au-delĂ  de la taille d’allocation demandĂ©e car le noyau voit quelques bits supplĂ©mentaires. Donc, l’appelant doit revenir sur les bits de l’ensemble renvoyĂ© en comptant ceux qui sont positionnĂ©s et s’arrĂȘter lorsqu’il atteint la valeur renvoyĂ©e par CPU_COUNT (3) (et non pas revenir sur les bits de l’ensemble dont une allocation a Ă©tĂ© demandĂ©e).

EXEMPLES

Le programme ci-dessous crĂ©e un processus enfant. Puis le parent et l’enfant s’affectent mutuellement un processeur indiquĂ© et exĂ©cutent des boucles identiques qui consomment du temps de processeur. Avant de se terminer, le parent attend que l’enfant s’achĂšve. Le programme prend trois paramĂštres en ligne de commande : le numĂ©ro de processeur du parent, celui de l’enfant et le nombre de boucles que doivent effectuer les deux processus.

Comme le montre le modĂšle ci-dessous, la quantitĂ© de temps processeur et de temps rĂ©el consommĂ© lors de l’exĂ©cution d’un programme dĂ©pendra des effets de mise en cache Ă  l’intĂ©rieur du processeur et de l’utilisation ou non du mĂȘme processeur par les processus.

On utilise d’abord lscpu (1) pour dĂ©terminer que ce systĂšme (x86) comporte deux cƓurs, chacun ayant deux processeurs :

$ lscpu | egrep -i 'core.*:|socket'
Thread(s) par cƓur : 2
CƓur(s) par socket : 2
Socket(s) : 1

On chronomĂštre alors l’opĂ©ration du programme exemple dans trois cas : les deux processus en fonction sur le mĂȘme processeur, sur des processeurs diffĂ©rents du mĂȘme cƓur et sur des processeurs diffĂ©rents sur des cƓurs diffĂ©rents.

$ time -p ./a.out 0 0 100000000
réel 14.75
utilisateur 3.02
sys 11.73
$ time -p ./a.out 0 1 100000000
réel 11.52
utilisateur 3.98
sys 19.06
$ time -p ./a.out 0 3 100000000
réel 7.89
utilisateur 3.29
sys 12.07

Source du programme

#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, "Utillisation : %s CPU_parent CPU_enfant nb_boucles\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: /* Erreur */
err(EXIT_FAILURE, "fork");
case 0: /* Enfant */
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); /* Attendre que l’enfant se termine */
exit(EXIT_SUCCESS);
}
}

VOIR AUSSI

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)

TRADUCTION

La traduction française de cette page de manuel a été créée par Christophe Blaess <https://www.blaess.fr/christophe/>, Stéphan Rafin <stephan.rafin@laposte.net>, Thierry Vignaud <tvignaud@mandriva.com>, François Micaux, Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe Guérard <fevrier@tigreraye.org>, Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>, Julien Cristau <jcristau@debian.org>, Thomas Huriaux <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin Duneau <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>, Denis Barbier <barbier@debian.org>, David Prévot <david@tilapin.org>, Cédric Boutillier <cedric.boutillier@gmail.com>, Frédéric Hantrais <fhantrais@gmail.com> et Jean-Philippe MENGUAL <jpmengual@debian.org>

Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n’y a aucune RESPONSABILITÉ LÉGALE.

Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à debian-l10n-french@lists.debian.org .