Sur les systèmes dont le noyau a été compilé avec la prise en charge des cpusets, tous les processus sont attachés à un cpuset, et les cpusets sont toujours présents. Si un système prend en charge les cpusets, alors il aura une entrée nodev cpuset dans le fichier /proc/filesystems. En montant le système de fichiers cpuset (consultez la section EXEMPLE ci-dessous), l'administrateur peut configurer les cpusets d'un système pour contrôler le placement des processus sur les CPU et dans la mémoire sur de système. Par défaut, si la configuration des cpusets d'un système n'est pas modifiée ou si le système de fichiers cpuset n'est même pas monté, le mécanisme des cpusets, même s'il est présent, n'a pas d'effets sur le comportement du système.
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.
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.
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.
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é.
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.
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.
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\en ». Consultez la section AVERTISSEMENTS ci-dessous.
Une moyenne instantanée par cpuset est utilisée pour les raisons suivantes :
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.
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.
cpuset.memory_spread_page et cpuset.memory_spread_slab sont tous les deux des fichiers contenant des drapeaux booléens. Par défaut, ils contiennent un « 0 », ce qui signifie que la fonctionnalité est désactivée pour ce cpuset. Si un « 1 » est écrit dans le fichier, la fonctionnalité correspondante est activée.
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 :
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.
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.
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 :
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.
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 :
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, -1 est la valeur la plus faible, remplacée par toute autre valeur et -0 est la valeur la plus faible suivante.
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.
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
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é.
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
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.
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 :
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 # Le shell en cours s'exécute désormais dans le cpuset Charlie # La ligne suivante devrait afficher « /Charlie » $ cat /proc/self/cpuset
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
La séquence ci-dessus déplace tous les processus de alpha vers beta et déplace toute mémoire utilisée par ces processus sur les nœuds mémoire 2-3 vers les nœuds mémoire 8-9.
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
Documentation/admin-guide/cgroup-v1/cpusets.rst dans l'arborescence des sources du noyau Linux (ou Documentation/cgroup-v1/cpusets.txt avant Linux 4.18 et Documentation/cpusets.txt avant Linux 2.6.29)
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 à