Provided by: manpages-fr-dev_4.19.0-7_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⟩.