Table des matières
Jean Zay : Collection de travaux similaires (Job Array)
Principe
Les Jobs Arrays offrent la possibilité à un utilisateur de soumettre en une seule fois une collection de travaux similaires.
Attention : à l'IDRIS, les Jobs Arrays ne sont admis que pour des travaux soumis via la commande sbatch
car ils peuvent générer un très grand nombre de travaux.
Ils se distinguent par l'utilisation de la directive SLURM #SBATCH --array
permettant de spécifier les indices, ou un rang d'indices, pour les travaux de la collection comme indiqué ci-dessous :
- Pour une collection de travaux dont les indices vont successivement de 0 à NB_JOBS (i.e. 0, 1, 2, … , NB_JOBS) :
#SBATCH --array=0-NB_JOBS
- Pour une collection de travaux dont les indices varient de 0 à, au plus, NB_JOBS par pas de STEP_SIZE (i.e. 0, STEP_SIZE, 2*STEP_SIZE, etc…) :
#SBATCH --array=0-NB_JOBS:STEP_SIZE
- Pour une collection de N travaux ayant les indices prédéfinis J_1, J_2, … , J_N :
#SBATCH --array=J_1,J_2,...,J_N
Remarques :
- Le nombre maximal de jobs admis dans la queue Slurm est de 10 000 jobs par utilisateur.
- Le nombre maximal de travaux qui peuvent être exécutés simultanément à partir d'un Job Array peut être spécifié à l'aide du séparateur
%
. La commande suivante permet d'exécuter tous les travaux d'une collection par lot deNB_MAX_RUNNING_JOBS
travaux :#SBATCH --array=0-NB_JOBS%NB_MAX_RUNNING_JOBS
Variables propres aux Job Arrays
Lors de l'utilisation des Job Arrays, certaines variables d'environnement SLURM peuvent être utilisées dans le script shell afin de personnaliser les divers travaux d'une même collection. Par exemple, pour que chaque travail de la collection utilise des répertoires d'entrées et/ou de sorties différents. Les variables d’environnement suivantes sont ainsi automatiquement valorisées par SLURM :
SLURM_JOB_ID
: l'identifiant du jobSLURM_ARRAY_JOB_ID
: aussi l'identifiant du jobSLURM_ARRAY_TASK_ID
: l'indice propre à chaque travail de la collection (peut être vue comme un compteur des travaux)SLURM_ARRAY_TASK_COUNT
: le nombre total de travaux de la collection qui seront exécutés.SLURM_ARRAY_TASK_MIN
: le plus petit indice de tous les travaux de la collectionSLURM_ARRAY_TASK_MAX
: le plus grand indice de tous les travaux de la collection
De plus, avec les Job Arrays, deux options supplémentaires sont disponibles pour spécifier les noms des fichiers d'entrée et de sortie de chaque travail dans les directives #SBATCH --output=...
et #SBATCH --error=...
:
%A
qui est automatiquement substituée par la valeur deSLURM_ARRAY_JOB_ID
%a
qui est automatiquement substituée par la valeur deSLURM_ARRAY_TASK_ID
.
Remarques :
- Par défaut, le format du nom de fichier de sortie pour un Job Array est
slurm-%A_%a.out
.
- En Bash, les variables propres aux Job Arrays peuvent être récupérées de la manière suivante :
echo ${SLURM_JOB_ID} echo ${SLURM_ARRAY_JOB_ID} echo ${SLURM_ARRAY_TASK_ID} echo ${SLURM_ARRAY_TASK_COUNT} echo ${SLURM_ARRAY_TASK_MIN} echo ${SLURM_ARRAY_TASK_MAX}
- Pour les scripts Python, les variables propres aux Job Arrays peuvent être récupérées de la manière suivante :
import os slurm_job_id=int(os.environ["SLURM_JOB_ID"]) slurm_array_job_id=int(os.environ["SLURM_ARRAY_JOB_ID"]) slurm_array_task_id=int(os.environ["SLURM_ARRAY_TASK_ID"]) slurm_array_task_count=int(os.environ["SLURM_ARRAY_TASK_COUNT"]) slurm_array_task_min=int(os.environ["SLURM_ARRAY_TASK_MIN"]) slurm_array_task_max=int(os.environ["SLURM_ARRAY_TASK_MAX"])
Exemples d’utilisation
- Remarque préliminaire : les exemples ci-dessous concernent des exécutions sur la partition CPU. Le principe reste le même pour des exécutions sur les partitions GPU.
- Exemple de script de soumission pour 20 travaux identiques avec un maximum de 5 travaux placés dans la file (exécution par séries de 5 travaux) :
- job_array_20.slurm
#!/bin/bash #SBATCH --job-name=job-array # nom du job #SBATCH --ntasks=1 # Nombre total de processus MPI #SBATCH --ntasks-per-node=1 # Nombre de processus MPI par noeud # Dans le vocabulaire Slurm "multithread" fait référence à l'hyperthreading. #SBATCH --hint=nomultithread # 1 processus MPI par coeur physique (pas d'hyperthreading) #SBATCH --time=00:01:00 # Temps d’exécution maximum demande (HH:MM:SS) #SBATCH --output=%x_%A_%a.out # Nom du fichier de sortie contenant l'ID et l'indice #SBATCH --error=%x_%A_%a.out # Nom du fichier d'erreur (ici commun avec la sortie) #SBATCH --array=0-19%5 # 20 travaux en tout mais 5 travaux max dans la file # on se place dans le répertoire de soumission cd ${SLURM_SUBMIT_DIR} # nettoyage des modules charges en interactif et herites par defaut module purge # chargement des modules module load ... # echo des commandes lancées set -x # Execution du binaire "mon_exe" avec des donnees differentes pour chaque travail # La valeur de ${SLURM_ARRAY_TASK_ID} est differente pour chaque travail. srun ./mon_exe < fichier${SLURM_ARRAY_TASK_ID}.in > fichier${SLURM_ARRAY_TASK_ID}.out
- Exemple de script de soumission pour 3 travaux identiques, ayant respectivement les indices 1, 3 et 8 :
- job_array_3.slurm
#!/bin/bash #SBATCH --job-name=job-array # nom du job #SBATCH --ntasks=1 # Nombre total de processus MPI #SBATCH --ntasks-per-node=1 # Nombre de processus MPI par noeud # Dans le vocabulaire Slurm "multithread" fait référence à l'hyperthreading. #SBATCH --hint=nomultithread # 1 processus MPI par coeur physique (pas d'hyperthreading) #SBATCH --time=00:01:00 # Temps d’exécution maximum demande (HH:MM:SS) #SBATCH --output=%x_%A_%a.out # Nom du fichier de sortie contenant l'ID et l'indice #SBATCH --error=%x_%A_%a.out # Nom du fichier d'erreur (ici commun avec la sortie) #SBATCH --array=1,3,8 # 3 travaux en tout ayant les indices 1, 3 et 8 # on se place dans le répertoire de soumission cd ${SLURM_SUBMIT_DIR} # nettoyage des modules charges en interactif et herites par defaut module purge # chargement des modules module load ... # echo des commandes lancées set -x # Execution du binaire "mon_exe" avec des donnees differentes pour chaque travail # La valeur de ${SLURM_ARRAY_TASK_ID} est differente pour chaque travail. srun ./mon_exe < fichier${SLURM_ARRAY_TASK_ID}.in > fichier${SLURM_ARRAY_TASK_ID}.out
- Exemple de script de soumission pour 6 travaux identiques, ayant des indices compris entre 0 et 11 par pas de 2 :
- job_array_0-11.slurm
#!/bin/bash #SBATCH --job-name=job-array # nom du job #SBATCH --ntasks=1 # Nombre total de processus MPI #SBATCH --ntasks-per-node=1 # Nombre de processus MPI par noeud # Dans le vocabulaire Slurm "multithread" fait référence à l'hyperthreading. #SBATCH --hint=nomultithread # 1 processus MPI par coeur physique (pas d'hyperthreading) #SBATCH --time=00:01:00 # Temps d’exécution maximum demande (HH:MM:SS) #SBATCH --output=%x_%A_%a.out # Nom du fichier de sortie contenant l'ID et l'indice #SBATCH --error=%x_%A_%a.out # Nom du fichier d'erreur (ici commun avec la sortie) #SBATCH --array=0-11:2 # 6 travaux ayant les indices 0, 2, 4, 6, 8, et 10 # on se place dans le répertoire de soumission cd ${SLURM_SUBMIT_DIR} # nettoyage des modules charges en interactif et herites par defaut module purge # chargement des modules module load ... # echo des commandes lancées set -x # Execution du binaire "mon_exe" avec des donnees differentes pour chaque travail # La valeur de ${SLURM_ARRAY_TASK_ID} est differente pour chaque travail. srun ./mon_exe < fichier${SLURM_ARRAY_TASK_ID}.in > fichier${SLURM_ARRAY_TASK_ID}.out
Commande de contrôle des travaux
Un travail de type Job Array doit être exécuté via la commande sbatch
en raison du grand nombre de travaux qu'il peut générer :
$ sbatch job_array.slurm
Le suivi de ces jobs s'effectue avec la commande squeue
qui retourne alors une information adaptée. Par exemple, pour un Job Array comportant 7 travaux exécutés par séries de 2 travaux sur la partition cpu_p1
:
- Le premier appel à
squeue
retourne :$ squeue -J 305813 JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 305813_[2-6%2] cpu_p1 job-array mylogin PD 0:00 1 (JobArrayTaskLimit) 305813_0 cpu_p1 job-array mylogin R 0:00 1 r7i1n0 305813_1 cpu_p1 job-array mylogin R 0:00 1 r8i6n3
Ici, on constate que les 2 premiers travaux sont en cours d'exécution et les 5 autres en attente.
- Lorsque les 2 premiers travaux sont finis, un second appel à
squeue
retourne :$ squeue -J 305813 JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) 305813_[4-6%2] cpu_p1 job-array mylogin PD 0:00 1 (JobArrayTaskLimit) 305813_2 cpu_p1 job-array mylogin R 0:05 1 r7i1n0 305813_3 cpu_p1 job-array mylogin R 0:05 1 r8i6n3
Maintenant, on constate que ce sont les 2 travaux suivants qui s'exécutent et qu'il n'en reste plus que 3 en attente. Notez qu'il n'y a plus aucune trace des 2 premiers travaux terminés.
Pour supprimer un Job Array, vous devez utiliser la commande scancel
. Mais il y a alors plusieurs façons de procéder :
- Pour annuler l'ensemble de la collection, indiquez son identifiant
${SLURM_JOB_ID}
. Avec l'exemple ci-dessus, cela donne :$ scancel 305813
- Pour annuler l'exécution d'un travail en particulier, indiquez l'identifiant de la collection
${SLURM_ARRAY_JOB_ID}
et l'indice du travail${SLURM_ARRAY_TASK_ID}
. Avec l'exemple ci-dessus, cela donne :$ scancel 305813_2
- Pour annuler l'exécution d'une série de travaux, indiquez l'identifiant de la collection
${SLURM_ARRAY_JOB_ID}
et un intervalle d'indices (ici de 4 à 6). Avec l'exemple ci-dessus, cela donne :$ scancel 305813_[4-6]