cpuset(7) Miscellaneous Information Manual cpuset(7) NOM cpuset - Confiner des processus a des sous-ensembles de processeurs et de noeuds memoire DESCRIPTION Le systeme de fichiers cpuset (N.d.T. : << cpuset >> signifie mot a mot << ensemble de CPU >>, mais comme il ne s'agit pas uniquement d'ensembles de CPU, le terme cpuset sera utilise par la suite) est une interface sous forme d'un pseudosysteme de fichiers pour le mecanisme << cpuset >> du noyau, qui permet de controler le placement de processus sur des processeurs ou en memoire. Il est habituellement monte 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 definit une liste de CPU et de noeuds memoire. Les CPU d'un systeme comprennent toutes les unites de traitement logiques sur lesquelles peuvent s'executer des processus, comprenant, s'il y en a, les differents coeurs d'un processeur et les Hyper-Threads d'un coeur de processeur. Les noeuds memoire comprennent tous les bancs distinct de memoire ; les petits systemes et les systemes SMP ont typiquement un seul noeud memoire qui contient toute la memoire du systeme, alors que les systemes NUMA (<< non-uniform memory access >> : acces non uniforme a la memoire) ont plusieurs noeuds memoire. Les cpusets sont representes par des repertoires dans un pseudosysteme de fichiers hierarchique dont le repertoire de plus haut niveau (/dev/cpuset) represente le systeme complet (tous les CPU et noeuds memoire en ligne). Tout cpuset fils (le descendant) d'un autre cpuset pere contient un sous-ensemble des CPU et des noeuds memoire du pere. Les repertoires et les fichiers qui representent les cpusets ont les permissions habituelles des systemes de fichiers. Chaque processus du systeme appartient a un unique cpuset. Un processus est oblige de s'executer sur les CPU du cpuset auquel il appartient et est oblige d'allouer de la memoire uniquement sur les noeuds memoire de ce cpuset. Quand un processus cree un fils avec fork(2), le processus fils est place dans le meme cpuset que le processus pere. S'il a les privileges suffisants, le processus fils peut se deplacer d'un cpuset a un autre et les CPU ou noeuds memoire d'un cpuset existant peuvent etre changes. Au debut du demarrage du systeme, un seul cpuset est defini qui comprend tous les CPU et tous les noeuds memoire du systeme et tous les processus se trouvent dans ce cpuset. Pendant le demarrage ou par la suite lors de l'execution normale du systeme, d'autres cpusets peuvent etre crees, en tant que sous-repertoire de ce cpuset de plus haut niveau, sous le controle de l'administrateur systeme. Des processus peuvent etre places dans ces autres cpusets. Les cpusets sont integres dans le noyau avec le mecanisme d'affinite d'ordonnancement de sched_setaffinity(2) et les mecanismes de placement en memoire de mbind(2) et set_mempolicy(2). Aucun de ces mecanismes ne permettent a un processus d'utiliser un CPU ou un noeud memoire qui n'est pas autorise par le cpuset du processus. Si une modification du cpuset entre en conflit avec ces autres mecanismes, le placement dans le cpuset est force, meme si cela signifie qu'il faut outrepasser ces autres mecanismes. Ceci est fait silencieusement par le noyau en restreignant les CPU et noeuds memoire demandes par ces autres mecanismes a ceux qui sont autorises par le cpuset du processus appelant. Ces autres appels peuvent alors renvoyer une erreur si, par exemple, ils sont amenes a demander un ensemble vide de CPU ou de noeuds memoire apres que la demande est restreinte au cpuset du processus appelant. Typiquement, un cpuset est utilise pour gerer le confinement dans des CPU ou des noeuds memoire pour un ensemble de processus qui cooperent entre eux, comme un ordonnanceur de taches, et ces autres mecanismes permettent de gerer le placement de chacun des processus ou des regions memoire pour chacune de ces taches. FICHIERS Chaque repertoire de /dev/cpuset represente un cpuset et contient un ensemble definit de pseudofichiers qui decrivent l'etat de ce cpuset. Les nouveaux cpusets sont crees avec l'appel systeme mkdir(2) ou la commande mkdir(1). Les proprietes d'un cpuset, comme ses drapeaux, les CPU et noeuds memoire autorises et les processus attaches sont recuperes ou modifies en lisant ou ecrivant dans le fichier approprie du repertoire du cpuset. Ces fichiers sont decrits ci-dessous. Les pseudofichiers dans chaque repertoire d'un cpuset sont crees automatiquement quand le cpuset est cree, suite a l'appel a mkdir(2). Il n'est pas possible d'ajouter ou de supprimer directement ces pseudofichiers. Le repertoire d'un cpuset qui ne contient pas de repertoire pour un cpuset fils et n'a pas de processus lui etant attache peut etre supprime a l'aide de rmdir(2) ou rmdir(1). Il n'est pas necessaire, ou possible, de supprimer les pseudofichiers du repertoire avant de le supprimer. Les pseudofichiers des repertoires d'un cpuset sont de petits fichiers textes qui peuvent etre lus ou ecrits en utilisant les outils traditionnels comme cat(1) et echo(1) ou depuis un programme en utilisant des fonctions d'une bibliotheque d'entrees sorties ou des appels systeme, comme open(2), read(2), write(2) et close(2). Les pseudofichiers dans un repertoire d'un cpuset representent l'etat interne du noyau et n'ont pas de representation persistante sur le disque. Les fichiers d'un cpuset sont listes et decrits ci-dessous. tasks Liste des identifiants de processus (PID) des processus dans ce cpuset. La liste contient une serie de nombres decimaux au format ASCII, chacun suivit d'une nouvelle ligne. Un processus peut etre ajoute a un cpuset (ce qui le supprime automatiquement du cpuset qui le contenait auparavant) en ecrivant son PID dans le fichier tasks du cpuset (avec ou sans nouvelle ligne a la fin). Attention : un seul PID peut etre ecrit a la fois dans le fichier tasks. Si une chaine est ecrite et qu'elle contient plus d'un PID, seul le premier sera utilise. notify_on_release Drapeau (0 ou 1). Lorsqu'il est active (1), ce cpuset sera gere de facon particuliere une fois qu'il sera libere, c'est-a-dire apres que tous les processus cessent de l'utiliser (c'est-a-dire se terminent ou ont ete deplaces dans un autre ensemble de CPU) et que tous les repertoires des cpusets fils ont ete supprimes. Consultez la section Notification a la liberation ci-dessous. cpuset.cpus Liste des numeros physiques des CPU sur lesquels les processus de ce cpuset ont le droit de s'executer. Consultez la section Format des listes ci-dessous pour une description du format de cpus. Les CPU autorises pour un cpuset peuvent etre changes en ecrivant 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 freres s'ils ont le meme cpuset pere dans la hierarchie /dev/cpuset. Deux cpusets sont cousins si aucun n'est l'ancetre de l'autre. Independamment du parametre cpu_exclusive, si un cpuset est l'ancetre 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 pere. cpuset.mems Liste des noeuds memoire sur lesquels les processus de ce cpuset ont le droit d'allouer de la memoire. 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). Independamment du parametre mem_exclusive, si un cpuset est l'ancetre d'un autre, alors leurs noeuds memoires doivent se chevaucher parce que l'ensemble des noeuds memoire d'un cpuset est toujours un sous ensemble des noeuds memoire du cpuset pere. 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 memoire causee par les processus d'un cpuset. Consultez la section Pression memoire ci-dessous. A moins que memory_pressure_enabled soit active, il vaut toujours zero. 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 active (1, la valeur par defaut), le noyau repartira automatiquement la charge des processus du cpuset au travers les CPU autorises pour le cpuset. S'il est desactive (0), le noyau ne repartira pas la charge des processus du cpuset, a moins qu'un autre cpuset qui partage des CPU avec lui n'ait son drapeau sched_load_balance active. Consultez la section Repartition de la charge par l'ordonnanceur ci-dessous pour plus de details. cpuset.sched_relax_domain_level (depuis Linux 2.6.26) Entier, compris entre -1 et une petite valeur positive. sched_relax_domain_level controle la largeur de l'intervalle des CPU pour lesquels le noyau effectue une repartition immediate des taches executables. Si sched_load_balance est desactive, alors sched_relax_domain_level ne compte pas, puisqu'il n'y a pas de repartition de la charge. Si sched_load_balance est active, alors plus sched_relax_domain_level est important, plus l'intervalle des CPU sur lesquels le noyau essaie de repartir la charge est important. Consultez la section Niveau du domaine de detente de l'ordonnanceur ci-dessous pour plus de details. In addition to the above pseudo-files in each directory below /dev/cpuset, each process has a pseudo-file, /proc/pid/cpuset, that displays the path of the process's cpuset directory relative to the root of the cpuset filesystem. Also the /proc/pid/status file for each process has four added lines, displaying the process's Cpus_allowed (on which CPUs it may be scheduled) and Mems_allowed (on which memory nodes it may obtain memory), in the two formats Mask Format and List Format (see below) as shown in the following example: Cpus_allowed: ffffffff,ffffffff,ffffffff,ffffffff Cpus_allowed_list: 0-127 Mems_allowed: ffffffff,ffffffff Mems_allowed_list: 0-63 Les champs << allowed >> ont ete ajoutes dans Linux 2.6.24 ; les champs << allowed_list >> ont ete ajoutes dans Linux 2.6.26. CAPACITES ETENDUES En plus de controler quels CPU (cpus) et noeuds memoire (mems) un processus a le droit d'utiliser, les cpusets fournissent les fonctionnalites etendues suivantes. Ensembles de CPU exclusifs Si un cpuset est marque avec cpu_exclusive ou mem_exclusive, aucun autre cpuset, autre que des ancetres ou descendants directs, peuvent partager des CPU ou des noeuds memoire avec ce cpuset. Un cpuset dont mem_exclusive est active restreint les allocations du noyau pour les pages des tampons de cache et autres donnees internes du noyau communement partagees par le noyau au travers differents utilisateurs. Tous les cpusets, que mem_exclusive soit active ou non, restreignent l'allocation de memoire depuis l'espace utilisateur. Ceci permet de configurer un systeme de telle sorte que differentes taches puissent partager des donnees du noyau, tout en isolant toutes les allocations en mode utilisateur des taches dans leur propre cpuset. Pour ceci, il faut creer un gros cpuset, avec mem_exclusive active, pour contenir toutes les taches, et creer des cpuset fils sans mem_exclusive pour chacune des taches. Seule une petite partie de la memoire du noyau, comme les requetes des gestionnaires d'interruptions, est autorisee a etre placee sur des noeuds memoire en dehors d'un cpuset, meme si mem_exclusive est active. Hardwall Un cpuset pour lequel mem_exclusive ou mem_hardwall est active est un cpuset hardwall. Un cpuset hardwall restreint les allocations memoire du noyau pour les pages, tampons et toutes autre donnees partages frequemment par le noyau au travers differents utilisateurs. Tous les cpusets, hardwall ou non, restreignent les allocations memoire pour l'espace utilisateur. Ceci permet de configurer un systeme de telle sorte que differentes taches independantes puissent partager des donnees du noyau, comme des pages des systemes de fichiers, tout en isolant les allocations de l'espace utilisateur de chaque tache dans leur cpuset. Pour ceci, il faut creer un gros cpuset hardwall qui contiendra toutes les taches et creer des cpusets fils (non hardwall) pour chacune des taches. Seule une petite quantite de memoire noyau, comme les demandes des gestionnaires d'interruption, peut etre utilisee a l'exterieur d'un cpuset hardwall. Notification a la liberation Si le drapeau notify_on_release d'un cpuset est active (1), alors quand le dernier processus quitte le cpuset (il se termine ou s'attache a un autre cpuset) et que le dernier cpuset fils de ce cpuset a ete supprime, le noyau executera la commande /sbin/cpuset_release_agent en lui fournissant le chemin (relatif au point de montage du systeme de fichiers cpuset) du cpuset abandonne. Ceci permet de supprimer automatiquement les cpusets abandonnes. Le drapeau notify_on_release du cpuset racine est desactive (0) par defaut au moment du demarrage. La valeur par defaut pour les autres cpusets lors de leur creation est egale a la valeur de notify_on_release de leur cpuset parent. La commande /sbin/cpuset_release_agent est appelee, avec dans argv[1] le nom (un chemin relatif a /dev/cpuset) du cpuset a 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 etre modifie en ecrivant un 0 ou un 1 ASCII (avec ou sans fin de ligne) dans le fichier pour respectivement desactiver ou activer le drapeau. Pression memoire Le fichier memory_pressure d'un cpuset indique la moyenne instantanee du taux auquel les processus du cpuset tentent de liberer de la memoire utilisee sur les noeuds du cpuset pour satisfaire les nouvelles demandes de memoire. Ceci permet a un gestionnaire de taches de superviser les taches qui s'executent dans des cpuset dedies et detecter efficacement la pression memoire qu'une tache produit. Ceci est utile a la fois pour les systemes tres surveilles qui executent diverses taches qui leurs sont fournies et peuvent choisir de terminer ou de changer la priorite des taches qui essaient d'utiliser plus de memoire que les noeuds memoire qui leurs ont ete assignes leurs permettent, et les systemes pour du calcul scientifique avec des taches paralleles, fortement couplees, au temps d'execution important, qui ne pourraient plus fournir les performances demandees si elles se mettaient a utiliser plus de memoire qu'elles n'en ont droit. Ce mecanisme fourni un moyen tres economique pour detecter des signes de pression memoire sur un cpuset. L'action a effectuer lorsqu'un signe de pression memoire est detecte est laisse au libre arbitre du gestionnaire des taches ou autre code utilisateur. A moins que le calcul de la pression memoire soit active par le pseudofichier /dev/cpuset/cpuset.memory_pressure_enabled, cette pression memoire n'est calculee pour aucun cpuset et les lectures dans les fichiers memory_pressure renvoient toujours zero, c'est-a-dire la chaine ASCII << 0\n >>. Consultez la section AVERTISSEMENTS ci-dessous. Une moyenne instantanee par cpuset est utilisee pour les raisons suivantes : - Comme cette metrique est par cpuset plutot que par processus ou par region memoire virtuelle, la charge du systeme due a la supervision de cette metrique par un gestionnaire de taches est fortement reduite sur les gros systemes, etant donne qu'il n'est pas necessaire de parcourir la liste des taches a chaque fois. - Comme cette metrique est une moyenne instantanee plutot qu'un compteur, un gestionnaire de taches obtient la pression memoire en une seule lecture sans avoir a lire et se souvenir des resultats pendant un certain temps. - Because this meter is per-cpuset rather than per-process, the batch scheduler can obtain the key information--memory pressure in a cpuset--with a single read, rather than having to query and accumulate results over all the (dynamically changing) set of processes in the cpuset. La pression memoire d'un cpuset est calculee en utilisant un simple filtre digital par cpuset dans le noyau. Pour chaque cpuset, ce filtre suit le taux auquel les processus attaches a ce cpuset demandent au noyau de reutiliser de la memoire. Ces demandes de reutilisation de memoire se produisent quand un processus doit satisfaire une demande de page memoire en trouvant d'abord une page a reutiliser, du fait de l'absence de page disponible deja prete. Les pages sales des systemes de fichiers sont reutilisees en les ecrivant d'abord sur le disque. Les tampons des systemes de fichiers qui n'ont pas ete modifies sont reutilises tout simplement en les abandonnant, mais si cette page est necessaire de nouveau, il faudra la relire sur le disque. Le fichier cpuset.memory_pressure fournit un nombre entier qui represente le taux des demandes recentes (la demi-vie est de 10 secondes) de reutilisation de memoire par les processus du cpuset, l'unite etant le nombre de demandes par seconde fois 1000. Repartition memoire Il y a deux fichiers, par cpuset, pour des drapeaux booleens qui controlent ou le noyau alloue les pages pour les tampons des systemes de fichiers et les structures de donnees liees internes au noyau. Ces fichiers sont cpuset.memory_spread_page et cpuset.memory_spread_slab. Si le drapeau booleen cpuset.memory_spread_page est active, alors le noyau repartit les tampons des systemes de fichiers (les caches des pages) equitablement sur tous les noeuds autorises pour le processus qui demande la page, au lieu de placer ces pages de preference sur le noeud sur lequel s'execute le processus. Si le drapeau booleen cpuset.memory_spread_slab d'un cpuset est active, alors le noyau repartira uniformement les caches slab lies aux systemes de fichiers, comme ceux pour des entrees d'inoeuds ou de repertoires, sur tous les noeuds autorises pour le processus qui demande de la memoire, plutot que de preferer mettre ces pages sur le noeud sur lequel s'execute le processus. La configuration de ces drapeaux n'affecte pas les pages du segment de donnees (consultez brk(2)) ou du segment de la pile d'un processus. Par defaut, les deux types de repartition de la memoire sont desactives et le noyau prefere allouer la memoire sur le noeud local ou s'execute le processus. Si ce noeud n'est pas autorise par la politique NUMA du processus ou par la configuration des cpusets ou s'il n'y a plus suffisamment de pages memoire disponibles sur ce noeud, alors le noyau recherche le noeud le plus proche etant autorise et ayant suffisamment de pages disponibles. Quand un nouveau cpuset est cree, il herite de la configuration de repartition memoire de son pere. Activer la repartition memoire a pour effet d'ignorer la politique memoire NUMA du processus pour les allocations de pages ou de caches slab, qui sont alors eparpillees. Cependant, les changements dus a la repartition memoire demandee par un cpuset ne sont pas visibles pour les appels systeme mbind(2) ou set_mempolicy(2). Ces deux appels systeme lies a la politique memoire NUMA semblent se comporter comme si aucune repartition memoire n'etait demandee par un cpuset, meme si c'est le cas. Si la repartition memoire est par la suite desactivee pour les cpuset, la derniere politique memoire NUMA definie par ces appels est automatiquement appliquee 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 repartition memoire d'un cpuset se comporte de facon similaire a ce qui est connu (dans d'autres contextes) comme le placement memoire a tour de role (<< round-robin >>) ou entrelace (<< interleave >>). La configuration d'une strategie de repartition memoire pour un cpuset peut ameliorer significativement les performances pour les taches qui : - necessitent de placer les donnees locales des threads dans des noeuds memoire proches des CPU qui executent les threads qui accedent le plus frequemment a ces donnees ; mais aussi - necessitent d'acceder a de gros ensembles de donnees de systemes de fichiers qui doivent etre repartis sur differents noeuds du cpuset de la tache du fait de leurs tailles. Sans cette politique, la repartition des allocations memoire sur les noeuds du cpuset de la tache peut ne pas etre equitable, particulierement pour les taches qui n'auraient qu'un thread charge de l'initialisation ou de la lecture des donnees d'entree. Migration memoire Normalement, avec la configuration de cpuset.memory_migrate par defaut (desactive), une fois qu'une page est allouee (une page physique de la memoire lui est donnee), cette page reste sur le noeud ou elle a ete allouee, tant qu'elle reste allouee, meme si la politique de placement memoire du cpuset (mems) change par la suite. Quand la migration memoire est activee pour un cpuset, si la configuration de mems est modifiee alors toute page memoire utilisee par un processus du cpuset qui se trouverait sur un noeud memoire qui n'est plus autorise sera deplacee sur un noeud memoire qui est autorise. De plus, si un processus est deplace dans un cpuset dont le drapeau memory_migrate est active, toutes les pages memoire qu'il utilise et qui se trouvent sur des noeuds memoire qui etaient autorises dans son cpuset precedant mais ne le sont plus dans le nouveau cpuset seront deplacees sur un noeud memoire autorise pour le nouveau cpuset. L'emplacement relatif d'un page deplacee d'un cpuset est preserve si possible lors de ces operations de deplacement. Par exemple, si la page se trouvait sur le deuxieme noeud valable du precedent cpuset, alors la page sera placee sur le deuxieme noeud valable du nouveau cpuset, si c'est possible. Repartition de la charge par l'ordonnanceur L'ordonnanceur du noyau repartit automatiquement la charge des processus. Si un CPU est sous-utilise, le noyau recherchera des processus sur d'autres CPU plus charges et deplacera ces processus sur le CPU sous-utilise a condition que les mecanismes comme les cpuset et sched_setaffinity(2) le permettent. Le cout de l'algorithme de repartition de la charge et son impact sur les structures de donnees partagees du noyau, comme la liste des processus, augmente plus que lineairement avec le nombre de CPU qui interviennent pour la repartition de la charge. Par exemple le cout pour la repartition de la charge dans un grand ensemble de CPU sera superieur a celui pour la repartition de la charge dans deux ensembles ayant moitie moins de CPU. (La relation entre le nombre de CPU intervenant dans la repartition de la charge et le cout de cette repartition de charge depend de l'implementation de l'ordonnanceur de processus du noyau, qui change dans le temps quand de meilleurs algorithmes d'ordonnancement sont implementes) Le drapeau sched_load_balance d'un cpuset permet de supprimer cette repartition automatique de la charge dans les cas ou elle n'est pas necessaire et que sa suppression ameliorerait les performances. Par defaut, la repartition de la charge se fait sur tous les CPU, a l'exception de ceux marques comme etant isoles en utilisant au moment du demarrage le parametre du noyau << isolcpus= >>. (Consultez la section Niveau du domaine de detente de l'ordonnanceur ci-dessous pour changer le comportement par defaut) Cette repartition de la charge par defaut n'est pas bien adaptee aux situations suivantes : - Sur les gros systemes, la repartition de la charge sur beaucoup de CPU est tres couteuse. Si le systeme est gere avec des cpusets pour placer les taches independantes sur differents ensembles de CPU, une repartition de la charge complete n'est pas necessaire. - Les systemes avec une prise en charge temps-reel sur certains CPU doivent minimiser la surcharge du systeme sur ces CPU et donc eviter la repartition de la charge des processus si elle n'est pas necessaire. Quand le drapeau sched_load_balance d'un cpuset est active (ce qui est le cas par defaut), une repartition de la charge sur tous les CPU autorises par le cpuset est demande, a condition que le processus puisse etre deplace d'un CPU du cpuset a un autre CPU (c'est-a-dire qu'il n'ait pas ete attache a des CPU avec, par exemple, sched_setaffinity(2)). Quand le drapeau sched_load_balance d'un cpuset est desactive, alors l'ordonnanceur evitera de deplacer des processus pour repartir la charge des CPU du cpuset, sauf si un autre cpuset partage le meme CPU et a son drapeau sched_load_balance active. Ainsi, par exemple, si le cpuset racine a son drapeau sched_load_balance active, alors l'ordonnanceur repartira la charge sur tous les CPU et la configuration du drapeau sched_load_balance des autres cpusets n'a pas d'effet, puisqu'une repartition complete de la charge est deja demandee. Dans les deux situations ci-dessus, le drapeau sched_load_balance devrait donc etre desactive sur le cpuset racine et seuls les cpusets fils plus petits devraient l'activer. Lorsque vous faites ceci, vous ne devez generalement pas laisser un processus non attache a un CPU dans le cpuset racine qui pourrait utiliser les CPU de facon non negligeable. De cette facon les processus peuvent etre artificiellement contraints a un sous ensemble des CPU en fonction de la configuration de ce drapeau dans les cpusets descendants. Meme si ce processus pourrait utiliser des cycles CPU inutilises par certains CPU, l'ordonnanceur du noyau ne cherchera pas a repartir la charge du processus sur le CPU sous utilise. Bien sur, les processus attaches a un CPU particulier peuvent etre laisses dans un cpuset qui desactive sched_load_balance puisque ces processus ne peuvent etre deplaces de toute facon. Niveau du domaine de detente de l'ordonnanceur L'ordonnanceur du noyau effectue une repartition de la charge immediate lorsqu'un CPU devient disponible ou lorsqu'une autre tache est prete. Cette repartition de la charge permet de s'assurer que le plus de CPU possibles sont utilises efficacement en executant des taches. Le noyau effectue aussi une repartition de la charge de facon plus sporadique sur la base de l'horloge logicielle decrite dans time(7). La configuration de sched_relax_domain_level ne s'applique qu'a la repartition de charge automatique. Independamment de la configuration de sched_relax_domain_level, une repartition de charge sporadique est effectuee a travers tous les CPU (sauf si cela a ete desactive avec sched_load_balance). Dans tous les cas, bien sur, les taches ne seront executees que sur les CPU autorises par leur cpuset et par les appels systemes sched_setaffinity(2). Sur les petits systemes, avec peu de CPU, la repartition de charge immediate est utile pour ameliorer l'interactivite du systeme et minimiser les cycles CPU inutilises. Mais sur les gros systemes, essayer de repartir la charge immediatement sur un nombre important de CPU peut etre plus couteux que ce que ca ne rapporte, en fonction des performances des differentes taches et du materiel. La signification exacte des petites valeurs de sched_relax_domain_level dependra de l'implementation de l'ordonnanceur du noyau et de l'architecture non uniforme du materiel. Ces deux parametres evolueront dans le temps et dependent de l'architecture du systeme et de la version du noyau. A ce jour, quand cette capacite a ete 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 immediatement une repartition de la charge sur les differents Hyper-Thread freres d'un meme coeur. 2 Effectuer immediatement une repartition de la charge sur les differents coeurs d'un processeur. 3 Effectuer immediatement une repartition de la charge sur les differents CPU d'un meme noeud ou d'une meme lame. 4 Effectuer immediatement une repartition de la charge sur les differents (detail d'implementation) noeuds [pour les systemes NUMA]. 5 Effectuer immediatement une repartition de la charge sur tous les CPU d'un systeme [pour les systemes NUMA]. La valeur zero (0) pour sched_relax_domain_level signifie toujours qu'il n'y a pas de repartition de charge immediate, et donc la repartition de la charge s'effectue periodiquement et non pas immediatement quand un CPU devient disponible ou qu'une tache peut etre executee. La valeur -1 pour sched_relax_domain_level signifie toujours qu'il faut utiliser la valeur par defaut du systeme. La valeur par defaut du systeme peut varier en fonction de l'architecture et du noyau. Cette valeur par defaut du systeme peut etre modifiee en fournissant au noyau un parametre << relax_domain_level= >> lors du demarrage. In the case of multiple overlapping cpusets which have conflicting sched_relax_domain_level values, then the highest such value applies to all CPUs in any of the overlapping cpusets. In such cases, -1 is the lowest value, overridden by any other value, and 0 is the next lowest value. FORMATS Les formats suivants sont utilises pour representer des ensembles de CPU et de noeuds memoire. Affichage sous forme de masque The Mask Format is used to represent CPU and memory-node bit masks in the /proc/pid/status file. Ce format affiche chaque mot de 32 bits au format hexadecimal (en utilisant les caracteres ASCII << 0 >> - << 9 >> et << a >> - << f >>) ; le debut des mots est complete par des zeros si necessaire. Pour les masques de plus d'un mot, une virgule est utilisee pour separer les mots. Les mots sont affiche au format grand boutiste, avec le bit le plus significatif en premier. Les chiffres hexadecimaux d'un mot utilise aussi l'ordre grand boutiste. Le nombre de mots de 32 bits affiches est le nombre minimal necessaire 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 actives sera affiche de cette facon : 00000001,00000001,00010117 Le premier << 1 >> correspond au bit 64, le second au bit 32, le troisieme au bit 16, le quatrieme au bit 8, le cinquieme 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 numeros ou intervalles de CPU ou de noeuds memoire separes par des virgules, en decimal au format ASCII. Exemple d'Affichage sous forme de liste : 0-4,9 # bits 0, 1, 2, 3, 4 et 9 actives 0-2,7,12-14 # bits 0, 1, 2, 7, 12, 13 et 14 actives REGLES Les regles suivantes s'appliquent a chaque cpuset : - Ses CPU et noeuds memoire doivent etre des sous-ensembles de ceux de leur parent (ou les memes ensembles). - Il ne peut etre marque avec cpu_exclusive que si son parent l'est. - Il ne peut etre marque avec mem_exclusive que si son parent l'est. - S'il est marque avec cpu_exclusive, ses CPU ne doivent pas etre partages avec ses freres. - If it is mem_exclusive, its memory nodes may not overlap any sibling. PERMISSIONS Les permissions d'un cpuset sont determinees par les permissions des repertoires et pseudofichiers du systeme de fichiers cpuset, normalement monte dans /dev/cpuset. Par exemple, un processus peut se placer dans un autre cpuset s'il peut ecrire dans le fichier tasks de ce cpuset. Ceci necessite les permission d'execution des repertoires a traverser et la permission d'ecrire dans le fichier tasks. Une contrainte supplementaire s'applique aux demandes de deplacement d'autres processus dans un cpuset. Un processus ne peut pas attacher un autre processus a un cpuset a moins qu'il ait la permission d'envoyer un signal a ce processus (consultez kill(2)). Un processus peut creer un cpuset fils s'il a acces et peut ecrire dans le repertoire du cpuset pere. Il peut modifier les CPU et noeuds memoire d'un cpuset s'il a acces au repertoire de ce cpuset (les permissions d'executer tous les repertoires parents) et s'il peut ecrire dans les fichiers correspondants cpus ou mems. Il y a une petite difference entre la maniere dont ces permissions sont evaluees et la maniere dont sont evaluees les permissions pour les operations sur des systemes de fichiers normaux. Le noyau interprete les chemins relatifs en fonction du repertoire de travail actuel d'un processus. Meme quand on opere sur un fichier d'un cpuset, les chemins relatifs sont interpretes en fonction du repertoire de travail du processus, et non pas relativement au cpuset actuel du processus. Les seules facons pour que les chemins de cpusets soient interpretes relativement au cpuset actuel du processus sont soit que le processus utilise le repertoire du cpuset comme repertoire de travail (il a d'abord effectue un cd ou chdir(2) dans le repertoire de son cpuset dans /dev/cpuset, ce qui est plutot inhabituel), soit que du code utilisateur convertit le chemin relatif au cpuset en un chemin absolu. En theorie, ceci signifie que le code utilisateur devrait indiquer les cpusets en utilisant des chemins absolus, ce qui necessite de connaitre le point de montage du systeme de fichier cpuset (d'habitude, mais sans que ce soit necessaire, /dev/cpuset). En pratique, a la connaissance de l'auteur, tous les utilitaires en mode utilisateur supposent que si le systeme de fichier cpuset est monte, alors il est monte dans /dev/cpuset. De plus, une pratique assez courante utilise pour du code ecrit soigneusement consiste a verifier la presence du pseudofichier /dev/cpuset/tasks afin de verifier que le pseudosysteme de fichiers cpuset est bien monte. AVERTISSEMENTS Activation de memory_pressure Par defaut, le fichier cpuset.memory_pressure d'un cpuset vaut zero (0). A moins que cette fonctionnalite soit activee en ecrivant << 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 utilisee dans un interpreteur de commandes pour changer les valeurs des fichiers d'un cpuset, soyez conscient que la commande echo interne a certains interpreteurs de commandes n'affiche pas de message d'erreur si l'appel systeme write(2) echoue. Par exemple, si la commande : echo 19 > cpuset.mems echoue parce que le noeud memoire numero 19 n'est pas autorise (par exemple le systeme n'a pas de noeud memoire numero 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'ecriture : argument invalide EXCEPTIONS Placement memoire Les contraintes des cpusets ne s'appliquent pas a toutes les allocations de memoire systeme pour les raisons suivantes : Si la fonctionnalite de connexion a chaud est utilisee pour supprimer tous les CPU d'un cpuset, alors le noyau mettra a jour automatiquement la liste de CPU autorises (cpus_allowed) de tous les processus attaches aux CPU du cpuset et autorisera tous les CPU. Le comportement est similaire lorsque la fonctionnalite de connexion a chaud est utilisee pour la memoire. En general, le noyau prefere ne pas tenir compte du placement sur les CPU ou les noeuds memoire plutot que d'abandonner un processus dont tous les CPU ou noeuds memoire autorises sont deconnectes. Le code utilisateur devrait reconfigurer les cpusets pour ne mentionner que les CPU et les noeuds memoire en ligne lorsque la fonctionnalite de connexion a chaud est utilisee pour ajouter ou retirer ces ressources. Quelques demandes d'allocation memoire critiques et internes au noyau, marquees GFP_ATOMIC, doivent etre satisfaites immediatement. Le noyau peut rater des demandes ou ne pas fonctionner correctement si certaines de ces allocations echouent. Si une de ces demandes ne peut etre satisfaite par le cpuset du processus en cours, alors les contraintes du cpuset sont relachees et le noyau recherche de la memoire la ou il peut en trouver. Il est preferable de ne pas respecter un cpuset plutot que de stresser le noyau. Les allocations de memoire demandees 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 systeme rename(2) pour renommer des cpusets. Seuls des renommages simples sont pris en charge ; c'est-a-dire que changer le nom du repertoire d'un cpuset est autorise, mais deplacer le repertoire d'un cpuset dans un autre repertoire n'est pas autorise. ERREURS L'implementation des cpusets du noyau Linux positionne errno pour indiquer la raison de l'echec d'un appel systeme lie a un cpuset. Les valeurs possible pour errno et leurs significations, lors d'un echec d'un appel systeme lie a un cpuset sont listees ci-dessous : E2BIG Tentative d'ecriture (write(2)) dans un fichier special d'un cpuset avec une longueur superieure a la longueur autorisee par le noyau pour ces ecritures. EACCES Tentative d'ecriture (write(2)) d'un identifiant de processus (PID) dans le fichier tasks d'un cpuset alors que l'appelant n'est pas autorise a deplacer le processus. EACCES Tentative d'ajout, avec write(2), d'un CPU ou d'un noeud memoire dans un cpuset alors que ce CPU ou ce noeud memoire 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 proprietes. EACCES Tentative d'ecriture (write(2)) dans un fichier cpuset.memory_pressure. EACCES Tentative de creation d'un fichier dans le repertoire d'un cpuset. EBUSY Tentative de suppression, avec rmdir(2), d'un cpuset auquel sont attaches 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 noeud memoire d'un cpuset alors que le CPU ou le noeud memoire se trouve egalement dans un des fils du cpuset. EEXIST Tentative de creation, avec mkdir(2), d'un cpuset qui existe deja. EEXIST Tentative de renommage (rename(2)) d'un cpuset avec un nom deja utilise. EFAULT Tentative de lecture (read(2)) ou d'ecriture (write(2)) dans un fichier d'un cpuset en utilisant un tampon en dehors de l'espace memoire 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 respectes pour ce cpuset ou ses freres. EINVAL Tentative d'ecriture (avec write(2)) d'une liste vide dans cpuset.cpus ou cpuset.mems pour un cpuset auquel sont deja attaches des processus ou des cpuset fils. EINVAL Tentative d'ecriture (avec write(2)) dans cpuset.cpus ou cpuset.mems d'une liste qui comprend un intervalle dont la borne superieure est inferieure a la borne inferieure. EINVAL Tentative d'ecriture (avec write(2)) dans cpuset.cpus ou cpuset.mems d'une liste dont la chaine comprend un caractere non valable. EINVAL Tentative d'ecriture (avec write(2)) dans le fichier cpuset.cpus d'une liste qui ne comprend aucun CPU en ligne. EINVAL Tentative d'ecriture (avec write(2)) dans le fichier cpuset.mems d'une liste qui ne comprend aucun noeud memoire en ligne. EINVAL Tentative d'ecriture (avec write(2)) dans le fichier cpuset.mems d'une liste qui comprend un noeud qui ne contient pas de memoire. EIO Tentative d'ecriture (avec write(2)) dans le fichier tasks d'un cpuset d'une chaine qui ne commence pas par un entier decimal au format ASCII. EIO Tentative de renommage (avec rename(2)) d'un cpuset dans un autre repertoire. ENAMETOOLONG Attempted to read(2) a /proc/pid/cpuset file for a cpuset path that is longer than the kernel page size. ENAMETOOLONG Tentative de creation, avec mkdir(2), d'un cpuset dont le nom du repertoire de base fait plus de 255 caracteres. ENAMETOOLONG Tentative de creation, avec mkdir(2), d'un cpuset dont le chemin complet, prefixe du point de montage compris (typiquement << /dev/cpuset/ >>), fait plus de 4095 caracteres. ENODEV Le cpuset a ete supprime par un autre processus en meme temps qu'une tentative d'ecriture (avec write(2)) sur un des pseudofichiers du repertoire du cpuset. ENOENT Tentative de creation, avec mkdir(2), d'un cpuset dans un cpuset parent qui n'existe pas. ENOENT Tentative d'acceder a (avec access(2)) ou d'ouvrir (avec open(2)) un fichier inexistant du repertoire d'un cpuset. ENOMEM Pas assez de memoire disponible pour le noyau ; ceci peut se produire pour differents appels systeme lies aux cpusets, mais seulement si le systeme manque beaucoup de memoire. ENOSPC Tentative d'ecriture (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'ecriture (avec write(2)) d'un fichier cpuset.cpus ou cpuset.mems vide dans un cpuset auquel sont attachees des taches. ENOTDIR Tentative de renommage (avec rename(2)) d'un cpuset qui n'existe pas. EPERM Tentative de suppression d'un fichier dans le repertoire d'un cpuset. ERANGE Une liste pour cpuset.cpus ou cpuset.mems a ete fournie au noyau mais comprend un nombre trop grand pour que le noyau l'ajoute a son champ de bits. ESRCH Tentative d'ecriture (avec write(2)) de l'identifiant d'un processus inexistant dans le fichier tasks d'un cpuset. VERSIONS Cpusets appeared in Linux 2.6.12. NOTES Contrairement a ce que son nom indique, le parametre pid est en fait un identifiant de thread. Chaque thread d'un groupe de threads peut etre attache un cpuset different. La valeur renvoyee par un appel a gettid(2) peut etre fournie comme parametre pid. BOGUES Les fichiers cpuset.memory_pressure peuvent etre ouverts en ecriture en demandant une creation ou troncature, mais dans ce cas write(2) echouera en positionnant errno a EACCES, et les options de creation 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 a l'aide d'un interpreteur de commandes. Creer et s'attacher a un cpuset. Voici les etapes pour creer un nouveau cpuset et lui attacher l'interpreteur de commandes en cours : (1) mkdir /dev/cpuset (si ce n'est deja fait) (2) mount -t cpuset none /dev/cpuset (si ce n'est deja fait) (3) Creer un nouveau cpuset avec mkdir(1). (4) Assigner des CPU et noeuds memoire au nouveau cpuset. (5) Attacher l'interpreteur de commandes au nouveau cpuset. Par exemple, la sequence de commandes suivante definira un cpuset appele << Charlie >>, ne contenant que les CPU 2 et 3 et le noeud memoire 1, et attachera l'interpreteur de commandes en cours a 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 Deplacer des taches sur d'autres noeuds memoire. Pour deplacer les taches attachees a un cpuset sur d'autres CPU et d'autres noeuds memoire du systeme et deplacer les pages memoires actuellement allouees par ces processus, effectuez les etapes 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) Creer 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) Deplacer chaque tache d'alpha vers beta. La sequence 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 derniere etape de la sequence ci-dessus n'etait pas : $ cp ../alpha/tasks tasks La boucle while, plutot que l'utilisation de la commande cp(1), est necessaire par ce qu'un seul identifiant de processus a la fois peut etre ecrit dans le fichier tasks. La meme chose (l'ecriture d'un PID a la fois) peut se faire plus efficacement qu'avec la boucle while, en moins de caractere et dans une syntaxe qui fonctionne avec tous les interpreteurs de commandes mais malheureusement de facon 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) TRADUCTION La traduction francaise de cette page de manuel a ete creee par Christophe Blaess , Stephan Rafin , Thierry Vignaud , Francois Micaux, Alain Portal , Jean-Philippe Guerard , Jean-Luc Coulon (f5ibh) , Julien Cristau , Thomas Huriaux , Nicolas Francois , Florentin Duneau , Simon Paillard , Denis Barbier , David Prevot , Cedric Boutillier et Frederic Hantrais Cette traduction est une documentation libre ; veuillez vous reporter a la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITE LEGALE. Si vous decouvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message a . Pages du manuel de Linux 6.06 31 octobre 2023 cpuset(7)