Open MP
Open MP
Françoise ROCH
OpenMP : une
ne alternati
alternative
e pl
plus
s simple po
pourr le
programmeur
Programmation multi-tâches sur les
architectures UMA
mémoire
SMT SMT SMT SMT SMT SMT SMT SMT SMT SMT SMT SMT
…
SMT SMT T0 SMT SMT SMT SMT SMT SMT SMT SMT
T1
ACCES DISTANT
ACCES LOCAL
Caractéristiques du modèle
OpenMP
Gestion de « threads » transparente et portable
Facilité de programmation
p g
Mais
Problème de localité des données
Mémoire partagée mais non hiérarchique
Efficacité non garantie (impact de l’organisation
l organisation
matérielle de la machine)
Passage à l’échelle
l échelle limité, parallélisme modéré
OpenMP
p
(Open specifications for MultiProcessing)
Introduction
Structure d’OpenMP
p
portée des variables
Constructions de ppartage
g du travail
Construction task
Synchronisation
Performances
Conclusion
Introduction : supports
pp d’OpenMP
p
La p
parallélisation multi-tâches existait avant p
pour
certains compilateurs (Ex:Cray,NEC,IBM)
OpenMP est une API pour un modèle à mémoire
partagé
Spécifications pour les langages C/C++, Fortran
Supporté par beaucoup de systèmes et de
compilateurs
OpenMP-2 2000 , OpenMP-3 2008
Specs : [Link]
Introduction : Modèle d’exécution
Un programme OpenMP est exécuté par un
processus unique (sur un ou plusieurs cores)
join
join
join
forrk
forrk
forrk
Thread
maître
Régions
parallèles
Introduction : les threads
Les threads accèdent aux mêmes ressources que le
processus.
Elles ont une pile (stack, pointeur de pile et pointeur
d’instructions propres)
Processus
Processus
Processus légers
Introduction : exécution d’un
programme OpenMP sur un
multicoeur
Le gestionnaire de tâches du système d’exploitation affecte
les tâches aux cores
cores.
Gestionnaire
de tâches
Cores 0 1 2 3
OpenMP
Introduction
Structure d’OpenMP
Portée des données
Constructions de ppartage
g du travail
Construction task
Synchronisation
Performances
Conclusion
Structure d’OpenMP
p :
architecture logicielle
OpenMP
! Code sequentiel execute par le maître /* Code sequentiel execute par le maître */
!C
Code
d sequentiel
ti l !* Code Sequentiel */
./[Link]
/a out
# ps –eLF
USER PID PPID LWP C NLWP SZ RSS PSR
…
OpenMP
IIntroduction
t d ti
Structure d’OpenMP
Portée des variables
Constructions de partage du travail
Construction task
Synchronisation
S h i ti
Performances
Conclusion
Rappel : allocation mémoire- portée des variables
Variables statiques et automatiques
¾ statique : emplacement en mémoire défini dès sa déclaration par le
compilateur
p
¾ automatique : emplacement mémoire attribué au lancement de l’unité de
programme où elle est déclarée (existence garantie que pendant ’exécution
de l’unité).
Variables globales
g
globale : déclarée au début du programme principal, elle est statique
2 cas :
¾ initialisées à la déclaration (exemple : parameter, data)
¾ non-initialisées
i iti li é à lla dé
déclaration
l ti ((exemple l : en ffortran
t lles common,
en C les variables d’unités de fichier, les variables externes ou static)
Variables locales
variable à portée restreinte à l’unité
l unité de programme où elle est déclarée
déclarée, 2
catégories :
¾ Variables locales automatiques
¾ Variables locales rémanentes (statiques) si elles sont :
a) initialisées explicitement à la déclaration
déclaration,
b) déclarées par une instruction de type DATA,
c) déclarées avec l’attribut SAVE => valeur conservée entre 2 appels
Rappel : stockage des variables
Le processus
thread0 thread1 thread2 thread3
Noyau
y UNIX appels
pp systèmes
y
Communications entre zoneU Dans un sous programme appelé dans une
l’application et l’OS
région parallèle, les variables locales et
Code assembleur obtenu après automatiques sont privées à chacune des
compilation et édition de liens
TXT threads (mode stack).
Variables statiques
initialisées : DATA
data
Variables statiques non initialisées :
bss Variables partagées
COMMON, SAVE
Tableaux dynamiques
y q :
ALLOCATABLE heap
Leur profil n’est pas connu à
l’écriture du programme Stack du processus
Variables locales automatiques Variables
Tableaux automatiques Stack Stack Stack Stack
thread0 thread1 thread2 thread3 privées
Contextes de procédures
Statut d’une variable
Le statut d’une variable dans une zone !$USE OMP_LIB
parallèle est : program private_var.f
¾ soit SHARED,
SHARED elle se trouve dans la
mémoire globale integer:: tmp =999
¾ soit PRIVATE, elle est dans la pile Integer :: OMP_GET_THREAD_NUM
q thread, sa valeur est
de chaque Call OMP_SET_NUM_THREADS(4)
OMP SET NUM THREADS(4)
indéfinie à l’entrée de la zone
!$OMP PARALLEL PRIVATE(tmp)
Déclarer le statut d’une variable print *, tmp
!$OMP PARALLEL PRIVATE(list) tmp= OMP_GET_THREAD_NUM()
!$OMP PARALLEL FIRSTPRIVATE(list)
print *, OMP_GET_THREAD_NUM(), tmp
!$OMP PARALLEL SHARED(list) ( )
!$OMP END PARALLEL
Déclarer un statut par défaut
Clause DEFAULT(PRIVATE|SHARED| print *, tmp
NONE)) end
Clauses de la directive PARALLEL
NONE
Equivalent de l’ IIMPLICIT NONE en Fortran. Toute variable
devra avoir un statut défini explicitement
SHARED (liste_variables)
Variables partagées entre les threads
PRIVATE (liste_variables)
Variables privées à chacune des threads, indéfinies en
dehors du bloc PARALLEL
FIRSTPRIVATE (liste_variables)
Variable initialisée avec la valeur que la variable d’origine
avait
it juste
j t avantt la
l section
ti parallèle
llèl
DEFAULT (PRIVATE | SHARED|NONE)
IIntroduction
t d ti
Structure d’OpenMP
Portée des données
Constructions de partage du travail
Construction task
Synchronisation
S h i ti
Performances
Conclusion
Partage
g du travail
Répartition d’une boucle entre les threads
(boucle //)
Répartition de plusieurs sections de code entre
les threads,, une section de code p
par thread
(sections //)
Exécution d’une portion de code par un seul
Thread
Exécution de plusieurs occurences d’une même
procédure par différents threads (orphaning)
Exécution par différents threads de différentes
unités de travail provenant de constructions f95
Portée d’une région parallèle
Program portee
implicit none
!$OMP PARALLEL Subroutine sub()
call sub()
Logical :: p, OMP_IN_PARALLEL
!$OMP END PARALLEL
!$ p = OMP_IN_PARALLEL()
OMP IN PARALLEL()
End program portee
print *, “Parallel prog ? ”, p
End subroutine sub
!$OMP DO SCHEDULE(DYNAMIC,taille_paquets) 0 1 3
2
Les paquets sont distribués aux threads libres de façon dynamique 5 6 4
7
Tous les paquets ont la même taille sauf éventuellement le dernier, 9
t
8 10
11
par défaut la taille des paquet est 1. 12 13
14 15
!$OMP DO SCHEDULE(GUIDED,taille_paquets) 0 2 4 6
Taille_paquets : taille minimale des paquets (1 par défaut) sauf le 1 3
dernier. 8 9 5 7 t
Taille des paquets maximale en début de boucle (ici 2) puis diminue 13 10 11 12
15 14
pour équilibrer la charge.
Répartition du travail : clause SCHEDULE
Ex: 24 itérations, 3 threads
13,14 15 16
15,16 17,18
21,22
19,20 23,24
Mode static, avec
Taille paquets=nb itérations/nb threads
Cyclique : STATIC
Ex :
export OMP_SCHEDULE=“DYNAMIC,400”
Reduction : pourquoi ?
Ex séquentiel : En parallele :
Do i=1,N
i=1 N !$OMP PARALLEL DO SHARED(X)
do i=1,N
X=X+a(i)
X = X + a(i)
enddo enddo
!$OMP END PARALLEL DO
Ex d’application
pp :p
parallélisation des nids de boucle,, avec un
découpage par blocs.
Parallélisme imbriqué
q
!$OMP MASTER
...
!$OMP END MASTER
Partage du travail : Program main
implicit none
procédures orphelines integer, parameter :: n=1025
real, dimension(n,n) :: a
real, dimension(n) :: x,y
IIntroduction
t d ti
Structure d’OpenMP
Portée des données
Constructions de partage du travail
Construction TASK
Synchronisation
S h i ti
Performances
Conclusion
Partage du travail : construction TASK
Une “TASK” au sens OpenMP est une unité de travail dont
ll’exécution
exécution peut être différée (ou démarrer immédiatement)
Autorise la génération dynamique de tâches
IIntroduction
t d ti
Structure d’OpenMP
Portée des données
Constructions de partage du travail
Construction task
S
Synchronisation
h i ti
Performances
Conclusion
Synchronisation
y
Program barriere
Par défaut à la fin des !$OMP PARALLEL &
SHARED(A,B,C) PRIVATE(tid)
constructions parallèles, tid = OMP_GET_THREAD_NUM()
A(tid) = big_calcul_1(tid);
big calcul 1(tid);
en l’absence
l’ b d
du !$OMP BARRIER Barrière
NOWAIT !$OMP DO
DO i=1, n
explicite
C(i) = big_calcul_2(i,
big calcul 2(i A)
Directive BARRIER ENDDO
!$OMP END DO
Barrière
Impose explicitement !$OMP DO implicite
une barrière de DO ii=11, n
B(i) = big_calcul_3(i, C)
synchronisation: chaque END DO
!$OMP END DO NOWAIT
tâche attend la fin de A(tid) = big_calcul_4(tid)
big calcul 4(tid)
!$OMP END PARALLEL
toutes les autres End program barriere
Pas de
barrière
Synchronisation
y
Il peut être nécessaire d’introduire une synchronisation entre
tâches concurrentes pour éviter que celles-ci modifient la valeur
d’une variable dans un ordre quelconque
Ex : Espace partagé
fruit cerise
pomme
2 threads
th d ontt un
espace de couleur jaune
rouge
mémoire partagé
Thread 1 Thread 2
Synchronisation
y : régions
g critiques
Integer,dimension(n) :: a=1
Directive CRITICAL somme = 0
DO j=1,n
Ell s’applique
Elle ’ li sur une somme = somme + a(i)
(i)
END DO
portion de code …
Les tâches exécutent la
Integer somme = 0
région critique dans un Integre dimension(n) :: a=1
ordre non-déterministe, !$OMP PARALLEL DEFAULT(SHARED) &
& PRIVATE(i,,j,somme_partielle)
une à la fois somme_partielle = 0
!$OMP DO
Garantit aux threads un DO j=1,n
accès en exclusion somme_partielle = somme_partielle + a(i)
END DO
mutuelle !$OMP END DO
Son étendue est dynamique !$OMP CRITICAL
somme = somme+somme_partielle
!$OMP END CRITICAL
!$OMP END PARALLEL
….
Synchronisation : mise à jour atomique
La directive ATOMIC s’applique seulement dans le cadre de la mise à
jour dd’un
un emplacement mémoire
Caches
Ligne de cache
Cores
Mé i
Mémoire Mé i
Mémoire
CPU CPU
Cohérence de Cache
Performances : effets du CC-NUMA
Comment placer les données pour optimiser les temps
d’accès ?
La p
politique
q de p placement dépendp de l’OS
Sous linux, solaris : « first touch »
a[0]
[ ]
a[1] Mémoire Mémoire
a[99]
CPU C U
CPU
Cohérence de Cache
a[0] a[50]
a[1] Mé i
Mémoire Mé i
Mémoire a[51]
a[49] a[99]
CPU CPU
Cohérence de Cache
En attendant :
utiliser les possibilités offertes par l’OS pour
attacher les threads à des cores et pour
contrôler l’allocation de page.
Affinité thread/core avec
l’environnement d’exécution Intel:
Possibilité de lier les threads OpenMP à des
cores
N ti d
Notion de thread
th d affinity
ffi it : le
l lilieu d’
d’exécution
é ti d de
certaines threads est restreint à un sous
ensemble d’unités d’exécution physiques
Avec la librairie intel :
Variable d’environnement KMP_AFFINITY
S SGI : notion
Sur ti ded cpusett
outil « dplace » permet de lier une
application à un ensemble de CPUs
Outil « taskset » sous linux
Performances : parallélisation
conditionnelle
Utiliser lla clause
Utili l IF pour Program parallel
mettre en place une implicit none
parallélisation integer, parameter :: n=8192
integer :: i,j
conditionnelle
diti ll real, dimension(n,n) :: a,b
ex : ne paralléliser une call random_number(a)
!$OMP PARALLEL DO SCHEDULE(RUNTIME) &
boucle q que si sa taille &!$OMP IF([Link].1024)
est suffisamment do j=2,n-1
do i=1,n
grande b(i,j) = a(i,j+1) – a(i,j-1)
end do
end do
!$OMP END PARALLEL DO
End program parallel
Fonctions de bibliothèque
Fonctions relatives aux verrous
Un verrou est libre ou possédé par une thread.
omp_init_lock(),
omp init lock() omp
omp_set_lock(),
set lock() omp
omp_unset_lock(),
unset lock() omp
omp_test_lock()
test lock()
« omp_test_lock() » permet d’attendre à un point du code la libération d’un
verrou par une autre thread.
Fonctions de l’environnent d’exécution
Modifier/vérifier le nombre de threads
omp_set_num_threads(), omp_get_num_threads(),
omp_get_thread_num(), omp_get_max_threads()
Autoriser ou pas l’imbrication des régions parallèles et l’ajustement
dynamique du nombre de threads dans les régions parallèles
omp_set_nested(), omp_set_dynamic(), omp_get_nested()
Tester si le programme est actuellement dans une région parallèle
omp_in_parallel()
Combien y a t-il de processeurs reconnus par le système
[Link]
[Link]
[Link]
[Link]
« Using
U i O OpenMPMP , PPortable
t bl Sh
Shared dMMemory M
Model
d l »,
Barbara Chapman