IATIC4 CM 3
France Boillod-Cerneux
Rappels
• Programmation parallele
• Distribution du travail / probleme à resoudre sur plusieurs unités de calcul
• Mémoire distribuee:
• Echange explicite des informations. Les donnees sont envoyees explicitement d’un
processeur à l’autre
• Bibliotheque permettant de faire ces echanges: MPI pour Message Passing Interface
• Mémoire partagée
• La mémoire est visible par toutes les entites de calcul. Les variables sont donc visibles par
tous
• Dans ce cours, on va se concentrer sur la programmation à mémoire partagée.
Introduction à OpenMP
Introduction à OpenMP
Introduction à OpenMP
Introduction à OpenMP
• Langage par pragmas permettant la description des régions parallèles dans du code
écrit en séquentiel
• Peu intrusif sur le développement
• Support pour les langages C/C++ et Fortran
• Portable sur des nombreuses architectures et OS
• Y compris (en partie) les GPUs, depuis OpenMP5
• Le contexte:
• Les codes historiques (legacy codes) ont une durée de vie de plusieurs décennies.
• Les supercalculateurs ont une durée de vie de 5ans environ.
Introduction à OpenMP
Pragma openMP
Introduction à OpenMP
Introduction à OpenMP
OpenMP
La syntaxe OpenMP
#pragma omp directive [clauses]
CONSTRUIRE UNE REGION
PARALLELE
Interface de programmation
Interface de programmation
Interface de programmation
goto
Introduction à OpenMP
Introduction à OpenMP
Introduction à OpenMP
Question au tableau
On distribue l’algorithme sur deux threads
Quelle sera la valeur de S?
OpenMP, des fonctions à connaitre
Afin de distribuer le travail, il faut pouvoir identifier « quel thread fait
quoi »
• OpenMP propose plusieurs fonctions qui permettent
• De savoir combien de threads on manipule:
• omp_get_num_threads() => retourne un integer
• De pouvoir identifier un thread parmi les autres:
• Omp_get_thread_num() => retourne un integer
OpenMP – tester si l’on est dans une region
parallele
• Omp_in_parallel() => retourne vrai ou faux
• Faux: on est dans une region sequentielle
• Vrai: on est dans une region parallele
OpenMP – créer des threads
• Question: y a t il une limite du nb de threads que l’on peut creer?
• Limite SW – “ulimit –u”
• Short answer to your question : Number of process possible in the linux system
is UNLIMITED.
• But there is a limit on number of process per user(except root who has no limit)
• Laptop pro: ulimit –u => 256
• Limite HW
• Graphique TTS en function du nombre de threads
openmp
• Inclure la librairie omp.h
• Inclure –fopenmp lors de la compilation
• Sans quoi, les pragmas seront interprétés comme des commentaires
Portée des variables
Portée des variables
Portée des variables
#include <omp.h>
Portée des variables int main(){
int a = 2020;
int p = -1;
printf("Hello world sequential\n“);
#pragma omp parallel
{
printf("Hello world %d\n“, a);
p=omp_in_parallel();
}
printf(“p value is %d“, p);
}
$> gcc -fopenmp hello_world.c
$> export OMP_NUM_THREADS=2
$> ./a.exe
Hello world sequential
Hello world 2020
Hello world 2020
p value is 1
#include <omp.h>
int my_sub_function(){
…
Portée des variables }
int main(){
int a = 2020;
int p = 0;
int stuff = 0;
printf("Hello world sequential\n“);
#pragma omp parallel
{
printf("Hello world %d\n“, a);
p=omp_in_parallel();
printf(“p value is %d“, p);
stuff=my_sub_function();
}
}
$> gcc -fopenmp hello_world.c
$> export OMP_NUM_THREADS=2
$> ./a.exe
Hello world sequential
Hello world 2020
Hello world 2020
p value is 1
p value is 1
Portée des variables #include <omp.h>
int my_sub_function(){
…
}
int main(){
int a = 2020;
int p = 0;
int stuff = 0;
printf("Hello world sequential\n“);
Jusque la le 16.10.23 #pragma omp parallel
{
printf("Hello world %d\n“, a);
p=omp_in_parallel();
printf(“p value is %d“, p);
stuff=my_sub_function();
}
}
$> gcc -fopenmp hello_world.c
$> export OMP_NUM_THREADS=2
$> ./a.exe
Hello world sequential
Hello world 2020
Hello world 2020
p value is 1
p value is 1
Portee des variables
• Shared: Définit une liste de variables à placer en mémoire partagée
• Il n’y a qu’une instance de chaque variable partagée
• Tous les threads d’une même équipe peuvent accéder aux variables
partagées simultanément (sauf si une directive OpenMP specifique
l’interdit)
• Les modifications d’une variable partagée sont visibles par tous les
threads de l’équipe
• Quel type de variable va-t-on declarer en partage par defaut?
• Plutôt les variables qui font office de « variables d’entree, en mode lecture »
Portee des variables
• Default (shared|none)
• Permet à l’utilisateur de changer le statut par défaut des variables
de la région parallèle (hors variables locales et automatiques des
fonctions appelées)
• Choisir none impose au programmeur de spécifier le statut de
chaque variable
• Bien pour éviter les variables partagées par erreur
Construction d’une region parallèle
#include <omp.h>
void my_sub (){
int a = 2020;
a = a + rand();
printf(“a value is %d“, a);
}
int main(){
#pragma omp parallel
{
my_sub();
}
}
$> gcc -fopenmp hello_world.c
$> export OMP_NUM_THREADS=3
$> ./a.exe
Hello world sequential
a value is 2020
a value is 2021
a value is 2022
Code au tableau, instance de a copiée en memoire privee.
Exemple de sortie du code: qu’en deduisez vous sur les var
Portée des variables privees?
Portée des variables
Portée des variables
Portée des variables
Portée des variables
Portée des variables
Gerer le nombre de threads
Construction d’une region parallèle
• Définition de la taille de l’équipe de threads
C
Fortran
Construction d’une region parallèle
program parallel #include <omp.h>
!$ use OMP_LIB
implicit none int main(){
print*, "Hello world sequentiel" printf("Hello world sequential\n“);
!$OMP PARALLEL NUM_THREADS(2) #pragma omp parallel num_threads(2)
print*, "Hello world parallele" {
!$OMP END PARALLEL printf("Hello world parallele\n“);
}
!$OMP PARALLEL #pragma omp parallel
print*, "Hello Cats" {
!$OMP END PARALLEL printf("Hello Cats“);
end program parallel }
}
$> gfortran –fopenmp hello_world.f90 $> gcc –fopenmp hello_world.c
$> export OMP_NUM_THREADS=4 $> export OMP_NUM_THREADS=3
$>./a.exe $> ./a.exe
What is the output?
Construction d’une region parallèle
#include <omp.h>
• Spécificité du C int main(){
printf("Hello world sequential\n“);
#pragma omp parallel num_threads(2)
{
printf("Hello world parallele\n“);
}
#pragma omp parallel
{
printf("Hello Cats\n“);
}
omp_set_num_threads(3);
#pragma omp parallel
{
printf(“Hello Dinosaurs“);
}
}
$> gcc -fopenmp hello_world.c
$> export OMP_NUM_THREADS=4
$> ./a.exe
Hello world sequential Hello Cats Hello Dinosaurs
Hello world parallele Hello Cats Hello Dinosaurs
Hello world parallele Hello Cats Hello Dinosaurs
Hello Cats
Numérotation des threads
• Rappel: par défaut, il n’y a aucune garantie sur l’ordre global
d’exécution des instructions d’un programme parallèle
Portée des variables
synchronization
synchronization
synchronization
synchronization
synchronization
synchronization
synchronization
#pragma omp single
Partage du travail
Partage du travail
synchronization
Partage du travail
Partage du travail
Partage du travail
Partage du travail
Partage du travail
Partage du travail
Partage du travail
Rapport
Rapport
Partage du travail
Partage du travail
Partage du travail
Partage du travail
Partage du travail
Partage du travail
synchronization
Partage du travail
• En langage C:
#pragma omp parallel for reduction (+:s)
Partage du travail
Backup slides
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Les taches OpenMP
Portee des variables
#include <stdio.h> printf("rp2\n");
#include <omp.h> #pragma omp parallel private(tid,rprivate)
int main(){ {
int tid, tprivate, rprivate; tid=omp_get_thread_num();
printf("rp 1\n"); printf("thread:%d tprivate:%d rprivate:%d\n", tid, tprivate, rprivate);
#pragma omp parallel private(tid,rprivate) }
{ return 0;
tid = omp_get_thread_num(); }
tprivate=tid;
rprivate=tid;
printf("thread: %d, tprivate: %d and rptivate:%d\n", tid, tprivate, rprivate);
}
Portee des variables
• rp 1
• thread: 5, tprivate: 5 and rptivate:5
• thread: 4, tprivate: 4 and rptivate:4
• thread: 2, tprivate: 2 and rptivate:2
• thread: 3, tprivate: 3 and rptivate:3
• thread: 0, tprivate: 0 and rptivate:0
• thread: 6, tprivate: 6 and rptivate:6
• thread: 1, tprivate: 1 and rptivate:1
• thread: 7, tprivate: 7 and rptivate:7
• rp2
• thread:4 tprivate:7 rprivate:0
• thread:3 tprivate:7 rprivate:0
• thread:6 tprivate:7 rprivate:0
• thread:0 tprivate:7 rprivate:0
• thread:2 tprivate:7 rprivate:0
• thread:5 tprivate:7 rprivate:0
• thread:1 tprivate:7 rprivate:0
• thread:7 tprivate:7 rprivate:1
Portee des variables
#include <stdio.h>
#include <omp.h> #pragma omp parallel private(tid,rprivate)
{
int tid, tprivate, rprivate;
tid=omp_get_thread_num();
#pragma omp threadprivate(tprivate)
printf("thread:%d tprivate:%d rprivate:%d\n", tid,
int main(){
tprivate, rprivate);
}
printf("rp 1\n"); return 0;
}
#pragma omp parallel private(tid,rprivate)
{
tid = omp_get_thread_num();
tprivate=tid;
rprivate=tid;
printf("thread: %d, tprivate: %d and rptivate:%d\n", tid,
tprivate, rprivate);
Portee des variables
rp 1
thread: 3, tprivate: 3 and rptivate:3
thread: 0, tprivate: 0 and rptivate:0
thread: 1, tprivate: 1 and rptivate:1
thread: 5, tprivate: 5 and rptivate:5
thread: 4, tprivate: 4 and rptivate:4
thread: 6, tprivate: 6 and rptivate:6
thread: 2, tprivate: 2 and rptivate:2
thread: 7, tprivate: 7 and rptivate:7
rp2
thread:6 tprivate:6 rprivate:6
thread:0 tprivate:0 rprivate:0
thread:3 tprivate:3 rprivate:3
thread:2 tprivate:2 rprivate:2
thread:4 tprivate:4 rprivate:4
thread:5 tprivate:5 rprivate:5
thread:1 tprivate:1 rprivate:1
thread:7 tprivate:7 rprivate:7
Portee des variables
Portee des variables
• #pragma omp threadprivate ( /∗ L i s t e de v a r i a b l e s g l o b a l e
s / s t a t i q u e s ∗/ )
• Spécifie que les variables listées seront privées et persistantes à chaque
thread au travers de l’exécution de multiples régions parallèles
• La valeur des variables n’est pas spécifiée dans la première région parallèle
sauf si la clause copyin est utilisée
• Ensuite, les variables sont préservées
• La directive doit suivre la déclaration des variables globales ou statiques
concernées
• Le nombre de threads doit être fixe
• Clauses possibles : aucune
Portee des variables
• Spécifie que les valeurs des variables threadprivate du thread maître
présentes dans la liste devront être copiées dans les variables
privées correspondantes des threads travailleurs en début de région
parallèle
Portee des variables
• #pragma omp threadprivate ( /∗ L i s t e de v a r i a b l e s g l o b a l e
s / s t a t i q u e s ∗/ )
• Spécifie que les variables listées seront privées et persistantes à chaque
thread au travers de l’exécution de multiples régions parallèles
• La valeur des variables n’est pas spécifiée dans la première région parallèle
sauf si la clause copyin est utilisée
• Ensuite, les variables sont préservées
• La directive doit suivre la déclaration des variables globales ou statiques
concernées
• Le nombre de threads doit être fixe
• Clauses possibles : aucune
Construction d’une region parallèle
#include <omp.h>
void my_sub (){
int a = 2020;
a = a + omp_get_thread_num();
printf(“a value is %d“, a);
}
Demander le statut des variables de mysub
int main(){
#pragma omp parallel default(shared)
{
my_sub();
}
}
$> gcc -fopenmp hello_world.c
$> export OMP_NUM_THREADS=3
$> ./a.exe
Hello world sequential
a value is 2020
a value is 2021
a value is 2022
Portée des variables
Exemple d’abord
Portée des variables