Provided by: manpages-fr_4.13-4_all 

NOM
cpuset - Confiner des processus à des sous-ensembles de processeurs et de nœuds mémoire
DESCRIPTION
Le système de fichiers cpuset (N.d.T. : « cpuset » signifie mot à mot « ensemble de CPU », mais comme il
ne s'agit pas uniquement d'ensembles de CPU, le terme cpuset sera utilisé par la suite) est une interface
sous forme d'un pseudosystème de fichiers pour le mécanisme « cpuset » du noyau, qui permet de contrôler
le placement de processus sur des processeurs ou en mémoire. Il est habituellement monté dans
/dev/cpuset.
On systems with kernels compiled with built in support for cpusets, all processes are attached to a
cpuset, and cpusets are always present. If a system supports cpusets, then it will have the entry nodev
cpuset in the file /proc/filesystems. By mounting the cpuset filesystem (see the EXAMPLES section below),
the administrator can configure the cpusets on a system to control the processor and memory placement of
processes on that system. By default, if the cpuset configuration on a system is not modified or if the
cpuset filesystem is not even mounted, then the cpuset mechanism, though present, has no effect on the
system's behavior.
Un cpuset définit une liste de CPU et de nœuds mémoire.
Les CPU d'un système comprennent toutes les unités de traitement logiques sur lesquelles peuvent
s'exécuter des processus, comprenant, s'il y en a, les différents cœurs d'un processeur et les
Hyper-Threads d'un cœur de processeur. Les nœuds mémoire comprennent tous les bancs distinct de mémoire ;
les petits systèmes et les systèmes SMP ont typiquement un seul nœud mémoire qui contient toute la
mémoire du système, alors que les systèmes NUMA (« non-uniform memory access » : accès non uniforme à la
mémoire) ont plusieurs nœuds mémoire.
Les cpusets sont représentés par des répertoires dans un pseudosystème de fichiers hiérarchique dont le
répertoire de plus haut niveau (/dev/cpuset) représente le système complet (tous les CPU et nœuds mémoire
en ligne). Tout cpuset fils (le descendant) d'un autre cpuset père contient un sous-ensemble des CPU et
des nœuds mémoire du père. Les répertoires et les fichiers qui représentent les cpusets ont les
permissions habituelles des systèmes de fichiers.
Chaque processus du système appartient à un unique cpuset. Un processus est obligé de s'exécuter sur les
CPU du cpuset auquel il appartient et est obligé d'allouer de la mémoire uniquement sur les nœuds mémoire
de ce cpuset. Quand un processus crée un fils avec fork(2), le processus fils est placé dans le même
cpuset que le processus père. S'il a les privilèges suffisants, le processus fils peut se déplacer d'un
cpuset à un autre et les CPU ou nœuds mémoire d'un cpuset existant peuvent être changés.
Au début du démarrage du système, un seul cpuset est défini qui comprend tous les CPU et tous les nœuds
mémoire du système et tous les processus se trouvent dans ce cpuset. Pendant le démarrage ou par la suite
lors de l'exécution normale du système, d'autres cpusets peuvent être créés, en tant que sous-répertoire
de ce cpuset de plus haut niveau, sous le contrôle de l'administrateur système. Des processus peuvent
être placés dans ces autres cpusets.
Les cpusets sont intégrés dans le noyau avec le mécanisme d'affinité d'ordonnancement de
sched_setaffinity(2) et les mécanismes de placement en mémoire de mbind(2) et set_mempolicy(2). Aucun de
ces mécanismes ne permettent à un processus d'utiliser un CPU ou un nœud mémoire qui n'est pas autorisé
par le cpuset du processus. Si une modification du cpuset entre en conflit avec ces autres mécanismes, le
placement dans le cpuset est forcé, même si cela signifie qu'il faut outrepasser ces autres mécanismes.
Ceci est fait silencieusement par le noyau en restreignant les CPU et nœuds mémoire demandés par ces
autres mécanismes à ceux qui sont autorisés par le cpuset du processus appelant. Ces autres appels
peuvent alors renvoyer une erreur si, par exemple, ils sont amenés à demander un ensemble vide de CPU ou
de nœuds mémoire après que la demande est restreinte au cpuset du processus appelant.
Typiquement, un cpuset est utilisé pour gérer le confinement dans des CPU ou des nœuds mémoire pour un
ensemble de processus qui coopèrent entre eux, comme un ordonnanceur de tâches, et ces autres mécanismes
permettent de gérer le placement de chacun des processus ou des régions mémoire pour chacune de ces
tâches.
FICHIERS
Chaque répertoire de /dev/cpuset représente un cpuset et contient un ensemble définit de pseudofichiers
qui décrivent l'état de ce cpuset.
Les nouveaux cpusets sont créés avec l'appel système mkdir(2) ou la commande mkdir(1). Les propriétés
d'un cpuset, comme ses drapeaux, les CPU et nœuds mémoire autorisés et les processus attachés sont
récupérés ou modifiés en lisant ou écrivant dans le fichier approprié du répertoire du cpuset. Ces
fichiers sont décrits ci-dessous.
Les pseudofichiers dans chaque répertoire d'un cpuset sont créés automatiquement quand le cpuset est
créé, suite à l'appel à mkdir(2). Il n'est pas possible d'ajouter ou de supprimer directement ces
pseudofichiers.
Le répertoire d'un cpuset qui ne contient pas de répertoire pour un cpuset fils et n'a pas de processus
lui étant attaché peut être supprimé à l'aide de rmdir(2) ou rmdir(1). Il n'est pas nécessaire, ou
possible, de supprimer les pseudofichiers du répertoire avant de le supprimer.
Les pseudofichiers des répertoires d'un cpuset sont de petits fichiers textes qui peuvent être lus ou
écrits en utilisant les outils traditionnels comme cat(1) et echo(1) ou depuis un programme en utilisant
des fonctions d'une bibliothèque d'entrées sorties ou des appels système, comme open(2), read(2),
write(2) et close(2).
Les pseudofichiers dans un répertoire d'un cpuset représentent l'état interne du noyau et n'ont pas de
représentation persistante sur le disque. Les fichiers d'un cpuset sont listés et décrits ci-dessous.
tasks Liste des identifiants de processus (PID) des processus dans ce cpuset. La liste contient une
série de nombres décimaux au format ASCII, chacun suivit d'une nouvelle ligne. Un processus peut
être ajouté à un cpuset (ce qui le supprime automatiquement du cpuset qui le contenait auparavant)
en écrivant son PID dans le fichier tasks du cpuset (avec ou sans nouvelle ligne à la fin).
Attention : un seul PID peut être écrit à la fois dans le fichier tasks. Si une chaîne est écrite
et qu'elle contient plus d'un PID, seul le premier sera utilisé.
notify_on_release
Drapeau (0 ou 1). Lorsqu'il est activé (1), ce cpuset sera géré de façon particulière une fois
qu'il sera libéré, c'est-à-dire après que tous les processus cessent de l'utiliser (c'est-à-dire
se terminent ou ont été déplacés dans un autre ensemble de CPU) et que tous les répertoires des
cpusets fils ont été supprimés. Consultez la section Notification à la libération ci-dessous.
cpuset.cpus
Liste des numéros physiques des CPU sur lesquels les processus de ce cpuset ont le droit de
s'exécuter. Consultez la section Format des listes ci-dessous pour une description du format de
cpus.
Les CPU autorisés pour un cpuset peuvent être changés en écrivant une nouvelle liste dans la
fichier cpus.
cpuset.cpu_exclusive
Flag (0 or 1). If set (1), the cpuset has exclusive use of its CPUs (no sibling or cousin cpuset
may overlap CPUs). By default, this is off (0). Newly created cpusets also initially default this
to off (0).
Deux cpusets sont frères s'ils ont le même cpuset père dans la hiérarchie /dev/cpuset. Deux
cpusets sont cousins si aucun n'est l'ancêtre de l'autre. Indépendamment du paramètre
cpu_exclusive, si un cpuset est l'ancêtre d'un autre et si ces deux cpusets ont des listes de CPU
(cpus) non vides, alors leurs listes de CPU doivent se chevaucher parce que la liste cpus d'un
cpuset est toujours un sous ensemble de la liste cpus de son cpuset père.
cpuset.mems
Liste des nœuds mémoire sur lesquels les processus de ce cpuset ont le droit d'allouer de la
mémoire. Consultez la section Format des listes ci-dessous pour une description du format de mems.
cpuset.mem_exclusive
Flag (0 or 1). If set (1), the cpuset has exclusive use of its memory nodes (no sibling or cousin
may overlap). Also if set (1), the cpuset is a Hardwall cpuset (see below). By default, this is
off (0). Newly created cpusets also initially default this to off (0).
Indépendamment du paramètre mem_exclusive, si un cpuset est l'ancêtre d'un autre, alors leurs
nœuds mémoires doivent se chevaucher parce que l'ensemble des nœuds mémoire d'un cpuset est
toujours un sous ensemble des nœuds mémoire du cpuset père.
cpuset.mem_hardwall (depuis Linux 2.6.26)
Flag (0 or 1). If set (1), the cpuset is a Hardwall cpuset (see below). Unlike mem_exclusive,
there is no constraint on whether cpusets marked mem_hardwall may have overlapping memory nodes
with sibling or cousin cpusets. By default, this is off (0). Newly created cpusets also initially
default this to off (0).
cpuset.memory_migrate (depuis Linux 2.6.16)
Flag (0 or 1). If set (1), then memory migration is enabled. By default, this is off (0). See the
Memory Migration section, below.
cpuset.memory_pressure (depuis Linux 2.6.16)
Une mesure de la pression mémoire causée par les processus d'un cpuset. Consultez la section
Pression mémoire ci-dessous. À moins que memory_pressure_enabled soit activé, il vaut toujours
zéro. Ce fichier est en lecture seule. Consultez la section AVERTISSEMENTS ci-dessous.
cpuset.memory_pressure_enabled (depuis Linux 2.6.16)
Flag (0 or 1). This file is present only in the root cpuset, normally /dev/cpuset. If set (1), the
memory_pressure calculations are enabled for all cpusets in the system. By default, this is off
(0). See the Memory Pressure section, below.
cpuset.memory_spread_page (depuis Linux 2.6.17)
Flag (0 or 1). If set (1), pages in the kernel page cache (filesystem buffers) are uniformly
spread across the cpuset. By default, this is off (0) in the top cpuset, and inherited from the
parent cpuset in newly created cpusets. See the Memory Spread section, below.
cpuset.memory_spread_slab (depuis Linux 2.6.17)
Flag (0 or 1). If set (1), the kernel slab caches for file I/O (directory and inode structures)
are uniformly spread across the cpuset. By default, is off (0) in the top cpuset, and inherited
from the parent cpuset in newly created cpusets. See the Memory Spread section, below.
cpuset.sched_load_balance (depuis Linux 2.6.24)
Drapeau (0 ou 1). S'il est activé (1, la valeur par défaut), le noyau répartira automatiquement la
charge des processus du cpuset au travers les CPU autorisés pour le cpuset. S'il est désactivé
(0), le noyau ne répartira pas la charge des processus du cpuset, à moins qu'un autre cpuset qui
partage des CPU avec lui n'ait son drapeau sched_load_balance activé. Consultez la section
Répartition de la charge par l'ordonnanceur ci-dessous pour plus de détails.
cpuset.sched_relax_domain_level (depuis Linux 2.6.26)
Entier, compris entre -1 et une petite valeur positive. sched_relax_domain_level contrôle la
largeur de l'intervalle des CPU pour lesquels le noyau effectue une répartition immédiate des
tâches exécutables. Si sched_load_balance est désactivé, alors sched_relax_domain_level ne compte
pas, puisqu'il n'y a pas de répartition de la charge. Si sched_load_balance est activé, alors plus
sched_relax_domain_level est important, plus l'intervalle des CPU sur lesquels le noyau essaie de
répartir la charge est important. Consultez la section Niveau du domaine de détente de
l'ordonnanceur ci-dessous pour plus de détails.
En plus des pseudofichiers décrits ci-dessus, dans chaque répertoire de /dev/cpuset, chaque processus a
un pseudofichier, /proc/<pid>/cpuset, qui indique le chemin vers le répertoire du cpuset du processus,
relativement à la racine du système de fichiers cpuset.
Quatre lignes sont également ajoutées dans le fichier /proc/<pid>/status, fournissant pour chaque
processus les champs : Cpus_allowed (sur quels CPU il peut être ordonnancé) et Mems_allowed (sur quels
nœuds mémoire de la mémoire peut être allouée), avec l'Affichage sous forme de masque et l'Affichage sous
forme de liste (voir ci-dessous). Voici un exemple :
Cpus_allowed: ffffffff,ffffffff,ffffffff,ffffffff
Cpus_allowed_list: 0-127
Mems_allowed: ffffffff,ffffffff
Mems_allowed_list: 0-63
Les champs « allowed » ont été ajoutés dans Linux 2.6.24 ; les champs « allowed_list » ont été ajoutés
dans Linux 2.6.26.
CAPACITÉS ÉTENDUES
En plus de contrôler quels CPU (cpus) et nœuds mémoire (mems) un processus à le droit d'utiliser, les
cpusets fournissent les fonctionnalités étendues suivantes.
Ensembles de CPU exclusifs
Si un cpuset est marqué avec cpu_exclusive ou mem_exclusive, aucun autre cpuset, autre que des ancêtres
ou descendants directs, peuvent partager des CPU ou des nœuds mémoire avec ce cpuset.
Un cpuset dont mem_exclusive est activé restreint les allocations du noyau pour les pages des tampons de
cache et autres données internes du noyau communément partagées par le noyau au travers différents
utilisateurs. Tous les cpusets, que mem_exclusive soit activé ou non, restreignent l'allocation de
mémoire depuis l'espace utilisateur. Ceci permet de configurer un système de telle sorte que différentes
tâches puissent partager des données du noyau, tout en isolant toutes les allocations en mode utilisateur
des tâches dans leur propre cpuset. Pour ceci, il faut créer un gros cpuset, avec mem_exclusive activé,
pour contenir toutes les tâches, et créer des cpuset fils sans mem_exclusive pour chacune des tâches.
Seule une petite partie de la mémoire du noyau, comme les requêtes des gestionnaires d'interruptions, est
autorisée à être placée sur des nœuds mémoire en dehors d'un cpuset, même si mem_exclusive est activé.
Hardwall
Un cpuset pour lequel mem_exclusive ou mem_hardwall est activé est un cpuset hardwall. Un cpuset hardwall
restreint les allocations mémoire du noyau pour les pages, tampons et toutes autre données partagés
fréquemment par le noyau au travers différents utilisateurs. Tous les cpusets, hardwall ou non,
restreignent les allocations mémoire pour l'espace utilisateur.
Ceci permet de configurer un système de telle sorte que différentes tâches indépendantes puissent
partager des données du noyau, comme des pages des systèmes de fichiers, tout en isolant les allocations
de l'espace utilisateur de chaque tâche dans leur cpuset. Pour ceci, il faut créer un gros cpuset
hardwall qui contiendra toutes les tâches et créer des cpusets fils (non hardwall) pour chacune des
tâches.
Seule une petite quantité de mémoire noyau, comme les demandes des gestionnaires d'interruption, peut
être utilisée à l'extérieur d'un cpuset hardwall.
Notification à la libération
Si le drapeau notify_on_release d'un cpuset est activé (1), alors quand le dernier processus quitte le
cpuset (il se termine ou s'attache à un autre cpuset) et que le dernier cpuset fils de ce cpuset a été
supprimé, le noyau exécutera la commande /sbin/cpuset_release_agent en lui fournissant le chemin (relatif
au point de montage du système de fichiers cpuset) du cpuset abandonné. Ceci permet de supprimer
automatiquement les cpusets abandonnés.
Le drapeau notify_on_release du cpuset racine est désactivé (0) par défaut au moment du démarrage. La
valeur par défaut pour les autres cpusets lors de leur création est égale à la valeur de
notify_on_release de leur cpuset parent.
La commande /sbin/cpuset_release_agent est appelée, avec dans argv[1] le nom (un chemin relatif à
/dev/cpuset) du cpuset à supprimer.
Le contenu habituel de la commande /sbin/cpuset_release_agent est simplement le script shell suivant :
#!/bin/sh
rmdir /dev/cpuset/$1
Comme pour les autres drapeaux ci-dessous, ce drapeau peut être modifié en écrivant un 0 ou un 1 ASCII
(avec ou sans fin de ligne) dans le fichier pour respectivement désactiver ou activer le drapeau.
Pression mémoire
Le fichier memory_pressure d'un cpuset indique la moyenne instantanée du taux auquel les processus du
cpuset tentent de libérer de la mémoire utilisée sur les nœuds du cpuset pour satisfaire les nouvelles
demandes de mémoire.
Ceci permet à un gestionnaire de tâches de superviser les tâches qui s'exécutent dans des cpuset dédiés
et détecter efficacement la pression mémoire qu'une tâche produit.
Ceci est utile à la fois pour les systèmes très surveillés qui exécutent diverses tâches qui leurs sont
fournies et peuvent choisir de terminer ou de changer la priorité des tâches qui essaient d'utiliser plus
de mémoire que les nœuds mémoire qui leurs ont été assignés leurs permettent, et les systèmes pour du
calcul scientifique avec des tâches parallèles, fortement couplées, au temps d'exécution important, qui
ne pourraient plus fournir les performances demandées si elles se mettaient à utiliser plus de mémoire
qu'elles n'en ont droit.
Ce mécanisme fourni un moyen très économique pour détecter des signes de pression mémoire sur un cpuset.
L'action à effectuer lorsqu'un signe de pression mémoire est détecté est laissé au libre arbitre du
gestionnaire des tâches ou autre code utilisateur.
À moins que le calcul de la pression mémoire soit activé par le pseudofichier
/dev/cpuset/cpuset.memory_pressure_enabled, cette pression mémoire n'est calculée pour aucun cpuset et
les lectures dans les fichiers memory_pressure renvoient toujours zéro, c'est-à-dire la chaîne ASCII
« 0\n ». Consultez la section AVERTISSEMENTS ci-dessous.
Une moyenne instantanée par cpuset est utilisée pour les raisons suivantes :
– Comme cette métrique est par cpuset plutôt que par processus ou par région mémoire virtuelle, la
charge du système due à la supervision de cette métrique par un gestionnaire de tâches est fortement
réduite sur les gros systèmes, étant donné qu'il n'est pas nécessaire de parcourir la liste des tâches
à chaque fois.
– Comme cette métrique est une moyenne instantanée plutôt qu'un compteur, un gestionnaire de tâches
obtient la pression mémoire en une seule lecture sans avoir à lire et se souvenir des résultats
pendant un certain temps.
– Comme cette métrique est par cpuset plutôt que par processus, le gestionnaire de tâches peut obtenir
l'information importante, la pression mémoire dans un cpuset, en une seule lecture sans nécessiter
d'obtenir et de se souvenir des résultats pour tous les processus d'un cpuset (la liste des processus
peut changer dynamiquement).
La pression mémoire d'un cpuset est calculée en utilisant un simple filtre digital par cpuset dans le
noyau. Pour chaque cpuset, ce filtre suit le taux auquel les processus attachés à ce cpuset demandent au
noyau de réutiliser de la mémoire.
Ces demandes de réutilisation de mémoire se produisent quand un processus doit satisfaire une demande de
page mémoire en trouvant d'abord une page à réutiliser, du fait de l'absence de page disponible déjà
prête. Les pages sales des systèmes de fichiers sont réutilisées en les écrivant d'abord sur le disque.
Les tampons des systèmes de fichiers qui n'ont pas été modifiés sont réutilisés tout simplement en les
abandonnant, mais si cette page est nécessaire de nouveau, il faudra la relire sur le disque.
Le fichier cpuset.memory_pressure fournit un nombre entier qui représente le taux des demandes récentes
(la demi-vie est de 10 secondes) de réutilisation de mémoire par les processus du cpuset, l'unité étant
le nombre de demandes par seconde fois 1000.
Répartition mémoire
Il y a deux fichiers, par cpuset, pour des drapeaux booléens qui contrôlent où le noyau alloue les pages
pour les tampons des systèmes de fichiers et les structures de données liées internes au noyau. Ces
fichiers sont cpuset.memory_spread_page et cpuset.memory_spread_slab.
Si le drapeau booléen cpuset.memory_spread_page est activé, alors le noyau répartit les tampons des
systèmes de fichiers (les caches des pages) équitablement sur tous les nœuds autorisés pour le processus
qui demande la page, au lieu de placer ces pages de préférence sur le nœud sur lequel s'exécute le
processus.
Si le drapeau booléen cpuset.memory_spread_slab d'un cpuset est activé, alors le noyau répartira
uniformément les caches slab liés aux systèmes de fichiers, comme ceux pour des entrées d'inœuds ou de
répertoires, sur tous les nœuds autorisés pour le processus qui demande de la mémoire, plutôt que de
préférer mettre ces pages sur le nœud sur lequel s'exécute le processus.
La configuration de ces drapeaux n'affecte pas les pages du segment de données (consultez brk(2)) ou du
segment de la pile d'un processus.
Par défaut, les deux types de répartition de la mémoire sont désactivés et le noyau préfère allouer la
mémoire sur le nœud local où s'exécute le processus. Si ce nœud n'est pas autorisé par la politique NUMA
du processus ou par la configuration des cpusets ou s'il n'y a plus suffisamment de pages mémoire
disponibles sur ce nœud, alors le noyau recherche le nœud le plus proche étant autorisé et ayant
suffisamment de pages disponibles.
Quand un nouveau cpuset est créé, il hérite de la configuration de répartition mémoire de son père.
Activer la répartition mémoire a pour effet d'ignorer la politique mémoire NUMA du processus pour les
allocations de pages ou de caches slab, qui sont alors éparpillées. Cependant, les changements dus à la
répartition mémoire demandée par un cpuset ne sont pas visibles pour les appels système mbind(2) ou
set_mempolicy(2). Ces deux appels système liés à la politique mémoire NUMA semblent se comporter comme si
aucune répartition mémoire n'était demandée par un cpuset, même si c'est le cas. Si la répartition
mémoire est par la suite désactivée pour les cpuset, la dernière politique mémoire NUMA définie par ces
appels est automatiquement appliquée de nouveau.
Both cpuset.memory_spread_page and cpuset.memory_spread_slab are Boolean flag files. By default, they
contain "0", meaning that the feature is off for that cpuset. If a "1" is written to that file, that
turns the named feature on.
La répartition mémoire d'un cpuset se comporte de façon similaire à ce qui est connu (dans d'autres
contextes) comme le placement mémoire à tour de rôle (« round-robin ») ou entrelacé (« interleave »).
La configuration d'une stratégie de répartition mémoire pour un cpuset peut améliorer significativement
les performances pour les tâches qui :
a) nécessitent de placer les données locales des threads dans des nœuds mémoire proches des CPU qui
exécutent les threads qui accèdent le plus fréquemment à ces données ; mais aussi
b) nécessitent d'accéder à de gros ensembles de données de systèmes de fichiers qui doivent être répartis
sur différents nœuds du cpuset de la tâche du fait de leurs tailles.
Sans cette politique, la répartition des allocations mémoire sur les nœuds du cpuset de la tâche peut ne
pas être équitable, particulièrement pour les tâches qui n'auraient qu'un thread chargé de
l'initialisation ou de la lecture des données d'entrée.
Migration mémoire
Normalement, avec la configuration de cpuset.memory_migrate par défaut (désactivé), une fois qu'une page
est allouée (une page physique de la mémoire lui est donnée), cette page reste sur le nœud où elle a été
allouée, tant qu'elle reste allouée, même si la politique de placement mémoire du cpuset (mems) change
par la suite.
Quand la migration mémoire est activée pour un cpuset, si la configuration de mems est modifiée alors
toute page mémoire utilisée par un processus du cpuset qui se trouverait sur un nœud mémoire qui n'est
plus autorisé sera déplacée sur un nœud mémoire qui est autorisé.
De plus, si un processus est déplacé dans un cpuset dont le drapeau memory_migrate est activé, toutes les
pages mémoire qu'il utilise et qui se trouvent sur des nœuds mémoire qui étaient autorisés dans son
cpuset précédant mais ne le sont plus dans le nouveau cpuset seront déplacées sur un nœud mémoire
autorisé pour le nouveau cpuset.
L'emplacement relatif d'un page déplacée d'un cpuset est préservé si possible lors de ces opérations de
déplacement. Par exemple, si la page se trouvait sur le deuxième nœud valable du précédent cpuset, alors
la page sera placée sur le deuxième nœud valable du nouveau cpuset, si c'est possible.
Répartition de la charge par l'ordonnanceur
L'ordonnanceur du noyau répartit automatiquement la charge des processus. Si un CPU est sous-utilisé, le
noyau recherchera des processus sur d'autres CPU plus chargés et déplacera ces processus sur le CPU
sous-utilisé à condition que les mécanismes comme les cpuset et sched_setaffinity(2) le permettent.
Le coût de l'algorithme de répartition de la charge et son impact sur les structures de données partagées
du noyau, comme la liste des processus, augmente plus que linéairement avec le nombre de CPU qui
interviennent pour la répartition de la charge. Par exemple le coût pour la répartition de la charge dans
un grand ensemble de CPU sera supérieur à celui pour la répartition de la charge dans deux ensembles
ayant moitié moins de CPU. (La relation entre le nombre de CPU intervenant dans la répartition de la
charge et le coût de cette répartition de charge dépend de l'implémentation de l'ordonnanceur de
processus du noyau, qui change dans le temps quand de meilleurs algorithmes d'ordonnancement sont
implémentés)
Le drapeau sched_load_balance d'un cpuset permet de supprimer cette répartition automatique de la charge
dans les cas où elle n'est pas nécessaire et que sa suppression améliorerait les performances.
Par défaut, la répartition de la charge se fait sur tous les CPU, à l'exception de ceux marqués comme
étant isolés en utilisant au moment du démarrage le paramètre du noyau « isolcpus= ». (Consultez la
section Niveau du domaine de détente de l'ordonnanceur ci-dessous pour changer le comportement par
défaut)
Cette répartition de la charge par défaut n'est pas bien adaptée aux situations suivantes :
– Sur les gros systèmes, la répartition de la charge sur beaucoup de CPU est très coûteuse. Si le
système est géré avec des cpusets pour placer les tâches indépendantes sur différents ensembles de
CPU, une répartition de la charge complète n'est pas nécessaire.
– Les systèmes avec une prise en charge temps-réel sur certains CPU doivent minimiser la surcharge du
système sur ces CPU et donc éviter la répartition de la charge des processus si elle n'est pas
nécessaire.
Quand le drapeau sched_load_balance d'un cpuset est activé (ce qui est le cas par défaut), une
répartition de la charge sur tous les CPU autorisés par le cpuset est demandé, à condition que le
processus puisse être déplacé d'un CPU du cpuset à un autre CPU (c'est-à-dire qu'il n'ait pas été attaché
à des CPU avec, par exemple, sched_setaffinity(2)).
Quand le drapeau sched_load_balance d'un cpuset est désactivé, alors l'ordonnanceur évitera de déplacer
des processus pour répartir la charge des CPU du cpuset, sauf si un autre cpuset partage le même CPU et a
son drapeau sched_load_balance activé.
Ainsi, par exemple, si le cpuset racine a son drapeau sched_load_balance activé, alors l'ordonnanceur
répartira la charge sur tous les CPU et la configuration du drapeau sched_load_balance des autres cpusets
n'a pas d'effet, puisqu'une répartition complète de la charge est déjà demandée.
Dans les deux situations ci-dessus, le drapeau sched_load_balance devrait donc être désactivé sur le
cpuset racine et seuls les cpusets fils plus petits devraient l'activer.
Lorsque vous faites ceci, vous ne devez généralement pas laisser un processus non attaché à un CPU dans
le cpuset racine qui pourrait utiliser les CPU de façon non négligeable. De cette façon les processus
peuvent être artificiellement contraints à un sous ensemble des CPU en fonction de la configuration de ce
drapeau dans les cpusets descendants. Même si ce processus pourrait utiliser des cycles CPU inutilisés
par certains CPU, l'ordonnanceur du noyau ne cherchera pas à répartir la charge du processus sur le CPU
sous utilisé.
Bien sûr, les processus attachés à un CPU particulier peuvent être laissés dans un cpuset qui désactive
sched_load_balance puisque ces processus ne peuvent être déplacés de toute façon.
Niveau du domaine de détente de l'ordonnanceur
L'ordonnanceur du noyau effectue une répartition de la charge immédiate lorsqu'un CPU devient disponible
ou lorsqu'une autre tâche est prête. Cette répartition de la charge permet de s'assurer que le plus de
CPU possibles sont utilisés efficacement en exécutant des tâches. Le noyau effectue aussi une répartition
de la charge de façon plus sporadique sur la base de l'horloge logicielle décrite dans time(7). La
configuration de sched_relax_domain_level ne s'applique qu'à la répartition de charge automatique.
Indépendamment de la configuration de sched_relax_domain_level, une répartition de charge sporadique est
effectuée à travers tous les CPU (sauf si cela a été désactivé avec sched_load_balance). Dans tous les
cas, bien sûr, les tâches ne seront exécutées que sur les CPU autorisés par leur cpuset et par les appels
systèmes sched_setaffinity(2).
Sur les petits systèmes, avec peu de CPU, la répartition de charge immédiate est utile pour améliorer
l'interactivité du système et minimiser les cycles CPU inutilisés. Mais sur les gros systèmes, essayer de
répartir la charge immédiatement sur un nombre important de CPU peut être plus coûteux que ce que ça ne
rapporte, en fonction des performances des différentes tâches et du matériel.
La signification exacte des petites valeurs de sched_relax_domain_level dépendra de l'implémentation de
l'ordonnanceur du noyau et de l'architecture non uniforme du matériel. Ces deux paramètres évolueront
dans le temps et dépendent de l'architecture du système et de la version du noyau.
À ce jour, quand cette capacité a été introduite sous Linux 2.6.26, la signification des valeurs
positives de sched_relax_domain_level est la suivante pour certaines des architectures les plus
courantes :
(1) Effectuer immédiatement une répartition de la charge sur les différents Hyper-Thread frères d'un même
cœur.
(2) Effectuer immédiatement une répartition de la charge sur les différents cœurs d'un processeur.
(3) Effectuer immédiatement une répartition de la charge sur les différents CPU d'un même nœud ou d'une
même lame.
(4) Effectuer immédiatement une répartition de la charge sur les différents (détail d'implémentation)
nœuds [pour les systèmes NUMA].
(5) Effectuer immédiatement une répartition de la charge sur tous les CPU d'un système [pour les systèmes
NUMA].
La valeur zéro (0) pour sched_relax_domain_level signifie toujours qu'il n'y a pas de répartition de
charge immédiate, et donc la répartition de la charge s'effectue périodiquement et non pas immédiatement
quand un CPU devient disponible ou qu'une tâche peut être exécutée.
La valeur -1 pour sched_relax_domain_level signifie toujours qu'il faut utiliser la valeur par défaut du
système. La valeur par défaut du système peut varier en fonction de l'architecture et du noyau. Cette
valeur par défaut du système peut être modifiée en fournissant au noyau un paramètre
« relax_domain_level= » lors du démarrage.
Si des cpusets partagent des CPU et ont des valeurs de sched_relax_domain_level incompatibles, alors la
valeur la plus élevée s'applique à tous les CPU de ces cpusets. Dans ce cas, la valeur moins un (-1) est
la valeur la plus faible, remplacée par toute autre valeur et la valeur zéro (0) est la valeur la plus
faible suivante.
FORMATS
Les formats suivants sont utilisés pour représenter des ensembles de CPU et de nœuds mémoire.
Affichage sous forme de masque
L'Affichage sous forme de masque est utilisé pour représenter les masques de bits des CPU et nœuds
mémoire dans le fichier /proc/<pid>/status.
Ce format affiche chaque mot de 32 bits au format hexadécimal (en utilisant les caractères ASCII « 0 » -
« 9 » et « a » - « f ») ; le début des mots est complété par des zéros si nécessaire. Pour les masques de
plus d'un mot, une virgule est utilisée pour séparer les mots. Les mots sont affiché au format grand
boutiste, avec le bit le plus significatif en premier. Les chiffres hexadécimaux d'un mot utilise aussi
l'ordre grand boutiste.
Le nombre de mots de 32 bits affichés est le nombre minimal nécessaire pour afficher tous les bits du
masque, en fonction de la taille du masque de bits.
Exemple d'Affichage sous forme de masque :
00000001 # seul le bit 0
40000000,00000000,00000000 # seul le bit 94
00000001,00000000,00000000 # seul le bit 64
000000ff,00000000 # seuls les bits 32-39
00000000,000e3862 # les bits 1,5,6,11-13,17-19
Un masque avec les bits 0, 1, 2, 4, 8, 16, 32 et 64 activés sera affiché de cette façon :
00000001,00000001,00010117
Le premier « 1 » correspond au bit 64, le second au bit 32, le troisième au bit 16, le quatrième au bit
8, le cinquième au bit 4 et le « 7 » correspond aux bits 2, 1 et 0.
Affichage sous forme de liste
L'Affichage sous forme de liste pour les fichiers cpus et mems est une liste de numéros ou intervalles de
CPU ou de nœuds mémoire séparés par des virgules, en décimal au format ASCII.
Exemple d'Affichage sous forme de liste :
0-4,9 # bits 0, 1, 2, 3, 4 et 9 activés
0-2,7,12-14 # bits 0, 1, 2, 7, 12, 13 et 14 activés
RÈGLES
Les règles suivantes s'appliquent à chaque cpuset :
– Ses CPU et nœuds mémoire doivent être des sous-ensembles de ceux de leur parent (ou les mêmes
ensembles).
– Il ne peut être marqué avec cpu_exclusive que si son parent l'est.
– Il ne peut être marqué avec mem_exclusive que si son parent l'est.
– S'il est marqué avec cpu_exclusive, ses CPU ne doivent pas être partagés avec ses frères.
– S'il est marqué avec memory_exclusive, ses nœuds mémoire ne doivent pas être partagés avec ses frères.
PERMISSIONS
Les permissions d'un cpuset sont déterminées par les permissions des répertoires et pseudofichiers du
système de fichiers cpuset, normalement monté dans /dev/cpuset.
Par exemple, un processus peut se placer dans un autre cpuset s'il peut écrire dans le fichier tasks de
ce cpuset. Ceci nécessite les permission d'exécution des répertoires à traverser et la permission
d'écrire dans le fichier tasks.
Une contrainte supplémentaire s'applique aux demandes de déplacement d'autres processus dans un cpuset.
Un processus ne peut pas attacher un autre processus à un cpuset à moins qu'il ait la permission
d'envoyer un signal à ce processus (consultez kill(2)).
Un processus peut créer un cpuset fils s'il a accès et peut écrire dans le répertoire du cpuset père. Il
peut modifier les CPU et nœuds mémoire d'un cpuset s'il a accès au répertoire de ce cpuset (les
permissions d'exécuter tous les répertoires parents) et s'il peut écrire dans les fichiers correspondants
cpus ou mems.
Il y a une petite différence entre la manière dont ces permissions sont évaluées et la manière dont sont
évaluées les permissions pour les opérations sur des systèmes de fichiers normaux. Le noyau interprète
les chemins relatifs en fonction du répertoire de travail actuel d'un processus. Même quand on opère sur
un fichier d'un cpuset, les chemins relatifs sont interprétés en fonction du répertoire de travail du
processus, et non pas relativement au cpuset actuel du processus. Les seules façons pour que les chemins
de cpusets soient interprétés relativement au cpuset actuel du processus sont soit que le processus
utilise le répertoire du cpuset comme répertoire de travail (il a d'abord effectué un cd ou chdir(2) dans
le répertoire de son cpuset dans /dev/cpuset, ce qui est plutôt inhabituel), soit que du code utilisateur
convertit le chemin relatif au cpuset en un chemin absolu.
En théorie, ceci signifie que le code utilisateur devrait indiquer les cpusets en utilisant des chemins
absolus, ce qui nécessite de connaître le point de montage du système de fichier cpuset (d'habitude, mais
sans que ce soit nécessaire, /dev/cpuset). En pratique, à la connaissance de l'auteur, tous les
utilitaires en mode utilisateur supposent que si le système de fichier cpuset est monté, alors il est
monté dans /dev/cpuset. De plus, une pratique assez courante utilisé pour du code écrit soigneusement
consiste à vérifier la présence du pseudofichier /dev/cpuset/tasks afin de vérifier que le pseudosystème
de fichiers cpuset est bien monté.
AVERTISSEMENTS
Activation de memory_pressure
Par défaut, le fichier cpuset.memory_pressure d'un cpuset vaut zéro (0). À moins que cette fonctionnalité
soit activée en écrivant « 1 » dans le pseudofichier /dev/cpuset/cpuset.memory_pressure_enabled, le noyau
ne calcule pas les valeurs des fichiers memory_pressure de chaque cpuset.
Utilisation de la commande echo
Lorsque la commande echo est utilisée dans un interpréteur de commandes pour changer les valeurs des
fichiers d'un cpuset, soyez conscient que la commande echo interne à certains interpréteurs de commandes
n'affiche pas de message d'erreur si l'appel système write(2) échoue. Par exemple, si la commande :
echo 19 > cpuset.mems
échoue parce que le nœud mémoire numéro 19 n'est pas autorisé (par exemple le système n'a pas de nœud
mémoire numéro 19), alors la commande echo peut n'afficher aucune erreur. If faut mieux utiliser la
commande externe /bin/echo pour changer la configuration d'un fichier d'un cpuset puisque cette commande
affichera les erreurs de write(2), comme par exemple :
/bin/echo 19 > cpuset.mems
/bin/echo : erreur d'écriture : argument invalide
EXCEPTIONS
Placement mémoire
Les contraintes des cpusets ne s'appliquent pas à toutes les allocations de mémoire système pour les
raisons suivantes :
Si la fonctionnalité de connexion à chaud est utilisée pour supprimer tous les CPU d'un cpuset, alors le
noyau mettra à jour automatiquement la liste de CPU autorisés (cpus_allowed) de tous les processus
attachés aux CPU du cpuset et autorisera tous les CPU. Le comportement est similaire lorsque la
fonctionnalité de connexion à chaud est utilisée pour la mémoire. En général, le noyau préfère ne pas
tenir compte du placement sur les CPU ou les nœuds mémoire plutôt que d'abandonner un processus dont tous
les CPU ou nœuds mémoire autorisés sont déconnectés. Le code utilisateur devrait reconfigurer les cpusets
pour ne mentionner que les CPU et les nœuds mémoire en ligne lorsque la fonctionnalité de connexion à
chaud est utilisée pour ajouter ou retirer ces ressources.
Quelques demandes d'allocation mémoire critiques et internes au noyau, marquées GFP_ATOMIC, doivent être
satisfaites immédiatement. Le noyau peut rater des demandes ou ne pas fonctionner correctement si
certaines de ces allocations échouent. Si une de ces demandes ne peut être satisfaite par le cpuset du
processus en cours, alors les contraintes du cpuset sont relâchées et le noyau recherche de la mémoire là
où il peut en trouver. Il est préférable de ne pas respecter un cpuset plutôt que de stresser le noyau.
Les allocations de mémoire demandées par des pilotes du noyau lors du traitement d'une interruption ne se
trouvent dans le contexte d'aucun processus et ne sont donc pas contraintes par les cpusets.
Renommer des cpusets
Vous pouvez utiliser l'appel système rename(2) pour renommer des cpusets. Seuls des renommages simples
sont pris en charge ; c'est-à-dire que changer le nom du répertoire d'un cpuset est autorisé, mais
déplacer le répertoire d'un cpuset dans un autre répertoire n'est pas autorisé.
ERREURS
L'implémentation des cpusets du noyau Linux positionne errno pour indiquer la raison de l'échec d'un
appel système lié à un cpuset.
Les valeurs possible pour errno et leurs significations, lors d'un échec d'un appel système lié à un
cpuset sont listées ci-dessous :
E2BIG Tentative d'écriture (write(2)) dans un fichier spécial d'un cpuset avec une longueur supérieure à
la longueur autorisée par le noyau pour ces écritures.
EACCES Tentative d'écriture (write(2)) d'un identifiant de processus (PID) dans le fichier tasks d'un
cpuset alors que l'appelant n'est pas autorisé à déplacer le processus.
EACCES Tentative d'ajout, avec write(2), d'un CPU ou d'un nœud mémoire dans un cpuset alors que ce CPU ou
ce nœud mémoire ne se trouve pas dans le cpuset parent.
EACCES Tentative d'activation, avec write(2), de cpuset.cpu_exclusive ou de cpuset.mem_exclusive sur un
cpuset dont le parent n'a pas ces propriétés.
EACCES Tentative d'écriture (write(2)) dans un fichier cpuset.memory_pressure.
EACCES Tentative de création d'un fichier dans le répertoire d'un cpuset.
EBUSY Tentative de suppression, avec rmdir(2), d'un cpuset auquel sont attachés des processus.
EBUSY Tentative de suppression, avec rmdir(2), d'un cpuset ayant des ensembles de CPU fils.
EBUSY Tentative de suppression d'un CPU ou d'un nœud mémoire d'un cpuset alors que le CPU ou le nœud
mémoire se trouve également dans un des fils du cpuset.
EEXIST Tentative de création, avec mkdir(2), d'un cpuset qui existe déjà.
EEXIST Tentative de renommage (rename(2)) d'un cpuset avec un nom déjà utilisé.
EFAULT Tentative de lecture (read(2)) ou d'écriture (write(2)) dans un fichier d'un cpuset en utilisant
un tampon en dehors de l'espace mémoire accessible par le processus appelant.
EINVAL Tentative de modification d'un cpuset, en utilisant write(2), de telle sorte que les attributs
cpu_exclusive ou mem_exclusive ne soient plus respectés pour ce cpuset ou ses frères.
EINVAL Tentative d'écriture (avec write(2)) d'une liste vide dans cpuset.cpus ou cpuset.mems pour un
cpuset auquel sont déjà attachés des processus ou des cpuset fils.
EINVAL Tentative d'écriture (avec write(2)) dans cpuset.cpus ou cpuset.mems d'une liste qui comprend un
intervalle dont la borne supérieure est inférieure à la borne inférieure.
EINVAL Tentative d'écriture (avec write(2)) dans cpuset.cpus ou cpuset.mems d'une liste dont la chaîne
comprend un caractère non valable.
EINVAL Tentative d'écriture (avec write(2)) dans le fichier cpuset.cpus d'une liste qui ne comprend aucun
CPU en ligne.
EINVAL Tentative d'écriture (avec write(2)) dans le fichier cpuset.mems d'une liste qui ne comprend aucun
nœud mémoire en ligne.
EINVAL Tentative d'écriture (avec write(2)) dans le fichier cpuset.mems d'une liste qui comprend un nœud
qui ne contient pas de mémoire.
EIO Tentative d'écriture (avec write(2)) dans le fichier tasks d'un cpuset d'une chaîne qui ne
commence pas par un entier décimal au format ASCII.
EIO Tentative de renommage (avec rename(2)) d'un cpuset dans un autre répertoire.
ENAMETOOLONG
Tentative de lecture (avec read(2)) du fichier /proc/<pid>/cpuset d'un cpuset, pour lequel le
chemin est plus long que la taille des pages du noyau.
ENAMETOOLONG
Tentative de création, avec mkdir(2), d'un cpuset dont le nom du répertoire de base fait plus de
255 caractères.
ENAMETOOLONG
Tentative de création, avec mkdir(2), d'un cpuset dont le chemin complet, préfixe du point de
montage compris (typiquement « /dev/cpuset/ »), fait plus de 4095 caractères.
ENODEV Le cpuset a été supprimé par un autre processus en même temps qu'une tentative d'écriture (avec
write(2)) sur un des pseudofichiers du répertoire du cpuset.
ENOENT Tentative de création, avec mkdir(2), d'un cpuset dans un cpuset parent qui n'existe pas.
ENOENT Tentative d'accéder à (avec access(2)) ou d'ouvrir (avec open(2)) un fichier inexistant du
répertoire d'un cpuset.
ENOMEM Pas assez de mémoire disponible pour le noyau ; ceci peut se produire pour différents appels
système liés aux cpusets, mais seulement si le système manque beaucoup de mémoire.
ENOSPC Tentative d'écriture (avec write(2)) de l'identifiant d'un processus dans le fichier tasks d'un
cpuset alors que les fichiers cpuset.cpus ou cpuset.mems sont vides.
ENOSPC Tentative d'écriture (avec write(2)) d'un fichier cpuset.cpus ou cpuset.mems vide dans un cpuset
auquel sont attachées des tâches.
ENOTDIR
Tentative de renommage (avec rename(2)) d'un cpuset qui n'existe pas.
EPERM Tentative de suppression d'un fichier dans le répertoire d'un cpuset.
ERANGE Une liste pour cpuset.cpus ou cpuset.mems a été fournie au noyau mais comprend un nombre trop
grand pour que le noyau l'ajoute à son champ de bits.
ESRCH Tentative d'écriture (avec write(2)) de l'identifiant d'un processus inexistant dans le fichier
tasks d'un cpuset.
VERSIONS
Les cpusets sont apparus dans la version 2.6.12 du noyau Linux.
NOTES
Contrairement à ce que son nom indique, le paramètre pid est en fait un identifiant de thread. Chaque
thread d'un groupe de threads peut être attaché un cpuset différent. La valeur renvoyée par un appel à
gettid(2) peut être fournie comme paramètre pid.
BOGUES
Les fichiers cpuset.memory_pressure peuvent être ouverts en écriture en demandant une création ou
troncature, mais dans ce cas write(2) échouera en positionnant errno à EACCES, et les options de création
ou de troncature de open(2) n'ont aucun effet.
EXEMPLES
Voici des exemples pour l'affichage et la modification d'options d'un cpuset à l'aide d'un interpréteur
de commandes.
Créer et s'attacher à un cpuset.
Voici les étapes pour créer un nouveau cpuset et lui attacher l'interpréteur de commandes en cours :
1) mkdir /dev/cpuset (si ce n'est déjà fait)
2) mount -t cpuset none /dev/cpuset (si ce n'est déjà fait)
3) Créer un nouveau cpuset avec mkdir(1).
4) Assigner des CPU et nœuds mémoire au nouveau cpuset.
5) Attacher l'interpréteur de commandes au nouveau cpuset.
Par exemple, la séquence de commandes suivante définira un cpuset appelé « Charlie », ne contenant que
les CPU 2 et 3 et le nœud mémoire 1, et attachera l'interpréteur de commandes en cours à ce cpuset.
$ mkdir /dev/cpuset
$ mount -t cpuset cpuset /dev/cpuset
$ cd /dev/cpuset
$ mkdir Charlie
$ cd Charlie
$ /bin/echo 2-3 > cpuset.cpus
$ /bin/echo 1 > cpuset.mems
$ /bin/echo $$ > tasks
# The current shell is now running in cpuset Charlie
# The next line should display '/Charlie'
$ cat /proc/self/cpuset
Déplacer des tâches sur d'autres nœuds mémoire.
Pour déplacer les tâches attachées à un cpuset sur d'autres CPU et d'autres nœuds mémoire du système et
déplacer les pages mémoires actuellement allouées par ces processus, effectuez les étapes suivantes :
1) Let's say we want to move the job in cpuset alpha (CPUs 4–7 and memory nodes 2–3) to a new cpuset
beta (CPUs 16–19 and memory nodes 8–9).
2) Créer d'abord le nouveau cpuset beta.
3) Then allow CPUs 16–19 and memory nodes 8–9 in beta.
4) Activer memory_migration dans beta.
5) Déplacer chaque tâche d'alpha vers beta.
La séquence de commandes suivante effectue cela.
$ cd /dev/cpuset
$ mkdir beta
$ cd beta
$ /bin/echo 16-19 > cpuset.cpus
$ /bin/echo 8-9 > cpuset.mems
$ /bin/echo 1 > cpuset.memory_migrate
$ while read i; do /bin/echo $i; done < ../alpha/tasks > tasks
The above should move any processes in alpha to beta, and any memory held by these processes on memory
nodes 2–3 to memory nodes 8–9, respectively.
Notez que la dernière étape de la séquence ci-dessus n'était pas :
$ cp ../alpha/tasks tasks
La boucle while, plutôt que l'utilisation de la commande cp(1), est nécessaire par ce qu'un seul
identifiant de processus à la fois peut être écrit dans le fichier tasks.
La même chose (l'écriture d'un PID à la fois) peut se faire plus efficacement qu'avec la boucle while, en
moins de caractère et dans une syntaxe qui fonctionne avec tous les interpréteurs de commandes mais
malheureusement de façon moins intelligible, en utilisant l'option -u (sans tampon) de sed(1) :
$ sed -un p < ../alpha/tasks > tasks
VOIR AUSSI
taskset(1), get_mempolicy(2), getcpu(2), mbind(2), sched_getaffinity(2), sched_setaffinity(2),
sched_setscheduler(2), set_mempolicy(2), CPU_SET(3), proc(5), cgroups(7), numa(7), sched(7),
migratepages(8), numactl(8)
Documentation/admin-guide/cgroup-v1/cpusets.rst in the Linux kernel source tree (or
Documentation/cgroup-v1/cpusets.txt before Linux 4.18, and Documentation/cpusets.txt before Linux 2.6.29)
COLOPHON
Cette page fait partie de la publication 5.10 du projet man-pages Linux. Une description du projet et des
instructions pour signaler des anomalies et la dernière version de cette page peuvent être trouvées à
l'adresse https://www.kernel.org/doc/man-pages/.
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> et Frédéric Hantrais
<fhantrais@gmail.com>
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.
Linux 1 novembre 2020 CPUSET(7)