DOCUMENTATION

Sommaire
1. Introduction 2. Les partitions
3. Lancement d'un job 4. Demande de ressources
 5. Directives utiles 6. Features
7. Suivi de l'état d'un job 8. Autorisations / account Slurm
9. Suivi de sa consommation 10. Espace disque temporaire
11. Variables d'envrionnement 12. Priorités
 13. Exemple de script simple sur la partition public 14. Exemples de script simple sur la partition grant
 15. Exemple de demande de ressources  16. Exemples de jobs MPI
17. Exemples de job OpenMP 18. Exemple de jobs hybrides MPI/OpenMP
19. Exemples de job GPU 20. Exemple de lancement de plusieurs jobs séquentiels (ou d'applications multithread sur peu de cœurs) 

Introduction

Le principe d'un gestionnaire de ressources est de vous réserver des cœurs de calcul en fonction de vos besoins.

Vous interagissez avec le gestionnaire de ressources par les commandes suivantes :

Une documentation des commandes de base est disponible ici : http://slurm.schedmd.com/man_index.html

L'application graphique sview donne accès à l'ensemble des fonctionnalités ci-dessus, en plus d'une vue détaillée de l'ensemble des nœuds de calcul. Chaque onglet de sview est configurable via un click droit à la souris.

Les partitions

Les différents nœuds de calcul sont regroupés en fonction de différents critères dans des partitions. Lors de la soumission d'un job, il faut choisir une partition.

Les partitions à disposition sont les suivantes :

ATTENTION: les jobs soumis dans les partitions grant et privées sont prioritaires sur les jobs soumis dans la partition public. Il est donc possible que des jobs en cours d'exécution dans la partition public soient préemptés, c'est à dire arrêtés et remis en file d'attente.

Lancement d'un job

Pour lancer un job, il faut créer un script dans lequel il faut demander des ressources puis appeler son programme (voir les exemples plus loin).

Ce script est ensuite soumi au gestionnaire de file d'attente avec la commande sbatch. Par exemple :

sbatch mon_script

On obtient alors un numéro de job, qui peut être manipulé avec les commandes scancel, squeue ou scontrol.

Le script peut être écrit dans le langage de son choix (bash, tcsh, python, perl...). Il peut être exécuté directement, sans être appelé par sbatch, et dans ce cas, les directives d'allocations de ressources seront ignorées, et il s'exécutera dans le shell local.

Par défaut, la sortie standard du job (ce qui doit normalement s'afficher sur l'écran lorsque vous exécutez votre programme) sera écrit dans le fichier slurm-jobid.out, avec jobid égal au numéro de job.

Demande de ressources

Vos besoins en terme de ressources sont décrits dans l'en-tête d'un fichier via des directives Slurm. Par exemple :

#SBATCH -N 5
#SBATCH --tasks-per-node 16

demandera une allocation de 5 nœuds à 16 cœurs chacun (par défaut, 1 tâche demande 1 cœur).

D'autres critères peuvent être spécifié via ces directives, comme la taille mémoire souhaitée ou la durée pendant laquelle les ressources seront attribuées.

En règle générale, plus on sera parcimonieux dans la demande d'allocation, plus on aura de chance de voir rapidement son job passer de l'état en attente à l'état en exécution.

Par exemple, s'il est possible d'estimer précisément la durée nécessaire à une exécution, il peut être profitable de réduire au minimum la durée demandée pour la réservation. Ainsi une exécution se faisant en 3h30 pourra se faire au sein d'un job demandant 4h00 (marge de 30mn par précaution), avec la directive suivante :

#SBATCH -t 04:00:00

Attention toutefois à prendre une marge suffisante, car au-delà du temps demandé, l'exécution est stoppée automatiquement par Slurm.

Attention : toutes les partitions sont configurées avec une limite de temps d'exécution par défaut, qui s'applique à tout job ne précisant pas combien de temps doit lui être alloué. Pour connaître cette limite, utiliser la commande suivante :

sinfo -l

Remarque : tous les arguments de la directive #SBATCH peuvent également être utilisés en arguments des commandes srun, salloc et sbatch. Voir les exemples plus loin.

Quelques directives utiles

Vous trouverez une liste exhaustive sur le site de Slurm : https://slurm.schedmd.com/sbatch.html

Les features

Les nœuds de calculs du Centre de Calcul peuvent présenter des caractéristique différentes. Grâce à l'option --constraint= il est possible de choisir une ou plusieurs features si vous en avez besoin.

Voici une liste non exhaustive des features présentes sur le cluster :

Exemple pour demander des nœuds avx dans un script de soumission :

#SBATCH --constraint=avx

Exemple pour demander des nœuds avx avec des GPU Nvidia Tesla K40 dans un script de soumission :

#SBATCH --constraint="avx&gpuk40"

Exemple pour demandes des nœuds avec des GPU Nvidia Tesla V100 ou des GPU Nvidia RTX 5000 :

#SBATCH --constraint="gpuv100|gpurtx5000"

Suivre l'état d'un job

Il est possible d'obtenir le détail de l'état d'un job, qu'il soit en attente ou en exécution, avec les commandes scontrol ou squeue.

Liste de tous les jobs en cours :

squeue

Liste des jobs en cours d'un compte particulier :

squeue -u <login>

Détail de l'état d'un job :

scontrol show job <jobid>

Mon job est en attente. Quand va-t-il démarrer ?

Pour les jobs en attente, Slurm calcul périodiquement un temps probable de démarrage.

2 possibilités pour l'obtenir:

scontrol show job <jobid> | grep StartTime=
squeue -o "%S" -j <jobid>

Autorisations / Account

Pour utiliser une partition, il faut disposer d'un compte Slurm (indépendant du login Unix). Ce compte Slurm est configuré notamment en fonction du quota d'heures attribué dans le cadre d'un appel à projet, ou de la contribution à une partition mutualisée.

Le compte par défaut pour utiliser la partition public est dérivé du groupe unix primaire.

Sans indication de la partition et du compte dans votre script de soumission, votre job passera sur la partition public avec votre compte par défaut.

Pour utiliser la partition grant, il devra avoir accès à un compte Slurm spécifique (généralement de la forme g20XX), configuré avec un quota d'heures suite à une allocation du comité scientifique :

#SBATCH -p grant
#SBATCH -A g20XX

Si vous avez contribué aux nœuds d'un partition priXXXX, vous aurez accès à un compte spécifique (généralement de la forme qosXX), configuré pour refléter votre quote-part :

#SBATCH -p priXXXX
#SBATCH -A qosXX

Suivre sa consommation

Vous pouvez avoir une indication de votre consommation en heures CPU par la commande

sreport cluster AccountUtilizationByUser  start=2020-01-01 accounts=votre_account -t hours

Notez que votre_account correspond au nom du groupe Unix auquel vous appartenez ou alors au numéro du grant que vous avez obtenu lors d'une demande d'attributions d'heures par le comité scientifique.

Espace disque temporaire

À la soumission d’un job et sur le disque dur de chacun des nœuds qui vous sont alloués, Slurm crée un répertoire temporaire de nom /scratch/job.$SLURM_JOB_ID

Vous pouvez utiliser ce répertoire pour y stocker les fichiers temporaires de vos applications en cours d’exécution. Pensez à les recopier sur votre compte à la fin du script. En effet, le répertoire /scratch/job.$SLURM_JOB_ID est automatiquement effacé en fin de job.

Variables d'environnement

Dans certains cas, votre programme a besoin de connaître plus précisément les ressources que Slurm a mis à sa disposition. Pour cela, Slurm fourni un certain nombre de variables d'environnement, qui sont utilisables dans le script qui appelle le programme. En voici une liste non exhaustive :

Liste détaillée : vor chapitre "OUTPUT ENVIRONMENT VARIABLES" sous https://slurm.schedmd.com/sbatch.html

Priorités

Quand plusieurs jobs sont en même temps en attente dans une file, Slurm calcule une priorité entre ces jobs. Le job ayant la priorité la plus élevée sera le prochain à passer en exécution.

La priorité des jobs peut être vue avec la commande :

sprio -l

La priorité dépend de plusieurs facteurs :

Exemples

ATTENTION : Dans le but d'optimiser les performances et d'éviter les conflits entre plusieurs jobs, Slurm est configuré pour allouer au minimum 1 nœud entier par job CPU et une fraction de nœud GPU (par exemple 1/4 du nœud s'il contient 4 cartes GPU). Concrètement, cela veut dire qu'en demandant 1 seul cœur sur un nœud CPU, Slurm allouera en fait un nœud entier, soit 24 cœurs sur un nœud Intel Skylake par exemple. Et en conséquence 24 heures CPU seront comptabilisées pour chaque heure écoulée. Veuillez bien faire attention à cela pour éviter le gaspillage de ressources d'une part, et pour économiser vos quotas d'heures d'autre part.

Tous les scripts ci-dessous ne sont que des exemples, plusieurs stratégies différentes peuvent aboutir au même résultat, vous pouvez expérimenter de votre côté pour trouver des options qui vous conviennent mieux.

Exemple de script Slurm simple sur la partition public

Ce script demande 64 cœurs répartis sur au minimum sur 2 nœuds et au maximum sur 4 nœuds :

#! /bin/bash

#SBATCH -n 64                # 64 cœurs
#SBATCH -N 2-4               # au minimum 2 nœuds, au maximum 4
#SBATCH -t 12:00:00          # Le job sera tué au bout de 12h
#SBATCH --mem=2048           # Quantité mémoire demandée par nœud en Mo (unité obligatoire)
#SBATCH --mail-type=END      # Réception d'un mail à la fin du job
#SBATCH --mail-user=mon@adresse

./mon_code

Exemples de script Slurm simple sur la partition grant

Ce script demande 128 cœurs répartis sur au minimum sur 4 nœuds et au maximum sur 8 nœuds :

#! /bin/bash

#SBATCH -p grant     
#SBATCH -A g20XX             # voir chapitre "Autorisations / Account" ci-dessus
#SBATCH -n 64                # 64 cœurs
#SBATCH -N 4-8               # au minimum 4 nœuds, au maximum 8
#SBATCH -t 12:00:00          # Le job sera tué au bout de 12h
#SBATCH --mem=2048           # Quantité mémoire demandée par nœud en Mo (unité obligatoire)
#SBATCH --mail-type=END      # Réception d'un mail à la fin du job
#SBATCH --mail-user=mon@adresse

./mon_code

Ce script s'adapte au nombre de cœurs disponibles sur les 2 nœuds demandés. Le code est lancé par mpirun, qui calcule automatiquement le nombre de tâches à lancer :

#! /bin/bash

#SBATCH -p grant
#SBATCH -A g20XX                # voir chapitre "Autorisations / Account" ci-dessus
#SBATCH -N 2 --cpus-per-task=1  # 2 nœuds, 1 cœur par tâche MPI
#SBATCH -t 12:00:00             # Le job sera tué au bout de 12h
#SBATCH --mem=2048              # Quantité mémoire demandée par nœud en Mo (unité obligatoire)
#SBATCH --mail-type=END         # Réception d'un mail à la fin du job
#SBATCH --mail-user=mon@adresse

mpirun ./mon_code

Exemple de demande de ressources

Les commandes srun, salloc, sbatch peuvent prendre les même paramètres que ceux de la directive #SBATCH.

Par exemple, la commande suivante demandera 4 cœurs et lancera 1 fois par cœur la commande hostname

$ srun -n 4 hostname
hpc-n224
hpc-n224
hpc-n224
hpc-n224

Autre exemple en précisant la répartition :

$ srun -n 4 --tasks-per-node=2 hostname
hpc-n224
hpc-n224
hpc-n333
hpc-n333

Exemple avec la commande salloc, qui permet de travailler en interactif dans une réservation. Demandons 32 cœurs :

$ salloc -n 32
salloc: Granted job allocation 472

On pourrait avoir l'impression qu'il ne s'est rien passé, cependant :

Par exemple, la commande srun hostname (lancée dans le shell précédemment obtenu), produira la sortie suivante :

$ srun hostname
hpc-n221
hpc-n221
... (16 fois)
hpc-n333
hpc-n333
... (16 fois)

Exemple de lancement d'un job MPI

Openmpi est couplé nativement avec Slurm. Par défaut, il lancera autant de processus que de cœurs disponibles.

Il est aussi configuré pour que les processus ne se déplacent pas d'un cœur à l'autre.

Voici un exemple de job MPI nécessitant 64 cœurs, sans contrainte particulière sur le nombre de nœuds :

#! /bin/bash

#SBATCH -n 64            # 64 cœurs
#SBATCH -t 12:00:00      # Le job sera tué au bout de 5h
#SBATCH --mail-type=END  # Réception d'un mail à la fin du job
#SBATCH --mail-user=mon@adresse

# Il faut charger un module MPI
module load openmpi/openmpi-4.0.i20

mpirun mon_executable_mpi

Exemple de lancement d'un job OpenMP

Par défaut les threads des jobs OpenMP seront regroupés de manière compacte sur les cœurs d'un même socket.

Exemple de script de soumission pour un job OpenMP qui utilisera un socket complet :

#! /bin/bash

#SBATCH -n 1   # 1 tâche qui sera exécutée sur tous les cœurs d'un socket

./mon_code_omp

Exemple de script de soumission pour un job OpenMP qui utilisera un nœud complet (= 2 sockets) :

#! /bin/bash

#SBATCH -n 1          # 1 tâche qui sera exécutée sur tous les cœurs d'un socket
#SBATCH --exclusive   # Réservation de l'intégralité du nœud, et donc de ses 2 sockets

./mon_code_omp

Exemple de script de soumission pour un job OpenMP qui utilisera très précisément 8 cœurs :

#! /bin/bash

#SBATCH -N 1   # Réservation sur 1 nœud
#SBATCH -n 1   # 1 tâche (option facultative quand on ne lance qu'1 tâche) 
#SBATCH -c 8   # 8 cœurs par tâche

./mon_code_omp

Exemple de lancement d'un job hybride MPI/OpenMP

Pour les applications MPI hybrides (X processus lançant chacun Y threads), il faut réserver X*Y cœurs avec Slurm.

Une stratégie classique de calcul hybride est de lancer 1 processus MPI par nœud et d'utiliser tous les threads de chaque nœud avec OpenMP. Par défaut, Pour un calcul hybride, il faudra préciser le nombre de threads qu'OpenMP pour utiliser. La variable d'environnement SLURM_CPUS_ON_NODE est très utile dans ce cas. Il faudra également préciser qu'on ne veut qu'un processus MPI par job avec l'option Slurm --tasks-per-node=1 ou l'option OpenMPI -npernode 1

Voici 2 scripts d'un job hybride MPI/OpenMP demandant 4 nœuds de calcul et utilisant tous les cœurs :

#! /bin/bash

#SBATCH -N 4                # Réservation sur 4 nœuds
#SBATCH --tasks-per-node=1  # 1 seul processus MPI par nœud
#SBATCH --exclusive         # Réservation de l'intégralité du nœud, et donc de ses 2 sockets

export OMP_NUM_THREADS=$SLURM_CPUS_ON_NODE # Chaque tâche utilisera tous les cœurs disponibles sur son nœud

mpirun ./mon_code_hybride 
#! /bin/bash

#SBATCH -N 4            # Réservation sur 4 nœuds
#SBATCH --exclusive     # Réservation de l'intégralité du nœud, et donc de ses 2 sockets

export OMP_NUM_THREADS=$SLURM_CPUS_ON_NODE # Chaque tâche utilisera tous les cœurs disponibles sur son nœud

mpirun -npernode 1 ./mon_code_hybride

Exemple de script lançant 4 tâches MPI, avec précisément 4 threads par tâches (16 cœurs au total). Le calcul sera réparti sur 2 nœuds :

#!/bin/bash

#SBATCH -N 2                    # Réservation sur 2 nœuds
#SBATCH --tasks-per-node=2      # 2 processus MPI par nœud
#SBATCH -c 4                    # 4 cœurs par tâche

export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK # 1 tâche utilisera le nombre de cœur par tâche alloués par Slurm

mpirun ./mon_code_hybride

Voici le même cas de figure, mais en centralisant tout sur un seul nœud :

#!/bin/bash

#SBATCH -N 1                    # Réservation sur 1 nœuds
#SBATCH --tasks-per-node=4      # 4 processus MPI par nœud
#SBATCH -c 4                    # 4 cœurs par tâche

export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK # 1 tâche utilisera le nombre de cœur par tâche alloués par Slurm

mpirun ./mon_code_hybride

Exemple de lancement d'un job utilisant des GPU

Pour obtenir un gpu, il suffit d'indiquer l'option : --gres=gpu:, avec le nombre de GPU par nœuds (4 au maximum) et de se placer dans une partition GPU (publicgpu, grantgpu ou une partition pri* possédant des GPU.

On pourra, si nécessaire, se servir de la variable d'environnement CUDA_VISIBLE_DEVICES pour déterminer, à l'intérieur d'une tâche, le numéro de la carte affectée à la tâche (de 0 à 3, suivant le nombre de GPU par nœud demander).

Certains programmes utilises des nombres double précision. Il faut donc choisir des GPU optimisés pour l'utilisation de ces nombres avec l'option --constraint=gpudp, sinon les performances vont être mauvaise.

Si votre code utilise des tensor cores (notamment pour des calculs en Deep Learning), il faut demander des GPU compatibles avec l'option --contraint=gpudl.

Voici un exmple de script GPU demandant un nœud complet avec 4 GPU optimisés pour de la double précision :

#! /bin/bash

#SBATCH -p publicgpu          # Partition public avec des GPU
#SBATCH -N 1                  # 1 nœud
#SBATCH --exclusive           # Le nœud sera entièrement dédié à notre job, pas de partage de ressources
#SBATCH -t 05:00:00           # Le job sera tué au bout de 5h
#SBATCH --gres=gpu:4          # 4 GPU par nœud
#SBATCH --constraint=gpudp    # Nœuds GPU double précision
#SBATCH --mail-type=END       # Réception d'un mail à la fin du job
#SBATCH --mail-user=mon@adresse

./mon_code_gpu

Exemple de lancement d'une série de tâches séquentielles (ou d'applications multithread sur peu de cœurs) sur plusieurs nœuds

Pour ce genre de soumission, le Centre de Calcul a mis au point un outil basé sur gnu parallel et sur le système de SLURM array. Il faut commencer par mettre toutes les commandes à lancer dans un fichier.

Chaque ligne du fichier doit contenir une commande qui sera exécutée par un cœur. Ensuite, il faudra utiliser un script de soumission qui se chargera pour vous de répartir au mieux tous les calculs sur les ressources du Centre de Calcul. Voici un exemple de script de soumission, que l'on nommera mon_script.slurm :

#! /bin/bash
#SBATCH -N 1 --exclusive

commandes=jobfile # Fichier contenant l'ensemble des commandes a lancer, 1 par ligne

hpc_multilauncher $commandes

Il faut ensuite soumettre avec la commande suivante :

sbatch --array=1-Nb_sous_jobs mon_script.slurm 

Cela va générer Nb_sous_jobs sous-jobs, qui vont tous entrer en file d'attente sans avoir à tout gérer manuellement.

Il faut ajuster Nb_sous_jobs en fonction du temps total nécessaire pour l'ensemble des commandes se trouvant dans le fichier jobfile. Par exemple, prenons un programme qui nécessite 2 heures sur 1 cœurs CPU. Vous souhaitez lancer 10000 simulations sur la file public (limitée à 24 heures max). Slurm vous attribuera des nœuds à 16 cœurs minimum, il faudra 10000*2/16/24 = 52 sous-jobs. On arrondi à 60 pour tenir compte de la marge d'erreur sur l'estimation du temps nécessaire, ce qui donne :

sbatch --array=1-60 mon_script.slurm

S'il y a trop de sous-jobs, ils tourneront à vide et s'arrêteront instantanément.

Pour une application multithread sur un faible nombre de cœurs, il faut ajouter le nombre de threads par commande en argument de hpc_multilauncher. Voici un exemple pour une application sur 2 threads :

#! /bin/bash
#SBATCH -N 1 --exclusive

commandes=jobfile # Fichier contenant l'ensemble des commandes a lancer, 1 par ligne
Nthreads=2

hpc_multilauncher $commandes $Nthreads

N.B. : cet outil va générer plusieurs fichiers nécessaires au bon déroulement des opérations. Il ne faut surtout pas les supprimer ou les altérer tant que tous les calculs ne sont pas terminés. Ils seront automatiquement effacés à la fin.


VERSIONS ET SCRIPTS D'INSTALLATION


TAGS