Programmation parallèle
Objectifs de la section
Afin de nous rendre compte de la programmation des machines parallèles (implicitement du style de programmation pour une Grid) nous allons programmer en langage C ou C++ en utilisant deux API :
- MPI (Massage Passing Interface)
- OpenMP (Open Multiprocessing)
Ces deux API sont très différentes, voire complémentaire et peuvent s'utiliser ensemble pour la réalisation d'une application (programmation hybride). Dans cette partie on tentera de réaliser des programmes soit avec l'une, soit avec l'autre des API, jamais les deux.
MPI illustre le paradigme de la mémoire distribuée (chaque unité de traitement dispose uniquement de sa propre mémoire) et OpenMP illustre le paradigme de la mémoire partagée.
Installation
Il faut que vous ayez installé le compilateur gcc sur votre machine. Pour OpenMP il n'y a rien à faire, le compilateur gcc implémente déjà cette API. Pour MPI on conseille fortement d'installer l'API depuis le site OpenMPI.
OpenMP
Une application en OpenMP est une application mono-processus avec un thread principal et, éventuellement, d'autres threads lancés en parallèle. Les variables du programmes (dans la fonction main
ou toute autre fonction) deviennent des variables communes (shared) ou privé (private).
La compilation se réalise avec :
gcc -fopenmp prog.c ....
L'exécutable s'exécute comme tout exécutable sous Unix/Linux :
executable
ou ./executable
Quelques exemples de programmes :
- programme qui lance un nombre de thread et chacun affiche son numéro : omp_hello.c avec diverses versions pour voir clairement l'usage des variables partagées ou privées et l'importance d'une barrière de synchronisation : omp_hello_V2.c, omp_hello_V3.c, omp_hello_V4.c, omp_hello_V5.c.
- programme pour lequel on lance des threads qui communiquent en anneau (sur la base de leur numéro forment un anneau virtuel) : anneau.c
- programme qui calcule la date de Pâques (facile !) : date_Paques.c (illustration en programme d'un exercice en TD).
- programme qui fait la somme d'un tableau de valeurs générées aléatoirement : somme_omp.c version avec la partition des données en blocks de taille égale (+1), somme_omp_V2.c version avec un thread en plus et le dernier block de taille 'reste'
- programme qui implémente le tri exhaustif tri_omp.c
- programme pour le calcul de préfixe prefixe_parallel.c et une version qui n'est pas correcte prefixe_blague.c
MPI
Une application écrite en C et MPI se composera des plusieurs processus, les processus seront obtenus à partir du même code C (SPMD - Single Program Multiple Data) ou à partir des codes différents (MPMD). Toutefois, on conseille de ne pas utiliser plus de 3 codes (programmes) différents pour une même application.
La compilation se fait avec la commande :
mpicc prog.c -o executable
Chaque programme se compile séparément.
L'exécution d'une application MPI se fait avec la commande :
mpirun -np nb_processus executable
Si l'application se compose des processus issus des programmes différents, on compile avec la commande mpicc
chaque programme, chaque programme a sa propre fonction main()
, on construit autant d'exécutables que de programmes et on indique dans la commande mpirun
le nombre de processus ayant le même exécutable :
mpirun -np n1 executable1 : -np n2 executable2 ...
Quelques exemples de programmes :
- programme qui détecte son numéro de process et l'affiche (équivalent du "Hello, world!") : mpi_code.c
- programme pour lequel les processus, sur la base de leur numéro, forment un anneau virtuel : mpi_anneau.c
- programme distribué qui calcule le triangle de Pascal (difficile !) : mpi_pascal.c
Regardez attentivement le fonctionnement de ces programmes qui débutent tous pas la détection de numéro d'ordre du processus dans le cadre de son groupe (appelé communicateur).
Problèmes résolus complètement
- le calcul de la date de Pâques : solution séquentielle, en mémoire partagée et en mémoire distribue avec MPI (l'exécutable attend en entrée l'année de référence)
- le produit entre une matrice et un vecteur : solution séquentielle, parallélisme de threads au niveau du calcul, avec un nombre de threads prédéfinie, en MPI (l'exécutable attend en entrée les noms de fichiers d'entrée et de sortie)
Je reste à votre disposition pour toute information.