Cpuset
| Fiche express | |
|---|---|
| Domaine | Isolation CPU/mémoire d'un groupe de processus (cgroups) |
| Mécanisme | sous-système cpuset — cgroups v1 ou v2
|
| Contexte | Isolation durable d'une charge (VM, conteneur, appli critique) — souvent abstrait par systemd/Docker/Kubernetes |
| Voir aussi | Taskset (affinité ponctuelle d'un process), Numactl (politique NUMA) |
cpuset est le mécanisme du noyau Linux, exposé via les cgroups, qui permet de restreindre et d'isoler l'ensemble des CPU (et des nœuds mémoire NUMA) sur lesquels un groupe entier de processus est autorisé à s'exécuter. Contrairement à un simple épinglage d'un processus isolé, cpuset définit une hiérarchie persistante de groupes : tout processus placé dans un cgroup cpuset hérite de la restriction, ainsi que tous les processus qu'il lance par la suite, ce qui en fait l'outil adapté pour isoler durablement une charge du reste du système plutôt que de gérer l'affinité processus par processus.
Cgroups v1 ou v2
Sous cgroups v1, cpuset est un sous-système dédié, monté typiquement sous /sys/fs/cgroup/cpuset/, avec sa propre hiérarchie de répertoires. Sous cgroups v2, la hiérarchie est unifiée (/sys/fs/cgroup/) et cpuset devient un contrôleur parmi d'autres (mémoire, CPU, I/O) activé sur cette hiérarchie unique via le fichier cgroup.subtree_control.
Il a existé par le passé un outil en espace utilisateur nommé cpuset (paquet python-cpuset) qui fournissait une commande dédiée pour créer et gérer des cpusets sans toucher directement aux fichiers virtuels. Il est aujourd'hui obsolète et absent des distributions récentes : la gestion passe soit par une manipulation directe des cgroups, soit par les couches d'abstraction modernes (voir plus bas).
Différence avec taskset
Taskset fixe l'affinité CPU d'un seul processus (et de ses threads) au lancement ou à la volée via un masque ou une liste de CPU ; c'est une action ponctuelle qui ne s'applique qu'au processus visé et ne se transmet pas automatiquement à une hiérarchie de processus organisée. cpuset, lui, crée un groupe cgroup persistant auquel on assigne un ensemble de CPU et de nœuds mémoire, puis dans lequel on place des PID : tout processus déplacé dans ce groupe, et tous les processus qu'il lance ensuite, hérite automatiquement de la restriction sans qu'il soit nécessaire de relancer taskset à chaque nouveau processus.
Différence avec numactl
Numactl exprime une préférence ou une politique NUMA (liaison stricte, préférence souple, entrelacement) pour l'allocation mémoire et l'exécution d'un processus donné, mais reste une politique appliquée au niveau du processus que le noyau peut, selon les cas, ne pas pouvoir honorer intégralement si la ressource préférée n'est pas disponible. cpuset impose au contraire une restriction dure au niveau du scheduler et de l'allocateur mémoire du noyau : les CPU et nœuds mémoire exclus du cpuset sont tout simplement inaccessibles au groupe, ce n'est donc pas une préférence mais une frontière imposée.
Exemple manuel (cgroups v1)
Créer et peupler un cpuset directement via le système de fichiers virtuel :
# créer un nouveau groupe cpuset
mkdir /sys/fs/cgroup/cpuset/monjob
# lui attribuer les CPU 0 et 1
echo 0-1 > /sys/fs/cgroup/cpuset/monjob/cpuset.cpus
# lui attribuer le nœud mémoire NUMA 0 (obligatoire, sinon le groupe reste inutilisable)
echo 0 > /sys/fs/cgroup/cpuset/monjob/cpuset.mems
# y placer le shell courant (et donc tout ce qu'il lance ensuite)
echo $$ > /sys/fs/cgroup/cpuset/monjob/tasks
# vérifier la composition du groupe
cat /sys/fs/cgroup/cpuset/monjob/cpuset.cpus
cat /sys/fs/cgroup/cpuset/monjob/tasks
⚠️ Cette manipulation directe des fichiers virtuels reste utile pour comprendre le mécanisme, mais les outils modernes passent en pratique par une couche d'abstraction plutôt que par une écriture manuelle : systemd propose AllowedCPUs= dans une unit ou un slice, Docker et Kubernetes exposent l'option --cpuset-cpus (ou le CPU Manager en politique statique pour Kubernetes), qui créent et gèrent le cgroup cpuset correspondant en coulisses.