Compilateurs et MPI
eXplor-v2 met à disposition des compilateurs et des implémentations MPI via les modules d'environnement. Cette page explique comment choisir un environnement cohérent, compiler un programme C, C++ ou Fortran, puis l'exécuter avec Slurm.
Utilisez le même environnement de compilateur et de MPI pour compiler et exécuter un programme parallèle. Mélanger des bibliothèques ou des implémentations MPI incompatibles est une cause fréquente d'échecs à l'exécution.
Concepts essentiels
| Terme | Signification |
|---|---|
| Compilateur | Outil qui transforme un code source en exécutable, par exemple C, C++ ou Fortran |
| MPI | Interface de passage de messages pour les programmes parallèles distribués |
| Wrapper MPI | Commande de compilation qui appelle le compilateur avec les options MPI nécessaires |
| Tâche Slurm | Processus attribué et lancé par Slurm |
| CPU par tâche | Nombre de CPU attribués à chaque processus Slurm |
| OpenMP | Modèle de parallélisme par threads, souvent utilisé à l'intérieur d'un processus |
Les wrappers MPI courants sont :
| Langage | Wrapper MPI courant |
|---|---|
| C | mpicc |
| C++ | mpicxx ou mpic++ |
| Fortran | mpifort |
Les noms exacts dépendent de l'implémentation MPI chargée.
Préparer un environnement cohérent
Commencez par rechercher les modules disponibles :
module spider gcc
module spider mpi
Puis construisez un environnement propre :
module purge
module load nom_compilateur
module load nom_mpi
module list
Vérifiez les outils réellement utilisés :
which gcc
which mpicc
which mpifort
mpicc --version
mpifort --version
Pour connaître le compilateur sous-jacent utilisé par un wrapper MPI :
mpicc -show
mpicxx -show
mpifort -show
Selon l'implémentation MPI, l'option peut être --showme :
mpicc --showme
Les exemples utilisent nom_compilateur et nom_mpi. Utilisez toujours les noms et versions exacts retournés par module avail ou module spider.
Compiler un programme séquentiel
Programme C
Fichier bonjour.c :
#include <stdio.h>
int main(void) {
printf("Bonjour depuis eXplor-v2.\n");
return 0;
}
Compilation :
gcc -O3 -Wall -Wextra -o bonjour bonjour.c
Exécution :
./bonjour
Programme C++
g++ -O3 -Wall -Wextra -std=c++17 -o mon-programme mon-programme.cpp
Programme Fortran
gfortran -O3 -Wall -o mon-programme mon-programme.f90
Les options d'optimisation doivent être adaptées au compilateur et au programme. Commencez avec des options simples et validez les résultats avant d'utiliser des optimisations agressives.
Compiler un programme MPI
Les wrappers MPI ajoutent les chemins d'en-têtes et de bibliothèques nécessaires. Préférez-les aux appels directs au compilateur lorsque votre programme utilise MPI.
Programme MPI en C
Fichier bonjour-mpi.c :
#include <mpi.h>
#include <stdio.h>
int main(int argc, char **argv) {
int rank;
int size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
printf("Bonjour depuis le rang %d sur %d.\n", rank, size);
MPI_Finalize();
return 0;
}
Compilation :
mpicc -O3 -Wall -Wextra -o bonjour-mpi bonjour-mpi.c
Programme MPI en C++
mpicxx -O3 -std=c++17 -o mon-programme-mpi mon-programme-mpi.cpp
Programme MPI en Fortran
mpifort -O3 -o mon-programme-mpi mon-programme-mpi.f90
Exécuter MPI avec Slurm
Dans une allocation Slurm, utilisez srun pour lancer les processus MPI. Slurm peut ainsi attribuer, contrôler et suivre correctement les tâches.
Exemple en session interactive :
salloc \
--partition=std \
--ntasks=4 \
--cpus-per-task=1 \
--mem=4G \
--time=00:15:00
srun ./bonjour-mpi
Exemple de script batch :
#!/bin/bash
#SBATCH --job-name=bonjour-mpi
#SBATCH --partition=std
#SBATCH --ntasks=4
#SBATCH --cpus-per-task=1
#SBATCH --mem=4G
#SBATCH --time=00:15:00
#SBATCH --output=logs/%x-%j.out
#SBATCH --error=logs/%x-%j.err
set -euo pipefail
mkdir -p logs
module purge
module load nom_compilateur
module load nom_mpi
module list
srun ./bonjour-mpi
srunDans un job Slurm, préférez srun à mpirun ou mpiexec, sauf si la documentation spécifique de votre application ou la configuration du centre impose une autre méthode.
Parallélisme MPI, OpenMP et hybride
MPI
MPI utilise plusieurs processus, souvent un par tâche Slurm :
#SBATCH --ntasks=8
#SBATCH --cpus-per-task=1
srun ./mon-programme-mpi
OpenMP
OpenMP utilise plusieurs threads dans un seul processus :
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8
export OMP_NUM_THREADS="$SLURM_CPUS_PER_TASK"
srun ./mon-programme-openmp
Compilez un programme OpenMP avec l'option adaptée au compilateur. Avec GCC, par exemple :
gcc -O3 -fopenmp -o mon-programme-openmp mon-programme-openmp.c
MPI + OpenMP
Un programme hybride utilise plusieurs processus MPI, chacun avec plusieurs threads :
#SBATCH --ntasks=4
#SBATCH --cpus-per-task=2
export OMP_NUM_THREADS="$SLURM_CPUS_PER_TASK"
srun ./mon-programme-hybride
Dans cet exemple, le job réserve huit CPU au total : quatre tâches MPI avec deux CPU par tâche.
Bibliothèques et compilation
Lorsqu'une bibliothèque est fournie par module, chargez son module avant la compilation et l'exécution :
module purge
module load nom_compilateur
module load nom_mpi
module load nom_bibliotheque
Utilisez les options recommandées par le module ou l'outil fourni. pkg-config peut aider à obtenir des options de compilation pour certaines bibliothèques :
pkg-config --cflags nom_bibliotheque
pkg-config --libs nom_bibliotheque
Exemple générique :
gcc -O3 \
$(pkg-config --cflags nom_bibliotheque) \
-o mon-programme mon-programme.c \
$(pkg-config --libs nom_bibliotheque)
Optimisation et débogage
Commencez par vérifier que le programme produit des résultats corrects avant de chercher à l'optimiser.
Options courantes avec GCC :
| Objectif | Options indicatives |
|---|---|
| Avertissements | -Wall -Wextra |
| Débogage | -g -O0 |
| Optimisation générale | -O2 ou -O3 |
| OpenMP | -fopenmp |
| Standard C++ récent | -std=c++17 |
Certaines optimisations peuvent modifier le comportement numérique, notamment avec les calculs en virgule flottante. Comparez toujours les résultats avec une référence ou un jeu de tests connu.
Pour un débogage MPI, commencez avec peu de tâches :
srun --ntasks=2 ./bonjour-mpi
Vérifier l'environnement d'exécution
Avant de lancer une campagne importante, enregistrez les informations de compilation et d'exécution :
module list 2>&1
which mpicc
mpicc -show
which srun
srun --version
Pour identifier les bibliothèques dynamiques d'un exécutable :
ldd ./mon-programme-mpi
Exécutez ldd uniquement sur un exécutable de confiance.
Erreurs fréquentes
mpi.h: No such file or directory
Le module MPI n'est probablement pas chargé ou vous utilisez le compilateur direct au lieu de mpicc.
module list
which mpicc
Commande mpicc introuvable
Recherchez et chargez l'implémentation MPI correspondante :
module spider mpi
module load nom_mpi
Erreur de bibliothèque MPI à l'exécution
Le programme peut avoir été compilé avec une implémentation MPI différente de celle chargée à l'exécution. Rechargez le même compilateur et le même MPI, ou recompilez le programme dans l'environnement courant.
Nombre de processus inattendu
Vérifiez les ressources demandées et la commande :
scontrol show job "$SLURM_JOB_ID"
srun --ntasks="$SLURM_NTASKS" ./mon-programme-mpi
Performances faibles
Vérifiez :
- si le programme utilise réellement plusieurs tâches ou threads ;
- le nombre de CPU demandé ;
- la répartition MPI et OpenMP ;
- les accès aux fichiers ;
- la taille du problème ;
- le temps consacré aux communications MPI.
Augmentez progressivement les ressources et comparez les temps d'exécution plutôt que de supposer qu'un plus grand nombre de CPU sera toujours plus rapide.
Bonnes pratiques
- Commencez par
module purge. - Chargez explicitement le compilateur, MPI et les bibliothèques.
- Compilez et exécutez avec le même environnement logiciel.
- Utilisez les wrappers
mpicc,mpicxxetmpifortpour les programmes MPI. - Préférez
srundans les jobs Slurm. - Testez avec peu de tâches avant une grande exécution.
- Définissez
OMP_NUM_THREADSpour les programmes OpenMP. - Documentez les modules, compilateurs, options et ressources Slurm utilisés.
- Conservez les scripts de compilation et de soumission dans votre dépôt de code.