Contrôle de l'ordonnancement avec MPI

From Alliance Doc
Jump to navigation Jump to search
This site replaces the former Compute Canada documentation site, and is now being managed by the Digital Research Alliance of Canada.

Ce site remplace l'ancien site de documentation de Calcul Canada et est maintenant géré par l'Alliance de recherche numérique du Canada.

This page is a translated version of the page Advanced MPI scheduling and the translation is 100% complete.
Other languages:

La plupart du temps, vous devriez soumettre les tâches MPI parallèles à mémoire distribuée selon l'exemple présenté à section Tâche MPI de la page Exécuter des tâches. Il suffit d'utiliser - ntasks ou -n pour spécifier le nombre de processus et de laisser l'ordonnanceur faire la meilleure allocation, compte tenu de l'efficacité de la grappe.

Si par contre vous voulez plus de contrôle sur l'allocation, prenez connaissance de la page Support for Multi-core/Multi-thread Architectures de SchedMD; on y décrit comment plusieurs options de la commande sbatch agissent sur l'ordonnancement des processus.

Dans la foire aux questions Slurm, la réponse à What exactly is considered a CPU? peut aussi s'avérer utile.

Exemples de scénarios

Peu de cœurs, nœuds indéterminés

En plus de spécifier la durée de toute tâche Slurm, il faut aussi indiquer le nombre de processus MPI que Slurm doit démarrer. Le moyen le plus simple de ce faire est d'utiliser --ntasks. Puisque l'allocation par défaut de 256Mo de mémoire est souvent insuffisante, vous devriez aussi spécifier la quantité de mémoire nécessaire. Avec --ntasks, il est impossible de savoir combien de cœurs seront sur chaque nœud; vous voudrez alors utiliser --mem-per-cpu ainsi


File : basic_mpi_job.sh

#!/bin/bash 
#SBATCH --ntasks=15
#SBATCH --mem-per-cpu=3G
srun application.exe


Nous avons ici 15 processus MPI. L'allocation des cœurs pourrait se faire sur 1 nœud, sur 15 nœuds, ou sur tout nombre de nœuds entre 1 et 15.

Nœuds entiers

Pour une tâche parallèle intensive qui peut utiliser efficacement 32 cœurs ou plus, vous devriez probablement demander des nœuds entiers; il est donc utile de savoir quels types de nœuds sont disponibles sur la grappe que vous utilisez.

La plupart des nœuds de Béluga, Cedar, Graham, Narval et Niagara sont configurés comme suit ː

grappe cœurs mémoire utilisable notes
Béluga 40 186 GiB (~4.6 GiB/core) Certains sont réservés pour les tâches sur nœuds entiers.
Graham 32 125 GiB (~3.9 GiB/cœur) Certains sont réservés pour les tâches sur nœuds entiers.
Cedar (Skylake) 48 187 GiB (~3.9 GiB/cœur) Certains sont réservés pour les tâches sur nœuds entiers.
Narval 64 249 GiB (~3.9 GiB/cœur) processeurs AMD EPYC Rome
Niagara 40 188 GiB Cette grappe n'accepte que les tâches sur nœuds entiers.

Les tâches sur nœuds entiers peuvent être exécutées sur tous les nœuds. Dans le tableau ci-dessus, la note « Certains sont réservés pour les tâches sur nœuds entiers » signifie que les tâches par cœur sont interdites sur certains nœuds.

Voici un exemple d'un script demandant des nœuds entiers.

File : whole_nodes_beluga.sh

#!/bin/bash 
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=40
#SBATCH --mem=0
srun application.exe
File : whole_nodes_cedar.sh

#!/bin/bash 
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=48
#SBATCH --mem=0
srun application.exe
File : whole_nodes_graham.sh

#!/bin/bash 
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=32
#SBATCH --mem=0
srun application.exe
File : whole_nodes_narval.sh

#!/bin/bash 
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=64
#SBATCH --mem=0
srun application.exe
File : whole_nodes_niagara.sh

#!/bin/bash 
#SBATCH --nodes=2
#SBATCH --ntasks-per-node=40  # ou 80 (activation du Hyper-Threading)
#SBATCH --mem=0
srun application.exe

Le fait de demander --mem=0 indique à Slurm qu'il doit réserver toute la mémoire disponible de chacun des nœuds assignés à la tâche.

Toutefois, si vous avez besoin de plus de mémoire par nœud que ce que le plus petit nœud peut offrir (par exemple plus de 125Gio sur Graham), vous ne devriez pas utiliser --mem=0, mais demander une quantité explicite de mémoire. De plus, une partie de la mémoire de chaque nœud est réservée au système d'exploitation; dans la section Caractéristiques des nœuds, la colonne Mémoire disponible indique la plus grande quantité de mémoire qu'une tâche peut demander ː

Peu de cœurs, nœud unique

Si vous avez besoin de moins qu'un nœud entier, mais que tous les cœurs doivent être du même nœud, vous pouvez demander par exemple

File : less_than_whole_node.sh

#!/bin/bash 
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=15
#SBATCH --mem=45G
srun application.exe


Vous pourriez aussi utiliser --mem-per-cpu=3G, mais la tâche serait annulée si un des processus dépasse 3Go. L'avantage avec --mem=45G est que la mémoire consommée par chaque processus n'importe pas, pourvu que dans l'ensemble ils ne dépassent pas 45Go.

Tâche intensive en parallèle, sans multiples de nœuds entiers

Ce ne sont pas toutes les tâches qui sont effectuées de façon optimale sur des cœurs en multiples de 32, 40 ou 48. Le fait d'indiquer ou non un nombre précis de cœurs peut influer sur le temps d'exécution (ou la bonne utilisation de la ressource) ou le temps d'attente (ou la bonne utilisation du temps qui vous est imparti). Pour de l'aide sur comment évaluer ces facteurs, communiquez avec le soutien technique.

Tâches hybrides : MPI avec OpenMP ou MPI avec fils

Il est important de bien comprendre que le nombre de tâches Slurm demandées représente le nombre de processus qui seront démarrés avec srun. Dans le cas d'une tâche hybride qui utilise à la fois des processus MPI et des fils OpenMP ou Posix, vous voudrez indiquer le nombre de processus MPI avec --ntasks ou -ntasks-per-node et ;le nombre de fils avec --cpus-per-task.

--ntasks=16
--cpus-per-task=4
--mem-per-cpu=3G
 srun --cpus-per-task=$SLURM_CPUS_PER_TASK application.exe

Ici, 64 cœurs sont alloués, mais seulement 16 processus (tâches) MPI sont et seront initialisés. S'il s'agit en plus d'une application OpenMP, chacun des processus démarrera 4 fils, soit un par cœur. Chaque processus pourra utiliser 12Go. Avec 4 cœurs, les tâches pourraient être allouées sur 2 à 16 nœuds, peu importe lesquels. Vous devez aussi spécifier --cpus-per-task=$SLURM_CPUS_PER_TASK pour srun, puisque c'est exigé depuis Slurm 22.05 et ne nuit pas aux versions les moins récentes.

--nodes=2
--ntasks-per-node=8
--cpus-per-task=4
--mem=96G
 srun --cpus-per-task=$SLURM_CPUS_PER_TASK application.exe

La taille de cette tâche est identique à celle de la précédente, c'est-à-dire 16 tâches (soit 16 processus MPI) avec chacune 4 fils. La différence ici est que nous obtiendrons exactement 2 nœuds entiers. N'oubliez pas que --mem précise la quantité de mémoire par nœud et que nous l'utilisons de préférence à --mem-per-cpu pour la raison donnée plus haut.

Pourquoi srun plutôt que mpiexec ou mpirun?

mpirun permet la communication entre processus exécutés sur des ordinateurs différents; les ordonnanceurs récents possèdent cette même fonctionnalité. Avec Torque/Moab, il n'est pas nécessaire de fournir à mpirun la liste des nœuds ou le nombre de processus puisque l'ordonnanceur s'en charge. Avec Slurm, c'est l'ordonnanceur qui décide de l'affinité des tâches, ce qui évite d'avoir à préciser des paramètres comme

mpirun --map-by node:pe=4 -n 16  application.exe

Dans les exemples précédents, on comprend que srun application.exe distribue automatiquement les processus aux ressources précises allouées à la tâche.

En termes de niveaux d'abstraction, srun est au-dessus de mpirun; srun peut faire tout ce que fait mpirun et davantage. Avec Slurm, srun est l'outil de prédilection pour lancer tous les types de calcul; il est aussi plus polyvalent que le pbsdsh de Torque. On pourrait dire de srun que c'est l'outil Slurm universel pour la distribution des tâches en parallèle  une fois les ressources allouées, la nature de l'application importe peu, qu'il s'agisse de MPI, OpenMP, hybride, distribution sérielle, pipeline, multiprogramme ou autre.

Bien entendu, srun est parfaitement adapté à Slurm : il amorce la première étape de la tâche, initialise correctement les variables d'environnement SLURM_STEP_ID et SLURM_PROCID et fournit les renseignements de suivi appropriés.

Pour des exemples de quelques différences entre srun et mpiexec, voyez le forum OpenMPI. Dans certains cas, mpiexec offrira une meilleure performance que srun, mais srun diminue le risque de conflit entre les ressources allouées par Slurm et celles utilisées par OpenMPI.

Références

Categorie:SLURM