Exemple de Batch : Job Steps et Tasks

Les Jobs Steps permettent de découper un Job en plusieurs sections logiques. Ils sont créés en préfixant une commande (script/programme) avec la commande Slurm "srun" et peuvent s'exécuter séquentiellement et/ou parallèlement. Par exemple, un batch peut être constitué de 3 étapes successives, chacune étant divisée en 2 parties exécutées en parallèle.

Pour cela, Slurm utilise une "unité d'allocation" : la Task. Une Task est un processus disposant de "cpus-per-task" CPUs.

Un Step ("srun") utilise une ou plusieurs Task(s) (option "-n"), exécutées sur un ou plusieurs Node(s) (option "-N"). Si omises ces options utilisent, par défaut, la totalité de l'allocation du Job.

Les ressources d'un Job sont alors exprimées en "cpus-per-task" et "ntasks" (nombre de Tasks) pour une allocation CPU totale du Job de : cpus-per-task * ntasks.

Description du Job :

Dans cet exemple, le Job encode une vidéo en deux étapes successives : une première étape de préparation (par exemple, copie de fichiers, découpage de la vidéo, 1ère passe d'encodage...), et une seconde étape qui effectue deux encodages (en H264 et VP9) exécutées en parallèles. Les ressources à réserver pour ce Job sont donc 2 Tasks de 4 CPUs chacune.

Contenu du Batch :

# Options SBATCH :

#SBATCH --job-name=Encode-Steps # Nom du Job
#SBATCH --cpus-per-task=4       # Allocation de 4 CPUs par Task
#SBATCH --ntasks=2              # Nombre de Tasks : 2
#SBATCH --mail-type=END         # Notification par email de la
#SBATCH --mail-user=bob@irit.fr # fin de l'exécution du job.

# Traitement

module purge              # delete all loaded module environments
module load ffmpeg/0.6.5  # load ffmpeg module version 0.6.5

# 1ère étape : Step de 2 Tasks (ressources globales du Job)

srun prep.sh

# 2eme étape : 2 Steps en parallèle (une Task par Step)

srun -n1 -N1 ffmpeg -i video.avi -threads $SLURM_CPUS_PER_TASK -c:v libx264 [...] -f mp4 video-h264.mp4 &

srun -n1 -N1 ffmpeg -i video.mp4 -threads $SLURM_CPUS_PER_TASK -c:v libvpx-vp9 [...] -f webm video-vp9.webm &

# Attendre la fin des Steps "enfants" (exécutés en arrière plan)

wait

# 3eme étape : finalisation (2 Tasks)

srun finish.sh

Remarques :

  • Les CPUs non utilisés par une Task seront "perdus", non-utilisables par aucune autre Task ou Step. Si la Task crée plus de processus/threads que de CPUs alloués, ces threads se partageront les CPUs. (cf. Processus...)

Un des intérêts d'utiliser des Steps pour des tâches itératives (non éxécutées en parallèle) est leur prise en charge dans les fonctions de gestion de Jobs (sstat, sacct) permettant à la fois un suivi de l'avancement Step-by-Step du Job pendant l'exécution (Steps terminés, en cours, leur durée...), et des statistiques détaillées d'utilisation des ressources (CPU, RAM, disque, réseau...) pour chaque Step (après exécution).

  • Lorsque des Steps sont exécutés en parallèle, il est impératif dans le script parent (Job), d'attendre la fin de l'exécution des processus enfants avec un "wait\", faute de quoi ces derniers seront automatiquement interrompus (killed) une fois la fin du Batch atteinte.

  • La parallélisation des Steps est réalisée par le SHELL ('&' en fin de ligne), qui exécute la commande "srun" dans un sous-processus (sub-shell) du Job.

  • Une Task ne peut être exécutée/distribuée sur plusieurs nœuds ; le nombre de Tasks doit donc toujours être supérieur ou égal au nombre de nœuds (dans le Batch comme dans un Step).

Structures Shell (Bash) de création de Steps en fonction de la source des données :

# Boucle sur les éléments d\'un tableau (ici des fichiers) :
files=('file1' 'file2' 'file3' ...)

for f in "${files[@]}"; do
    # Adaptez "-n1" et "-N1" en fonction de vos besoins
    srun -n1 -N1 <command> [...] "$f" &
done

# Boucle sur les fichiers d'un répertoire :
while read f; do
    # Adaptez "-n1" et "-N1" en fonction de vos besoins
    srun -n1 -N1 <command> [...] "$f" &
done < <(ls "/path/to/files/")

# Utilisez "ls -R" ou "find" pour un parcours récursif des dossiers

# Lecture ligne par ligne d'un fichier :
while read line; do
    # Adaptez "-n1" et "-N1" en fonction de vos besoins
    srun -n1 -N1 <command> [...] "$line" &
done <"/path/to/file"