Provided by: manpages-fr-dev_4.21.0-2_all bug

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.

VERSIONS

       Les appels système d'affinité ont été introduits dans Linux 2.5.8.  Les  fonctions  enveloppes  pour  ces
       appels  système  ont  été introduites dans la 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.

STANDARDS

       Ces appels système sont spécifiques à Linux.

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, "Usage : %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 ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩ 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⟩.