L’outil placement

 

Placement est un outil développé par CALMIP qui répond à deux objectifs principaux :

  1. Optimiser l'affinité des processus et des threads en les positionnant de manière appropriée sur les cœurs de calcul, afin d'améliorer les performances, de réduire les coûts de communication et de favoriser la localité mémoire (NUMA).
  2. Surveiller l'exécution des jobs en fournissant des informations détaillées sur l'utilisation des ressources (cœurs CPU, mémoire, GPU, etc.) et sur le placement effectif des processus et des threads.

Optimiser l'affinité des processus et des threads

Le contrôle du placement des processus MPI et des threads OpenMP est particulièrement important pour les applications hybrides (MPI + OpenMP). Un placement inadapté peut entraîner des migrations de threads, des accès mémoire distants entre nœuds NUMA et, par conséquent, une dégradation significative des performances.

Même pour les applications purement MPI ou purement OpenMP, il est recommandé de vérifier l'affinité des processus et des threads afin de garantir une bonne localité mémoire et une utilisation optimale des ressources du nœud.

L'outil Placement doit être utilisé avec srun. L'utilisation avec mpirun n'est pas prise en charge.

Exemple d'utilisation

L’utilisation de Placement est simple : il suffit de l’intégrer directement dans la commande srun dans le script slurm. L’outil se charge ensuite automatiquement de gérer le placement des processus et des threads.

srun $(placement) mon_executable ...

Avant d’intégrer Placement dans un script de production, il est possible de vérifier son comportement afin de comprendre comment les processus et threads seront répartis sur les ressources allouées. Cela permet d’éviter les mauvaises configurations (affinité incorrecte, déséquilibre NUMA, sur-souscription de cœurs, etc.) avant le lancement réel du calcul.

Supposons un exécutable MPI exécuté sur la partition Kairos avec les caractéristiques suivantes :

  • 6 processus MPI par nœud ;
  • 4 threads OpenMP par processus ;
Vérifier ce qui va se passer (en théorie) :

# placement 6 4 --ascii  
  S0---------------------------------------------------------------------------------------------- S1---------------------------------------------------------------------------------------------- 
P AAAABBBBCCCC.................................................................................... DDDDEEEEFFFF.................................................................................... 
 

  • Le premier paramètre (6) est le nombre de processus
  • Le second paramètre (4) est le nombre de threads par processus
  • Le switch (--ascii) entraîne un affichage en "art ascii", c’est-à-dire une représentation visuelle du placement sur les deux processeurs, uniquement pour un contrôle rapide.

Lecture de la sortie
  - S0 et S1 représentent les deux sockets du nœud.
  - Les lettres A, B, C, D, E, et F représentent les différents processus MPI.
  - Chaque occurrence d'une lettre correspond à un cœur utilisé par un thread du processus associé.
Ainsi :
AAAA signifie que le processus A dispose de 4 threads, chacun étant associé à un cœur de calcul sur le socket S0.

# placement 4 8 --numactl
--physcpubind=0-3,4-7,8-11,96-99,100-103,104-107

Ce résultat montre comment Placement configure l’affinité CPU en tenant compte de la topologie NUMA du nœud.
Sur Kairos, les nœuds sont composés de 6 domaines NUMA (3 par socket).
Comme on peut le constater dans la première sortie de placemetn, chaque paire de processus se trouve sur un socket.

numactl montre: 

  • les trois premiers processus sont placés sur le premier domaine NUMA du premier socket ;
  • les trois processus suivants sont placés sur le premier domaine NUMA du second socket ;
  • la répartition respecte la structure NUMA afin de maximiser la localité mémoire et réduire les accès distants.
     
Générer les switches qui vont bien pour srun :

# placement 4 8 --srun 
--cpu_bind=mask_cpu:0xf,0xf0,0xf00,0xf000000000000000000000000,0xf0000000000000000000000000,0xf00000000000000000000000000
 

  • Les deux premiers paramètres sont inchangés
  • Le switch --srun provoque la sortie compatible avec le contrôle du placement pour srun.
  • la sortie par défaut de placement.

Insérer la commande placement dans le script sbatch:

# srun $(placement) mon_executable ...

  • Les paramètres 6 et 4 sont superflus à condition que la réservation slurm ait été faite correctement, avec les balises #SBATCH --tasks_per_node et #SBATCH --cpus_per_task
  • Le switch --srun est superflu car la sortie "srun" est la sortie par défaut de placement
  • La syntaxe bash $() remplace ce qui est à l’intérieur des parenthèses par la sortie de la commande, donc srun voit simplement les switches de contrôle du placement.

Il est extrêmement important d’ajouter #SBATCH --cpus-per-task dans votre script lorsque vous utilisez Placement, même si vous n’avez qu’un seul thread par processus.

Après avoir utilisé Placement, vous pouvez désormais visualiser le résultat du placement des processus ainsi que l’utilisation des ressources grâce à Placement en mode monitoring.

 

Surveiller l'exécution des jobs

Vous pouvez utiliser Placement depuis votre terminal afin d'obtenir des informations détaillées sur les ressources utilisées par vos jobs en cours d'exécution.
Placement fonctionne pour les deux architectures, x86 et Grace Hopper, et s’adapte en fonction du job sur lequel il est exécuté.

Cas 1 : vous n'avez qu'un seul job en cours

Pour afficher les informations relatives à votre unique job en exécution :

placement --checkme

Cas 2 : vous avez plusieurs jobs en cours

Pour surveiller un job particulier, utilisez son identifiant :

placement --jobid=$jobid

où $jobid correspond à l'identifiant du job à analyser.

Cas 3 : votre job s'exécute sur plusieurs nœuds

Pour obtenir les informations concernant un nœud spécifique :

placement --host=$node_name 

où $node_name est le nom du nœud à surveiller.

Pour surveiller touts les nœud de job:

placement --host=$(squeue -j $jobid -h -o %N)

Options complémentaires

Les commandes précédentes peuvent être combinées avec différentes options afin d'afficher des informations supplémentaires.

Par exemple, Affichage de l'utilisation mémoire d'un job :

placement --jobid=$jobid --memory

Surveillance en temps réel. L'option --rt permet d'effectuer un suivi continu:

placement --host=$node_name --rt

Cette option peut également être utilisée avec d'autres commandes Placement selon vos besoins.

Pour obtenir la liste complète des options disponibles voire la documentation.

Vérifier que le placement est correct:

Lorsque le job est en exécution, il est utile de vérifier que le placement est correct :

On voit ici que :

  • Le placement des threads de chaque processus correspond à ce que l’on souhaite
  • La mémoire des processus est allouée sur les bancs connectés au bon processeur

Vérifier l’utilisation du GPU

Lorsqu’un job est exécuté sur un nœud GPU il est également utile de vérifier que les GPUSs sont effectivement utilisés :

On voit ici que :

  • Les quatre GPUs du nœud sont utilisés
  • Les processus A,B,C,D communiqueront chacun avec un GPU ( chaque GPU sur un socket) 

     

La documentation de placement

La documentation complète de placement peut se lire par :

placement --documentation

L’aide rapide est accessible par :

placement --help

On peut trouver d’autres informations sur le wiki de placement

Voir aussi

FAQ

Questions fréquentes et messages d'erreurs

Lancer un calcul

Les différentes manières de lancer un calcul