Vous êtes sur la page 1sur 118

Optimisation des performances et Parallélisme en

C/C++ - openMP - MPI - UPC - CUDA -openCL


http://www.ann.jussieu.fr/pironneau

Olivier Pironneau1

1 University of Paris VI, Laboratoire J.-L. Lions, Olivier.Pironneau@upmc.fr

Cours Mastère 2, Automne 2009

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE
- UPC - CUDA
1 / 118-op
Outline I
1 Leçon 1 : Architecture des machines
Principes
Les environnements de travail
Machines Parallèles
2 Leçon 2: architectures parallèles
Les logiciels
Un exemple facile a paralléliser
Le code C
3 Leçon 3: Parallélisation avec openMP
Principes de openMP
Exemples et syntaxes
Analyse de edostochOMP.c
Plus d’exemple et de mots clés en OpenMP
Exemple 2: EDP-1d en éléments finis
Discretisation par Elements Finis P 1
Parallélisation en OpenMP
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE
- UPC - CUDA
2 / 118-op
Outline II
Le code vanilafem.c
4 Leçon 4: Message Passing Interface
Historique et résumé
Parallélisation mémoire distribuée en MPI
5 Leçon 5: UPC: Unified Parallel C
UPC de Berkeley
6 Leçon 6: Les GPU, CUDA et openCL
Historique
Portabilité: openCL
openCL sur Mac
7 Leçon 7: Les outils du calcul parallèle
le partitionneur Metis pour les Maillages non-structurées
Integration les compilateurs dans Eclipse
Bibliothèques pour le calcul parallèle
PetSc
8 Leçon 8: les algorithmes du calcul parallèle
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE
- UPC - CUDA
3 / 118-op
Outline III
Méthodes de Schwarz
Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE
- UPC - CUDA
4 / 118-op
La machine de von Neumann

Un programme stocké en mémoire


Des mémoires pour les programmes et les données
Une ou plusieurs unités de calcul et unités logiques
La vitesse est limitée
- par la vitesse du processeur
- par le taux de transfert du bus entre la mémoire et le CPU
- par les conflits entre opérations et transferts dans les machines
vectorielles et multi-coeur.

Toute les opérations sont traduites en binaire (algèbre de Boole) et


implémentées par des portes logiques (silicium).
Ce mode de fonctionnement pourrait être remis en question pour les
ordinateurs quantiques. Si les mémoires acquièrent individuellement
des fonctions de calcul on pourrait aussi revenir au principe du "data
flow".
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE
- UPC - CUDA
5 / 118-op
Pointeurs et adresses

Numérotation des mémoires


Chaque mémoire possède une adresse physique, mais elle est
adressée par une adresse logique qui dépend du programme. Ainsi le
système met à la disposition du programme un bloc mémoire qui peut
être vu comme contiguë même s’il ne l’est pas en réalité.
Pointeurs: relations entre la valeur stockée par une mémoire et son
adresse (logique):
// 2 blocs mémoires sont alloués,
float a,b; // un pour le réel a et un pour b
float* adr;//adr est une nb de type "pointeur sur un réel"
adr = @a; //le bloc mémoire d’adresse adr contient a
*adr =b; // on recopie b dans le bloc mémoire
// qui contenait a, donc a est perdu.

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE
- UPC - CUDA
6 / 118-op
Hiérarchisation des mémoires

Mémoires périphériques (lent): disque dur, clef USB, bandes


magnétiques
Mémoires principales (rapide): memoire RAM
Buffers (mémoires dédiées aux communications): mémoires
tampon entre le disque dur et la RAM ou le proc.
Caches (très rapide) memoire rapide pres du processeur:
maintenant dans la puce proc.
Registres (interne au microprocesseur) : en général dans la puce
proc.
La situation se complique avec les machines parallèles et/ou les
machines hybrides (GPU) car il faut distinguer les mémoires
accessibles directement par le proc de celles accessible par
intéruption système (il faut demander la permission en quelque sorte)
parce qu’elles dépendent directement d’un autre processeur par
exemple.
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE
- UPC - CUDA
7 / 118-op
Ordinateurs vectoriels
L’objectif est d’accélérer l’opération suivante
float x[100], y[100], z[100];
for (i = 0: i < 100: i++)
z[i] = x[i] + y[i];

Plusieurs unités de calcul flottant


Amener les données dans le cache à l’avance (fetch)
Ordonner les données et faire les + en //
Ranger les données en // (store)
Tester l’option -O3 du compilateur gcc
Remarque
Ca ne marche pas si bien pour
float x[100], y[100];
for (i = 1: i < 100: i++)
x[i] = x[i-1] + y[i];
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE
- UPC - CUDA
8 / 118-op
CBLAS
L’objectif est d’optimiser les opérations vectorielles bas niveau en
utilisant une librairie adaptée à la machine. C’est le cas de "BLAS"; en
principe on n’a alors plus à se préoccuper des caches.
Exemple: accélération de la méthode du gradient conjugué avec la
fonction cblas_daxpy(..) qui remplace y par αx + y .
Rappel: le gradient conjugué pour Ax=f (ou A est n × n symmétrique)
for (n = 0; n < N; n + +){
g n = Ax n − f
|g n |2
γ = n−1 2
|g |
hn = γhn−1 − g n
hn · g n
ρ= n
h · Ahn
x = x n−1 + ρhn
n

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE
- UPC - CUDA
9 / 118-op
CBLAS memento
Level 1 BLAS
dim scalar vector vector scalars 5-element array pre xes
SUBROUTINE xROTG ( A, B, C, S ) Generate plane rotation S, D
SUBROUTINE xROTMG( D1, D2, A, B, PARAM ) Generate modi ed plane rotation S, D
SUBROUTINE xROT ( N, X, INCX, Y, INCY, C, S ) Apply plane rotation S, D
SUBROUTINE xROTM ( N, X, INCX, Y, INCY, PARAM ) Apply modi ed plane rotation S, D
SUBROUTINE xSWAP ( N, X, INCX, Y, INCY ) x$y S, D, C, Z
SUBROUTINE xSCAL ( N, ALPHA, X, INCX ) x x S, D, C, Z, CS, ZD
SUBROUTINE xCOPY ( N, X, INCX, Y, INCY ) y x S, D, C, Z
SUBROUTINE xAXPY ( N, ALPHA, X, INCX, Y, INCY ) y x + y S, D, C, Z
FUNCTION xDOT ( N, X, INCX, Y, INCY ) dot xT y S, D, DS
FUNCTION xDOTU ( N, X, INCX, Y, INCY ) dot xT y C, Z
FUNCTION xDOTC ( N, X, INCX, Y, INCY ) dot xH y C, Z
FUNCTION xxDOT ( N, X, INCX, Y, INCY ) dot + xT y SDS
FUNCTION xNRM2 ( N, X, INCX ) nrm2 jjxjj2 S, D, SC, DZ
FUNCTION xASUM ( N, X, INCX ) asum jjre(x)jj1 + jjim(x)jj1 S, D, SC, DZ
FUNCTION IxAMAX( N, X, INCX ) amax 1st k 3 jre(xk )j + jim(xk )j S, D, C, Z
= max(jre(xi)j + jim(xi)j)
Level 2 BLAS
options dim b-width scalar matrix vector scalar vector
xGEMV ( TRANS, M, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax + y; y AT x + y; y AH x + y; A m  n S, D, C, Z
xGBMV ( TRANS, M, N, KL, KU, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax + y; y AT x + y; y AH x + y; A m  n S, D, C, Z
xHEMV ( UPLO, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax + y C, Z
xHBMV ( UPLO, N, K, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax + y C, Z
xHPMV ( UPLO, N, ALPHA, AP, X, INCX, BETA, Y, INCY ) y Ax + y C, Z
xSYMV ( UPLO, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax + y S, D
xSBMV ( UPLO, N, K, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax + y S, D
xSPMV ( UPLO, N, ALPHA, AP, X, INCX, BETA, Y, INCY ) y Ax + y S, D
xTRMV ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) x Ax; x AT x; x AH x S, D, C, Z
xTBMV ( UPLO, TRANS, DIAG, N, K, A, LDA, X, INCX ) x Ax; x AT x; x AH x S, D, C, Z
xTPMV ( UPLO, TRANS, DIAG, N, AP, X, INCX ) x Ax; x AT x; x AH x S, D, C, Z
xTRSV ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) x A 1 x; x A T x; x A H x S, D, C, Z
xTBSV ( UPLO, TRANS, DIAG, N, K, A, LDA, X, INCX ) x A 1 x; x A T x; x A H x S, D, C, Z
xTPSV ( UPLO, TRANS, DIAG, N, AP, X, INCX ) x A 1 x; x A T x; x A H x S, D, C, Z
options dim scalar vector vector matrix
xGER ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyT + A; A m  n S, D
xGERU ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyT + A; A m  n C, Z
xGERC ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyH + A; A m  n C, Z
xHER ( UPLO, N, ALPHA, X, INCX, A, LDA ) A xxH + A C, Z
xHPR ( UPLO, N, ALPHA, X, INCX, AP ) A xxH + A C, Z
xHER2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyH + y( x)H + A C, Z
xHPR2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, AP ) A xyH + y( x)H + A C, Z
xSYR ( UPLO, N, ALPHA, X, INCX, A, LDA ) A xxT + A S, D
xSPR ( UPLO, N, ALPHA, X, INCX, AP ) A xxT + A S, D
xSYR2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyT + yxT + A S, D
xSPR2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, AP ) A xyT + yxT + A S, D
Level 3 BLAS
options dim scalar matrix matrix scalar matrix
xGEMM ( TRANSA, TRANSB, M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) C op(A)op(B) + C; op(X ) = X; X T ; X H ; C m  n S, D, C, Z
xSYMM ( SIDE, UPLO, M, N, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) C AB + C; C BA + C; C m  n; A = AT S, D, C, Z
xHEMM ( SIDE, UPLO, M, N, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) C AB + C; C BA + C; C m  n; A = AH C, Z
xSYRK ( UPLO, TRANS, N, K, ALPHA, A, LDA, BETA, C, LDC ) C AAT + C; C AT A + C; C n  n S, D, C, Z
xHERK ( UPLO, TRANS, N, K, ALPHA, A, LDA, BETA, C, LDC ) C AAH + C; C AH A + C; C n  n C, Z
xSYR2K( UPLO, TRANS, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) C ABT + BAT + C; C AT B + BT A + C; C n  n S, D, C, Z
xHER2K( UPLO, TRANS, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) C ABH + BAH + C; C AH B +  BH A + C; C n  n C, Z
xTRMM ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA, B, LDB ) B op(A)B; B Bop(A); op(A) = A; AT ; AH ; B m  n S, D, C, Z
xTRSM ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA, B, LDB ) B op(A 1 )B; B Bop(A 1 ); op(A) = A; AT ; AH ; B m  n S, D, C, Z
2

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -10
CUDA
/ 118-op
CBLAS
for(int iter=0;iter<n;iter++) {
atimesx(A,x,grad); // externe pour grad=Ax
cblas_daxpy( n,-1,f,1,grad,1); // grad[i] -= f[i];
double norm2min; // normg2 = scal(grad,grad)
double normg2 = cblas_ddot(n,grad,1,grad,1);
if(!iter) norm2min = normg2*1.0e-8;
if(normg2<norm2min) break;
double gamma = normg2/normg2old;
cblas_dscal(n,gamma,h,1); //h[i] = gamma*h[i]-grad[i]
cblas_daxpy( n, -1., grad,1, h, 1); h[0]=0;
double rho = cblas_ddot(n,h,1,grad,1); //rho=scal(h,grad)
atimesx(A,h,grad);
rho /= cblas_ddot(n,h,1,grad,1); //rho /= scal(h,grad)
cblas_daxpy( n, -rho, h,1, x, 1); // x[i] -= rho*h[i];
}

cblas est adapté du Fortran: blas1, blas2, blas3


Intégré a atlas et blitz (mais attention pour la suite)
sur edpblas.cpp le cpu est divisé par 3!
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -11
CUDA
/ 118-op
Le même en C++ (I)
#include<stdio.h>
#include<time.h>
const int n=5000, niter=200;
void atimesx(double** A, double* x, double* f){
for(int i=0;i<n;i++){
f[i]=0; for(int j=0;j<n;j++) f[i] += A[i][j]*x[j]; }
}
double ddot(double* a, double* b){
double aux=0; for(int i=0;i<n;i++) aux+=a[i]*b[i];
return aux;
}
int main() {
double **A, *x, *f, *h, *g;
A=new double*[n]; x=new double[n];
f=new double[n]; g=new double[n]; h=new double[n];
long int tt=clock();
gradcon();
printf("%10f\n",(tt-clock())/CLOCK_PER_SEC);
return 0;
}
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -12
CUDA
/ 118-op
Le même en C++ (II)

void gradcon(double** A, double* x, double* f,


double* h, double* g){
for(int i=0;i<n;i++){
A[i]=new double[n]; f[i]=i/double(n); x[i]=i;
for(int j=0;j<n;j++) A[i][j]=i*j/(n*n+11.);
}
double normg2old = 1e10;
for(int iter=0;iter<niter;iter++) {
atimesx(A,x,g); for(int i=0;i<n;i++) g[i] -= f[i];
double norm2min, normg2 = ddot(g,g);
if(!iter) norm2min = normg2*1.0e-8;
if(normg2<norm2min) break;
double gamma = normg2/normg2old;
for(int i=0;i<n;i++) h[i] = gamma * h[i] - g[i];
double rho = ddot(h,g);
atimesx(A,h,g); rho /= ddot(h,g);
for(int i=0;i<n;i++) x[i] -= rho*h[i];
}
}

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -13
CUDA
/ 118-op
L’outil linux ubuntu
Dans l’ensemble les pro du calcul travaillent sous unix: l’accès aux
bibliothèques y est plus simple. L’OS Mac est construit sur un Berkeley
unix. Donc pas la peine de mettre ubuntu.
Sur PC le plus simple est d’installer ubuntu avec wubi, une application
windows qui met ubuntu dans un dossier distinct et sans partitionner le
disque (donc pas de danger pour Windows). Réserver 12Go de disque
au moins.
Installer la 9.04 sur XP (9.10+XP=pb de veille) ou la 9.10 sur
vista/7.
Ouvrir une fenêtre terminal dans ubuntu et taper g++ puis faire ce
qui est demandé (sudo install...)
idem en tapant javac (installer le jdk)
idem en tapant mpicc (installer openmpi)
idem en tapant gnuplot (installer le gnuplot-x11)
Télécharger avec le firefox de ubuntu la version Galileo de
Eclipse C++, de-zipper et tester (voir plus bas).
Vous avez maintenant les outils pour le C++, l’openMP, le MPI.
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -14
CUDA
/ 118-op
L’environnement de travail Eclipse (I)
Eclipse est très populaire en entreprise. Pour tester un programme:
créer un projet par le menu file/new C++ project. Choisir Hello world
C++Project Nommer le projet; faire next plutot que finish.

Puis cliquer sur le marteau puis sur la flèche blanche dans le rond vert
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -15
CUDA
/ 118-op
L’environnement de travail Eclipse (II)

Multi plateforme et gratuit mais suppose que gcc et un java sont


déjà installés (peut nécessiter cygwin sous windows)
Ecrit en java et meme portable sur une clef USB
Signale les erreurs de syntaxe clairement
Permet de profiter pleinement du debuggeur gdb
Permet de gérer des makefiles complexes (calcul // entre autre)
Diminue le temps de développement

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -16
CUDA
/ 118-op
Première séance de TD

Ecrire un gradient conjugué en C++


Le transformer avec les appels BLAS
Etudier les perfs en fonction de la taille n de A
Installer Eclipse et faire tourner votre programme par eclipse
Résoudre −u” = 1 dans (0,1) avec u(0) = u(1) = 0 par
Différences Finies et la méthodes du gradient conjugué pour le
système linéaire.
tester le programme de la diapo suivante.
Dans un premier temps on étudie l’implémentation LU
Vous devriez vous aperçevoir que cblas ne fait pas trop de différence.
En fait il faut aller à blas3 pour voir que là la réduction du temps CPU
est de l’ordre de 10, comme le montre l’exemple suivant. D’ou l’idée de
grouper les instructions par blocs pour faire des appels à blas3. Si
vous vous en sentez le courrage dans l’exo précédent...
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -17
CUDA
/ 118-op
Test de BLAS3 (Juvigny)
#include <cblas.h> /* On inclue l’interface C du blas */
double A[3000000], B[6000000], C[2000000];
void assembleMat( int ni, int nj, double A[]){
int i,j; double xnj=nj;
for (i=0; i<ni; i++)
for (j=0; j<nj; j++) A[i*nj+j] = ((i+j)%nj)/xnj;
}
void prodMat(int ni,int nj,int nk,double A[],double B[],double C[]
int i,j,k; /* Calcul produit matrice--vecteur (C assumed =0) */
for (i=0; i <ni; i++) for (k=0; k<nk; k++)
for (j=0; j<nj; j++) C[i*nk+k] += A[i*nj+j]*B[j*nk+k];
}
int main(int nargc, char* argv[]){
const int ni = 1000, nj = 3000, nk = 2000;
assembleMat( ni, nj, A); assembleMat( nj, nk, B);
# ifdef USEBLAS
cblas_dgemm(CblasRowMajor,CblasNoTrans,CblasNoTrans,ni,nk,
nj, 1., A, nj, B, nk, 0., C, nk);
# else
prodMat(ni,nj,nk,A,B,C);
# endif
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -18
CUDA
/ 118-op
Outline I
1 Leçon 1 : Architecture des machines
Principes
Les environnements de travail
Machines Parallèles
2 Leçon 2: architectures parallèles
Les logiciels
Un exemple facile a paralléliser
Le code C
3 Leçon 3: Parallélisation avec openMP
Principes de openMP
Exemples et syntaxes
Analyse de edostochOMP.c
Plus d’exemple et de mots clés en OpenMP
Exemple 2: EDP-1d en éléments finis
Discretisation par Elements Finis P 1
Parallélisation en OpenMP
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -19
CUDA
/ 118-op
Outline II
Le code vanilafem.c
4 Leçon 4: Message Passing Interface
Historique et résumé
Parallélisation mémoire distribuée en MPI
5 Leçon 5: UPC: Unified Parallel C
UPC de Berkeley
6 Leçon 6: Les GPU, CUDA et openCL
Historique
Portabilité: openCL
openCL sur Mac
7 Leçon 7: Les outils du calcul parallèle
le partitionneur Metis pour les Maillages non-structurées
Integration les compilateurs dans Eclipse
Bibliothèques pour le calcul parallèle
PetSc
8 Leçon 8: les algorithmes du calcul parallèle
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -20
CUDA
/ 118-op
Outline III
Méthodes de Schwarz
Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -21
CUDA
/ 118-op
Multiprocesseurs
Mémoires partagées
Mémoires distribuées
SIMD - MIMD
Cartes mères multi-cœurs et multi-processeurs
GPU

float x[100], y[100], z[100];


for (i = 0; i < 100; i++)
if ( y[i]!= 0) z[i] = x[i] / y[i]; else z[i]=y[i];

implementé en SIMD par


y[i]==0? do nothing
y[i] !=0 do z[i] = x[i] / y[i];
y[i] !=0 do nothing
y[i] ==0 do z[i] = y[i];
De nombreux processeurs peuvent être inoccupés!
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -22
CUDA
/ 118-op
Ordinateurs en réseaux

Cluster = un système par carte mère + une connectique rapide


(myrinet, infiniband, ethernet gygabit)
Ferme de stations: typiquement = plusieurs PC en réseau par
ethernet
Grid: Typiquement des machines sur la toile www. La grille EGEE
permet d’accéder à 45 000 machines sur 240 sites

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -23
CUDA
/ 118-op
Les Ordinateurs disponibles

Vitesse en nb d’opérations flottantes par secondes (flops) (voir


www.top500.org)
machine Intel centrino 2 a 2 ghz: 15 giga flops
core i7 de Intel: nd il est seul. 4 coeurs mais de l’overclock (boost)
sur un coeur
et avec un GPU Nvidia Tesla (128 proc) : 0.5 tera flops
Carte mère quadri-proc dual cores 3ghz: 80 Gflops
Cluster 128 cartes bi-pro dual core 3 ghz: 2 Tflops
La machine js21 du ccre: 5 Tflops
Le SX8 vectoriel de l’Idris: 60 Tflops
L’ibm blue-gene de l’Idris: 140 Tflops
Le Road-runner de Los-Alamos: 1 peta flops
Le Jaguar (Cray X86) de Oakridge Nat Lab: 1.74 Pflops

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -24
CUDA
/ 118-op
Les outils Middleware (intergiciels!)

openMP
MPI (openMPI et MPICH2)
Globus et mpich-G
upc-Berkeley, chapel
CUDA, openCL

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -25
CUDA
/ 118-op
Exemple 1. Calcul d’une option en finance

Le sousjacent St est modélisé par une EDO-S

dSt = St (r dt + σdWt ), S(0) = S0

Le put est calculé par P0 = e−rT E(K − ST )+


e−rT
La loi des grands nombres ⇒ P0 ≈ M (K − STi )+

On utilise des différences finies et on simule dWt = dtN (0, 1),

Sm+1 = Sm + δtSm (r δt + σ δtN (0, 1))
p
N (0, 1) = −2 log x cos(2πy ) x,y aleatoires uniformes ∈ (0, 1).
Le calcul des STi est “embarrassingly parallel".
Voici le code C

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -26
CUDA
/ 118-op
edostoch.c(I)

#include <stdlib.h> // ... stdio, math et time.h

const int M=365; // nombre de pas de temps


const double two_pi =6.28318530718;
double CPUtime(){ return ((double) clock())/CLOCKS_PER_SEC;}

double gauss(){ double x,y;


x= (1.+rand())/(1.+RAND_MAX);
y= (1.+rand())/(1.+RAND_MAX);
return sqrt( -2 *log(x) )*cos(two_pi*y);
}

double EDOstoch(const double S0, const double dt,


const double sdt, const double rdt){
double S= S0; int i;
for(i=1;i<M;i++)
S= S*(1.+gauss()*sdt+rdt);
return S;
}

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -27
CUDA
/ 118-op
edostoch.c (II)
int main(int argc, char* argv[]){
const double K=110, S0=100;
const int kmax=20000; // nb de realisations
const double T=1., r=0.03, sigma=0.2;
double dt=T/M, sdt, rdt, P0=0;
double time0=CPUtime();
sdt =sigma*sqrt(dt);
rdt = r*dt; srand(time(NULL));

for(int k=0; k<kmax;k++){


double Sa= EDOstoch(S0, dt, sdt, rdt);
if(K>Sa) P0 += K-Sa;
}
time0-=CPUtime();
printf("P_0 = %f CPUtime=%f \n",P0*exp(-r*T)/kmax, -time0);
return 0;
}

Exercice: En vue du parallélisme proposer une scission de la partie


qui prend du temps en 2 blocs indépendants.
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -28
CUDA
/ 118-op
Outline I
1 Leçon 1 : Architecture des machines
Principes
Les environnements de travail
Machines Parallèles
2 Leçon 2: architectures parallèles
Les logiciels
Un exemple facile a paralléliser
Le code C
3 Leçon 3: Parallélisation avec openMP
Principes de openMP
Exemples et syntaxes
Analyse de edostochOMP.c
Plus d’exemple et de mots clés en OpenMP
Exemple 2: EDP-1d en éléments finis
Discretisation par Elements Finis P 1
Parallélisation en OpenMP
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -29
CUDA
/ 118-op
Outline II
Le code vanilafem.c
4 Leçon 4: Message Passing Interface
Historique et résumé
Parallélisation mémoire distribuée en MPI
5 Leçon 5: UPC: Unified Parallel C
UPC de Berkeley
6 Leçon 6: Les GPU, CUDA et openCL
Historique
Portabilité: openCL
openCL sur Mac
7 Leçon 7: Les outils du calcul parallèle
le partitionneur Metis pour les Maillages non-structurées
Integration les compilateurs dans Eclipse
Bibliothèques pour le calcul parallèle
PetSc
8 Leçon 8: les algorithmes du calcul parallèle
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -30
CUDA
/ 118-op
Outline III
Méthodes de Schwarz
Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -31
CUDA
/ 118-op
openMP

Historique: créé en 1991 on en est à la norme 2.5 de 2005


Implémentation cachée à l’utilisateur : integré à gcc 4.2 et plus
pour les systèmes qui implémentent la bibliothèque pthreads et
aussi a MS visual C++ 2.5 et plus
Directives données au compilateur sous forme de #pragma
C’est un modèle SIMD avec mémoire partagée ou à priori toutes
les variables sont globales.
Références:
http://www.openmp.org/,
http://bisqwit.iki.fi/story/howto/openmp/,
http://en.wikipedia.org/wiki/OpenMP

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -32
CUDA
/ 118-op
Hello world

#include <omp.h>
#include <stdio.h>
#include <stdlib.h>

int main () { printf("Hello\n");


double time0=omp_get_wtime();
#pragma omp parallel for num_threads(2)
for(int n=0; n<10; ++n)
printf(" %d ",n);
printf("CPUtime=%f\n",omp_get_wtime()-time0);
return 0;
}

Compiler avec g++ -fopenmp hellomp.c -o hello (peut


demander export PATH=/usr/local/bin:$PATH) resultat de
./hello: 0 5 1 6 2 7 3 8 4 9 CPUtime=0.000633 Si dans
eclipse il faut changer projet/properties/settings/linker

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -33
CUDA
/ 118-op
Principales commandes

#pragma omp parallel


{ ... }
#pragma omp for
#pragma omp parallel sections
{ { Work1(); }
#pragma omp section
{ Work2(); Work3(); }
#pragma omp section
{ Work4(); }
}
#pragma omp barrier
#pragma omp atomic
counter += value; // only one thread will do that
int a, b=0;
#pragma omp parallel for private(a) shared(b)

chaque thread a son ‘a‘ mais ‘b‘ est le meme pour tous

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -34
CUDA
/ 118-op
Concepts

Reduction: fabriquer une seule variable a partir de plusieurs


variables private du meme nom; ex si une var A existe dans 2
processes une reduction+ des A rend une var globale a contenant
la somme des 2 A.
Fonctions utiles
int thread_id = omp_get_thread_num();
int nthreads = omp_get_num_threads();
DWORD_PTR mask = (1 << omp_get_thread_num());
SetThreadAffinityMask( GetCurrentThread(), mask );
Un seul for par parallel bloc sera parallélisé.
openMP est simple mais sa scalabilité est limitée par le fait de la
mémoire partagée.
Pour utiliser Eclipse il faut rajouter openmp dans le menu
projet/propriété/C-C++ setting/linker.

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -35
CUDA
/ 118-op
Loi de Amdhal

Loi de Amdhal: le speed-up est limité par la partie séquentiel du


programme. Le speed-up est S/[(1-p)S+pS/N] ou S est le temps calcul
sequentiel,p la proportion parallélisée et N le nb de processeurs.

Exercice: Obtenir le meilleur speed-up avec openMP sur edostoch.c


Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -36
CUDA
/ 118-op
edostochOMP.c I

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -37
CUDA
/ 118-op
edostochOMP.c II

L’exemple suivant va permettre de comparer les performances de openMP comparé à


CBLAS présenté plus haut pour le produit matrice vecteur.

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -38
CUDA
/ 118-op
Produit Matrice Vecteur (Juvigny) I

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -39
CUDA
/ 118-op
Produit Matrice Vecteur (Juvigny) II

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -40
CUDA
/ 118-op
Produit Matrice Vecteur (Juvigny) III

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -41
CUDA
/ 118-op
Exercices pour le TD

1 Lancer edostochomp.c et étudier les perfs en fonctions de P


2 Changer S[] en une seule variable et utiliser reduce; il faudra
aussi utiliser la fonction rand_r(state) qui, elle, est réentrante.
3 Lancer prog2.c pour comparer openMP et BLAS
4 Modifier le code pour utiliser openMP ET cblas.
5 Mettre des directives openMP dans le prgramme vanilafem.c
çi-dessous.

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -42
CUDA
/ 118-op
Equation de la chaleur

∂t u − ∂x (κ∂x u) = f , u(0, t) = u(L, t) = 0, u(x, 0) = u 0 (x) ∀x, t ∈ (0, L) ×

Formulation variationnelle et differences finies en temps


Z L m+1 Z L Z L
u − um m+1
w(x)dx + κ∂x u ∂x w = fw ∀w ∈ V := H01 (0, L)
0 δt 0 0

Discretisation en espace par éléments finis de degrés 1: on remplace


V par Vh , l’espace des fonctions continues affines par morceaux sur
[0, L] = ∪i [xi , xi+1 ] avec xi = ih,i=0..I-1, tel que Ih = L. On obtient un
système lineaire a chaque itération pour U m+1 ∈ RN :

B(U m+1 − U m ) + AU m+1 = F ∈ RN ,


1 L i j
Z Z L
avec Bij = w w dx, Aij = κ∇w i ∇w j dx
δt 0 0

où w i est la fonction de Vh qui vaut δij en xj .


Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -43
CUDA
/ 118-op
Equation de la chaleur: discretisation

Il est facile de voir que A et B sont tridiagonales avec

2h h 2κ κ
Bii = , Bi,i−1 = Bi,i+1 = , Aii = , Ai,i−1 = Ai,i+1 = −
δt δt h h
A priori le système tridiagonal pourU m+1 is résolu par factorisation de
Gauss (A = LU) . La parallélisation de la méthode du gradient conjugé
est beaucoup plus simple mais dans un premier temps on étudie
l’implémentation LU.
Ci dessous le programme pour Black-Scholes:

σ2x 2
∂t u + ru − rx∂x u − ∂xx u = 0, u(t = 0) = max(K − x, 0)
2
If there is a low-barrier then u = 0 at xm ; u = 0 at xM anyway but if xM is not large
compare to K then it is an up-barrier. L’exercice va consister à mettre des directives
openMP dans le code, essentiellement en parallélisant toutes les boucles for.

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -44
CUDA
/ 118-op
Le code vanilafem.c (I)

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -45
CUDA
/ 118-op
Le code vanilafem.c (II)

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -46
CUDA
/ 118-op
Le code vanilafem.c (III)

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -47
CUDA
/ 118-op
Le code vanilafem.c (IV)

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -48
CUDA
/ 118-op
Le code vanilafem.c (V)

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -49
CUDA
/ 118-op
Outline I
1 Leçon 1 : Architecture des machines
Principes
Les environnements de travail
Machines Parallèles
2 Leçon 2: architectures parallèles
Les logiciels
Un exemple facile a paralléliser
Le code C
3 Leçon 3: Parallélisation avec openMP
Principes de openMP
Exemples et syntaxes
Analyse de edostochOMP.c
Plus d’exemple et de mots clés en OpenMP
Exemple 2: EDP-1d en éléments finis
Discretisation par Elements Finis P 1
Parallélisation en OpenMP
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -50
CUDA
/ 118-op
Outline II
Le code vanilafem.c
4 Leçon 4: Message Passing Interface
Historique et résumé
Parallélisation mémoire distribuée en MPI
5 Leçon 5: UPC: Unified Parallel C
UPC de Berkeley
6 Leçon 6: Les GPU, CUDA et openCL
Historique
Portabilité: openCL
openCL sur Mac
7 Leçon 7: Les outils du calcul parallèle
le partitionneur Metis pour les Maillages non-structurées
Integration les compilateurs dans Eclipse
Bibliothèques pour le calcul parallèle
PetSc
8 Leçon 8: les algorithmes du calcul parallèle
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -51
CUDA
/ 118-op
Outline III
Méthodes de Schwarz
Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -52
CUDA
/ 118-op
Présentation de MPI

Après beaucoup de propositions architecture-dépendantes, les


programmeurs plébicitent PVM de J. Dongarra, puis sur le même
modèle un concorsium produit en 1994: MPI.
MPI est fondamentalement multiple instruction - multiple data -
distributed memory
mais de manière naturel chaque proc exécute le même
programme; sinon il faut spécifier que le proc p exécute le prog p.
la communiction des données est à la charge du programmeur, ce
qui complique fortement la programmation mais permet de bien
voir comment optimiser l’implémentation.
Apres MPI_init() et jusqu’a MPI_finalize() chaque proc
recoit le programme et une copie des data.
Une variable se retrouve donc stockée P fois sauf si elle est
déclarée en interne du prog du proc p.

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -53
CUDA
/ 118-op
Le Hello World de MPI

se compile (mpic++ OK aussi) et donne :

% mpicc hello.c -o hello


% mpirun -np 2 hello
Proc 1 received: Hello there from proc 0

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -54
CUDA
/ 118-op
Produit matrice vecteur
On exploite le fait que A est tridiagonal:
si {xi }iiMm −1 est dans un banc mémoire p
Axi = ai xi−1 + bi xi + ci xi+1 demande la reception de
xim −1 et de xiM des bancs mémoires p − 1 et p + 1.

void Option::atimesx(Vector& a, Vector& b, Vector& c, Vector& x,Ve


MPI_Status s;
if(p!=0){
MPI_Send(&(x[im]),1,MPI_DOUBLE, p-1, 0, MPI_COMM_WORLD);
MPI_Recv(&(x[im-1]),1,MPI_DOUBLE,p-1,0,MPI_COMM_WORLD,&s);
} if(p!=P-1){
MPI_Send(&(x[iM-1]),1,MPI_DOUBLE, p+1, 0, MPI_COMM_WORLD);
MPI_Recv(&(x[iM]),1,MPI_DOUBLE,p+1,0,MPI_COMM_WORLD,&s);
}
for(int i=im1;i<iM1;i++)
Ax[i] = a[i]*x[i-1]+b[i]*x[i]+c[i]*x[i+1];
}

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -55
CUDA
/ 118-op
Produit scalaire

Chaque proc fait sa part de boucle puis les resultats sont aditionnés
dans le proc 0 et le résultat est renvoyé a tous les procs.
double Option::scal (const Vector& v1,const Vector& v2){
double S,s=0;
for(int i=im1; i<iM1;i++)
s += v1[i] * v2[i];
MPI_Barrier(MPI_COMM_WORLD);
MPI_Reduce(&s, &S, 1, MPI_DOUBLE, MPI_SUM,0,MPI_COMM_WORLD);
MPI_Bcast(&S, 1, MPI_DOUBLE,0, MPI_COMM_WORLD);
return S;
}

Noter que la mémoire n’est pas optimisée et qu’il faudrait decaller les
indices et accéder à v [i − im1].

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -56
CUDA
/ 118-op
La fonction principale (I)
Le C++ de la fonction qui calcul l’option:
void Option::calc() {
const double dt=m.T/m.nT;
int argc; char **argv; MPI_Status status;
MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &p); /* get current process id */
MPI_Comm_size (MPI_COMM_WORLD, &P); /* get number of processes */
im=(m.nX*p)/P, iM = (m.nX*(p+1))/P;
im1 = (im==0)?1:im, iM1 = (iM==m.nX)?m.nX-1:iM;
for (int i=im1; i<iM1; i++) {
double hi = m.x[i]-m.x[i-1], hi1 = m.x[i+1]-m.x[i];
double xss = m.x[i]*sigma*sigma; // FEM tridiag matrix:
bm[i] =(hi+hi1)*(1./3 +dt*(m.x[i]*xss/hi/hi1+r)/2);
am[i] = hi/6 - dt*m.x[i]*(xss/hi - r)/2;
cm[i] = hi1/6- dt*m.x[i]*(xss/hi1 + r)/2;
}
for (int i=im; i<iM; i++)
uold[i] = u0(m.x[i]);
MPI_Barrier(MPI_COMM_WORLD);

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -57
CUDA
/ 118-op
La fonction principale (II)
for (int j=1; j<m.nT; j++) { \\ time loop
if(p!=0){
MPI_Send(&(uold[im]),1,MPI_DOUBLE, p-1,0, MPI_COMM_WORLD);
MPI_Recv(&(uold[im-1]),1,MPI_DOUBLE,p-1,0,MPI_COMM_WORLD,&s);
} if(p!=P-1){
MPI_Send(&(uold[iM-1]),1,MPI_DOUBLE, p+1,0, MPI_COMM_WORLD);
MPI_Recv(&(uold[iM]),1,MPI_DOUBLE,p+1,0,MPI_COMM_WORLD,&s);
}
for (int i=im1; i<iM1; i++) {
double hi = m.x[i]-m.x[i-1], hi1 = m.x[i+1]-m.x[i];
w[i]=(hi+hi1)*uold[i]/3+(hi*uold[i-1]+hi1*uold[i+1])/6;
}
u[m.nX-1]=0; u[0]=uold[0]*exp(-r*dt); // C.L.
double h1 = m.x[1]-m.x[0];
w[1]-=uold[0]*(h1/6-dt*m.x[1]*(m.x[1]*sigma*sigma/h1-r)/2);
MPI_Barrier(MPI_COMM_WORLD);
gradconj(am,bm,cm,w);
for (int i=im1; i<iM1; i++) uold[i]=w[i];
} MPI_Finalize(); }

Note: la récupération des résultats doit se faire par un MPI_Send bloc.


Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -58
CUDA
/ 118-op
Outline I
1 Leçon 1 : Architecture des machines
Principes
Les environnements de travail
Machines Parallèles
2 Leçon 2: architectures parallèles
Les logiciels
Un exemple facile a paralléliser
Le code C
3 Leçon 3: Parallélisation avec openMP
Principes de openMP
Exemples et syntaxes
Analyse de edostochOMP.c
Plus d’exemple et de mots clés en OpenMP
Exemple 2: EDP-1d en éléments finis
Discretisation par Elements Finis P 1
Parallélisation en OpenMP
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -59
CUDA
/ 118-op
Outline II
Le code vanilafem.c
4 Leçon 4: Message Passing Interface
Historique et résumé
Parallélisation mémoire distribuée en MPI
5 Leçon 5: UPC: Unified Parallel C
UPC de Berkeley
6 Leçon 6: Les GPU, CUDA et openCL
Historique
Portabilité: openCL
openCL sur Mac
7 Leçon 7: Les outils du calcul parallèle
le partitionneur Metis pour les Maillages non-structurées
Integration les compilateurs dans Eclipse
Bibliothèques pour le calcul parallèle
PetSc
8 Leçon 8: les algorithmes du calcul parallèle
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -60
CUDA
/ 118-op
Outline III
Méthodes de Schwarz
Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -61
CUDA
/ 118-op
Présentation de UPC

Proposé en 1999, UPC est dévelopé par un consortium dont Berkeley


fait partie. Berkeley Unified Parallel C compiler tourne sur les
principaux environnements. La compilation et l’exécution se font par:

upcc -pthreads hello.upc -o hello


upcrun -n 2 ./hello

Il reprend des idées de MPI mais simplifie enormément les


communications en introduisant la notion de shared variable.
L’installation de UPC est relativement facile sur un Mac-Intel, possible
sur un PC linux, difficile sur un PC-Windows, le plus simple etant pour
ce dernier d’installer un cygwin special contenant la librairie pthreads
et dispo sur le site UPC-Berkeley. Ce type de langage dit PGAS, est
un sujet de recherche important. Il existe d’autres tentatives comme
Church de CRAY research et CAF/Fortran ainsi que Titanium/Java.

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -62
CUDA
/ 118-op
Organisation mémoire

Le programme est recopié dans chaque proc, chaque variable est en


THREADS exemplaires sauf si elle est déclarée shared; dans ce ca elle est
par defaut sur la mémoire du process 0. Les shared array sont distribués:
#define N 1000
int i;
shared double x, y[N]
shared [2] double a[N];

Chaque proc accède a toute variable shared et connait son affinity. Si


THREADS=10, il y aura 10 instances de i, une seule de x et dans Thread0,
une seule de chaque y[i] mais y[0] dans Thread0...y[9] dans Threads9,
y[10] dans Thread0... a[0],a[1] sera dans Thread0, a[2],a[3] dans Thread1...
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -63
CUDA
/ 118-op
Exemple: addition de 2 vecteurs (I)

#define J 200000
#define N J*THREADS
shared double a[N], b[N];
shared double sum;

int main(){
int j;
double localSum=0;
for(j=0;j<J;j++){ a[j] =1; b[j] =1e-8;} // initialisation
for(j=0;j<J;j++)
localSum += a[j] + b[j] ;
sum += localSum; // not scalable
upc_barrier;
if(MYTHREAD==0)
printf("sum = %f \n", sum);
return 0;
}

Mais ce programme n’est pas scalable.


Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -64
CUDA
/ 118-op
Exemple: addition de 2 vecteurs (II)
On peut utiliser une fonction de la bibliothèque bupc
#include <bupc_collectivev.h>
#define J 200000
#define N J*THREADS
shared double a[N], b[N];

int main(){
int j;
double localSum=0;
for(j=0;j<J;j++){ a[j] =1; b[j] =1e-8;} // initialisation
for(j=0;j<J;j++)
localSum += a[j] + b[j] ;
upc_barrier;
double sum = bupc_allv_reduce(double, localSum, 0, UPC_ADD);
if(MYTHREAD==0)
printf("sum = %f \n", sum );
return 0;
}

Remarque: les perfs ne sont pas au rendez-vous!


Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -65
CUDA
/ 118-op
Exemple: addition de 2 vecteurs (III)
#include <bupc_collectivev.h>
#define J 100000
#define N J*THREADS
shared double a[N], b[N];
int main(){
int j;
double localSum=0;
// initialisation de a et b ici
upc_forall(j=0;j<N;j++;j)
localSum += a[j] + b[j] ;
double sum = bupc_allv_reduce(double, localSum, 0, UPC_ADD);
if(MYTHREAD==0) printf("sum = %f \n", sum );
return 0;
}
Le upc_forall est un “parallel for” où le dernier argument indique qui
fera l’opération. Ici l’affinité de i détermine le proc: comme i est local,
c’est lorsque le i de la boucle est egal au i local. On aurait pu écrire:
for(i=0;i<N;i++)
if(MYTHREAD==(i%THREADS)) localSum += a[j] + b[j] ;
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -66
CUDA
/ 118-op
Mesure du temps calcul
#include <sys/time.h> // file somme.upc
shared double runtimes[THREADS];
...
int main(){
struct timeval ts_st, ts_end;
gettimeofday( &ts_st, NULL );
... // the tasks e.g localSum += log(sin(a[j]))+cos(exp(b[j])) ;
gettimeofday( &ts_end, NULL );
runtimes[MYTHREAD] = ts_end.tv_sec-ts_st.tv_sec
+ (ts_end.tv_usec - ts_st.tv_usec) / 1000000.0;
if(MYTHREAD==0){
max_time = runtimes[0];
for( i=1; i<THREADS; i++ )
if( max_time < runtimes[i] ) max_time = runtimes[i];
printf("CPUtime=%f ", max_time);
} return 0;
}

sum = -4294967296000000.000000 CPUtime=0.410912 sur 1 proc


sum = -4294967296000000.000000 CPUtime=0.234346 sur 2 proc
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -67
CUDA
/ 118-op
Exemple: edostch.upc

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -68
CUDA
/ 118-op
Locks

Notez la séquence

shared double PT;


upc_lock_t* L= upc_lock_alloc();
...
upc_forall(...) {
upc_lock(L); PT += S; upc_unlock(L);
...
upc_lock_free(L);
}

Pour éviter que 2 process écrire PT exactement en même temps on


utilise un lock. Toutefois si PT est déclaré en strict shared
double alors les locks ne sont pas nécéssaires.
UPC est une direction pour l’avenir mais les compilo ne sont ni C++ ni
optimisés comme gcc

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -69
CUDA
/ 118-op
Exemple:vanilafem.upc (I)

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -70
CUDA
/ 118-op
Exemple: vanilafem.upc (II)

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -71
CUDA
/ 118-op
Exemple 2(0): vanilafem.upc

• L’ implémentation par sous domaine ci-dessous n’améliore pas


• UPC ne gère pas le C++
• Les "shared array" sont globaux (alloc dynamique possible)
• Utilisation des locks ralentit terriblement
• Le break sur un process dans le gradconj: que faire de l’autre?
• Performences très inégales: ici n=1: 0.89", n=2: 0.59"
• Les compilateurs n’étant pas optimisés il est très difficile de battre
gcc

Method gcc g++ OMP mpicc(2p) mpic++(2p) upc(2p)


clock() 0.04 0.017 1.8 0.19 0.65 0.59
full time 0.04 0.017 1.8 1.8 0.7 3.0

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -72
CUDA
/ 118-op
Exemple 2(I): vanilafem2.upc

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -73
CUDA
/ 118-op
Exemple 2(II): vanilafem2.upc

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -74
CUDA
/ 118-op
Exemple 2(III): vanilafem2.upc

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -75
CUDA
/ 118-op
Exemple 2(IV): vanilafem2.upc

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -76
CUDA
/ 118-op
Exemple 2(V): vanilafem2.upc

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -77
CUDA
/ 118-op
Exemple 2(V): vanilafem2.upc

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -78
CUDA
/ 118-op
Exercices pour le TD

1 Lancer edostoch.upc et étudier les perfs en fonctions du


nombre de proc
2 Vérifier que le programme vanilafem0.upc çi-dessus tourne
sur 1 proc et pas sur plus et chercher à comprendre pourquoi.
3 Mettre des directives UPC dans la fonction gradconj du
programme vanilafem0.upc pour obtenir de bonnes perfs et
des résultats justes en multi-proc.
4 Etudier les perf en fonction du nombre de proc

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -79
CUDA
/ 118-op
Outline I
1 Leçon 1 : Architecture des machines
Principes
Les environnements de travail
Machines Parallèles
2 Leçon 2: architectures parallèles
Les logiciels
Un exemple facile a paralléliser
Le code C
3 Leçon 3: Parallélisation avec openMP
Principes de openMP
Exemples et syntaxes
Analyse de edostochOMP.c
Plus d’exemple et de mots clés en OpenMP
Exemple 2: EDP-1d en éléments finis
Discretisation par Elements Finis P 1
Parallélisation en OpenMP
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -80
CUDA
/ 118-op
Outline II
Le code vanilafem.c
4 Leçon 4: Message Passing Interface
Historique et résumé
Parallélisation mémoire distribuée en MPI
5 Leçon 5: UPC: Unified Parallel C
UPC de Berkeley
6 Leçon 6: Les GPU, CUDA et openCL
Historique
Portabilité: openCL
openCL sur Mac
7 Leçon 7: Les outils du calcul parallèle
le partitionneur Metis pour les Maillages non-structurées
Integration les compilateurs dans Eclipse
Bibliothèques pour le calcul parallèle
PetSc
8 Leçon 8: les algorithmes du calcul parallèle
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -81
CUDA
/ 118-op
Outline III
Méthodes de Schwarz
Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -82
CUDA
/ 118-op
Graphic Processor Units

• Le marché du jeu video à induit une concurrence féroce entre les 2


grands constructeurs ATI et Nvidia.
• Le besoin de réalisme a obligé les concepteurs de jeux à revenir vers
les équations fondamentales de la physique pour la simulation, en
particulier pour l’eau et la fumée.
• Vers 2006 les unités de calcul élémentaires sont devenues capables
de calculer en virgule flottante: le GPGPU (general purpose graphic
processor unit).
• Des chercheurs comme Pat Hanrahan et Ian Buck (Stanford) ont
développé des langages dédiés comme brook, puis CUDA; le langage
OpenCL est un travail d’équipe (consortium Khronos).
• Intel nous prommet avec Larrabee un processeurs sur le principe
des GPGPU: 32 CPU avec des mémoires hiérarchiques et des
communications rapides.

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -83
CUDA
/ 118-op
Comparaison de performance sur edostoch.c

nb threads omp gcc4.4 MPI UPC CUDA CPU - GPU


1 0.9489 1.1388
2 0.5647 0.5150 0.5805
8 0.1547
10 0.1316
16 0.1412
32 0.0207 0.1602

CBLAS sur edpplain.cpp


clock count= 8242 sans optim
clock count= 7363 avec -O3 sans CBLAS
clock count= 3690 avec O3 et CBLAS

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -84
CUDA
/ 118-op
Le Modèle de mémoires de Nvidia (I)

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -85
CUDA
/ 118-op
Le Modèle de mémoires de Nvidia (II)

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -86
CUDA
/ 118-op
Le Modèle de mémoires de Nvidia (III)

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -87
CUDA
/ 118-op
Programmation en CUDA
Nous allons ecrire un priceur d’option put basé sur la formule
√ N
(r − 21 σ 2 )T +σ T N n (0,1) e−rT X
STn = S0 e , PT = (K − STn )+
N
n=1

Cette formule vient d’une solution analytique de l’EDS de


Black-Scholes pour St lorsque r et σ sont constants. Nous allons
utiliser la formule de Cox-Muller pour générer les réalisations N n de la
variable aléatoire gaussienne N :
p
N(0, 1) = −2 log(x) cos(2πy ), x, y aleatoires uniformes sur (0,1)
• x n , y n sont générées par random() dans le CPU et
• envoyées au GPU en recopiant deux tableaux A1,A2 en RAM dans
B1,B2, memoires de la carte graphique.
• Les 2 formules ci-dessous sont évaluées dans le GPU pour chaque
x n , y n de B1, B2 et
• le resultat est stocké dans B2 et renvoyé par recopié dans A2.
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -88
CUDA
/ 118-op
Edition-compilation-exécution

Le plus simple est d’utiliser un Mac avec une carte Nvidia. On peut
utiliser Xcode et meme Eclipse mais le plus simple est d’utiliser une
fenetre terminal.
Le site de Nvidia permet d’installer un binary tout pret dans
/usr/local/bin
Pour pointer sur le compilateur il faut faire export
PATH=/usr/local/cuda/bin:$PATH
export DYLD_LIBRARY_PATH
=/usr/local/cuda/lib:$DYLD_LIBRARY_PATH
Pour compiler il faut
nvcc -deviceemu BSCuda.cu
Pour lancer l’exécutable il faut ./a.out

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -89
CUDA
/ 118-op
Implémentation des formules (cf. BSCuda.cu)

BSgpu et BScpu appelle BS sur chaque éléments des tableaux.

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -90
CUDA
/ 118-op
Transfer du CPU au GPU

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -91
CUDA
/ 118-op
Calcul dans le GPU

Exécute BSgpu sur Nthreads=512 chacun prenant en charge


Nblocks=256 et copie les résultats dans A2
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -92
CUDA
/ 118-op
Portage de vanilafem.c sous CUDA avec cublas

Preambule
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -93
CUDA
/ 118-op
Multiplication Matrice Vector (cf. testcublas.cu)

Utilisation de cblas

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -94
CUDA
/ 118-op
Préparation de l’appel d’une fonction cublas

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -95
CUDA
/ 118-op
Appel de la fonction de cublas

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -96
CUDA
/ 118-op
Gradient Conjugué cublas

Malheureusement les perfs ne sont pas au rendez-vous,


essentiellement parce que ce qui est en dehors de cublas se fait dans
le CPU et implique des communications non gérées.
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -97
CUDA
/ 118-op
La méthode de Jacobi

En différences finies le probleme −u” = 1, u(0) = u(1) = 0 devient


Au = 1 ou A est une matrice tridiagonale d’éléments (−1, 2, −1)h−2 ,
où h est la taille du maillage. Jacobi, c’est itérer sur l’équation:

vi = (u i + 1 + ui−1 + h2 )/2, ∀i puis ui = vi ∀i

Gauss-Seidel rouge noir, cela consiste a faire

ui = (ui+1 + ui−1 + h2 )/2, ∀i pairs puis pour tout i impair


ui = (ui+1 + ui−1 + h2 )/2

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -98
CUDA
/ 118-op
Programmation en CUDA de la méthode de Jacobi (I)

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC -99
CUDA
/ 118-op
Programmation en CUDA de la méthode de Jacobi (II)

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC100
- CUDA
/ 118-op
openCL sur Mac OSX 10.6

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC101
- CUDA
/ 118-op
HMPP et CAPS Entreprise

Traduction automatique en CUDA, openCL...


Utiliser le concept de codelets:
"Codelet=function with no return and arguments which are const
input"
Ainsi peut on faire tourner le codelet sur n’importe quel proc.
Apple propose un concept similaire : le block (proposé au C++
standard). C’est la généralisation du pointeur sur une fonction.
Exemple:
FILE *fp = fopen(filename, "r");
if (fp == NULL) { perror("Unable to open file");} else {}
char line[MAX_LINE];
while (fgets(line, MAX_LINE, fp)) {work; work; work;}
fclose(fp);
... remplacer~ par
foreach_line(filename, ^(char* line) {work; work;});

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC102
- CUDA
/ 118-op
Exercices pour le TD sur CUDA

Faire tourner BScuda.cu et évaluer les performances en


changeant la tailles des blocs
Faire tourner jacobi.cu et comparer avec gauss.cu
Faire tourner vanilaFEMcuBLAS.cu
remplacer le gradient conjugué par un jacobi item Evaluer les
perfs de vanilaFEMcuBLAS avec CG et avec jacobi.

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC103
- CUDA
/ 118-op
Outline I
1 Leçon 1 : Architecture des machines
Principes
Les environnements de travail
Machines Parallèles
2 Leçon 2: architectures parallèles
Les logiciels
Un exemple facile a paralléliser
Le code C
3 Leçon 3: Parallélisation avec openMP
Principes de openMP
Exemples et syntaxes
Analyse de edostochOMP.c
Plus d’exemple et de mots clés en OpenMP
Exemple 2: EDP-1d en éléments finis
Discretisation par Elements Finis P 1
Parallélisation en OpenMP
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC104
- CUDA
/ 118-op
Outline II
Le code vanilafem.c
4 Leçon 4: Message Passing Interface
Historique et résumé
Parallélisation mémoire distribuée en MPI
5 Leçon 5: UPC: Unified Parallel C
UPC de Berkeley
6 Leçon 6: Les GPU, CUDA et openCL
Historique
Portabilité: openCL
openCL sur Mac
7 Leçon 7: Les outils du calcul parallèle
le partitionneur Metis pour les Maillages non-structurées
Integration les compilateurs dans Eclipse
Bibliothèques pour le calcul parallèle
PetSc
8 Leçon 8: les algorithmes du calcul parallèle
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC105
- CUDA
/ 118-op
Outline III
Méthodes de Schwarz
Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC106
- CUDA
/ 118-op
Metis pour les methodes de sous domaine

La bibliothèque METIS permet de partitionner un maillage en N partie.


Il suffit de l’installer à partir du site
www-users.cs.umn.edu/∼karypis/metis/metis/download.html
et d’invoquer la fonction partmesh, par exemple 4
./partmesh simpletest.txt 2 avec simpletest = 5

6 1 6
1 2 3 7
2 4 6
2 6 3 3
2
4 5 6
5 6 3
7 4 2
. 1

Le programme fournit en sortie deux fichiers de nom


simpletest.txt.epart.2 et simpletest.txt.npart.2

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC107
- CUDA
/ 118-op
Metis: contenu des fichiers simpletest.txt
4
5
0 1
epart npart 6
B 0 0 C 7
B C
B 0 0 C
B C
B 1 1 C 3
2
B C
B 1 0 C
B C
B 1 1 C
B C
@ 0 1 A
. 0 1

Le fichier simpletest.txt contient le nombre d’element et un entier


pour donner le type d’element (ici 1=triangles). Ensuite pour chaque
ligne il y a les 3 sommets du triangle correspondant a la ligne.
En sortie le fichier .npart.2 contient l’indice d’appartenance des
sommets aux sous domaines Ainsi le sommet 2 et sur le sous-domaine
de numero 0 alors que le sommet 2 appartient au sous domaine 1.
De meme le fichier .epart.2 donne les appartenances des triangles aux
sous-domaines et donc le triangle 3 appartient au sous-domaine 1.

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC108
- CUDA
/ 118-op
Eclipse et le calcul parallèle
Il faut installer les plug-ins PTP (Parallel Tools Plateform)
http://www.eclipse.org/ptp/docs/install.html (bien lire la doc)
openMP est dans gcc> 4.2, c.f. le plugin PTP
openMPI 1.2 est géré par eclipse/PTP mais il faut l’installer
(configure, make install, pas simple, marche pas sous cygwin)
Un plug-in UPC peut etre downloader pour PTP
http://wiki.eclipse.org/PTP/other_tools_setup

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC109
- CUDA
/ 118-op
PetSc

- Présentation
- Application a une méthode de sous-domaine avec gradient conjugué
- Une méthode de Scharwz

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC110
- CUDA
/ 118-op
Outline I
1 Leçon 1 : Architecture des machines
Principes
Les environnements de travail
Machines Parallèles
2 Leçon 2: architectures parallèles
Les logiciels
Un exemple facile a paralléliser
Le code C
3 Leçon 3: Parallélisation avec openMP
Principes de openMP
Exemples et syntaxes
Analyse de edostochOMP.c
Plus d’exemple et de mots clés en OpenMP
Exemple 2: EDP-1d en éléments finis
Discretisation par Elements Finis P 1
Parallélisation en OpenMP
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC111
- CUDA
/ 118-op
Outline II
Le code vanilafem.c
4 Leçon 4: Message Passing Interface
Historique et résumé
Parallélisation mémoire distribuée en MPI
5 Leçon 5: UPC: Unified Parallel C
UPC de Berkeley
6 Leçon 6: Les GPU, CUDA et openCL
Historique
Portabilité: openCL
openCL sur Mac
7 Leçon 7: Les outils du calcul parallèle
le partitionneur Metis pour les Maillages non-structurées
Integration les compilateurs dans Eclipse
Bibliothèques pour le calcul parallèle
PetSc
8 Leçon 8: les algorithmes du calcul parallèle
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC112
- CUDA
/ 118-op
Outline III
Méthodes de Schwarz
Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC113
- CUDA
/ 118-op
Méthode de Schwarz avec recouvrement

On décompose Ω = Ω1 ∪ Ω2 avec Ω1 ∩ Ω2 6= ∅:
1 Tant que |u1k − u2k |Ω1 ∩Ω2 > ,
2 calculer u1k +1 solution de l’EDP dans Ω1 avec u1k +1 = u2k sur Γ12
3 calculer u2k +1 solution de l’EDP dans Ω2 avec u2k +1 = u1k sur Γ21
4 dans Ω1 ∩ Ω2 set u k +1 = 12 [u1k +1 + u2k +1 ].

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC114
- CUDA
/ 118-op
Méthode de Schwarz sans recouvrement

1 Tant que |u1k − u2k |Ω1 ∩Ω2 > ,


2 calculer u1k +1 solution de l’EDP dans Ω1 avec u1k +1 = λk on Γ12 ;
3 calculer u2k +1 solution de l’EDP dans Ω2 avec u2k +1 = λk on Γ21 ;
k +1
4 Poser λk +1 = λk + θ[ ∂u∂n ].
Exercice Prendre Ω = (0, 1) et trouver le bon signe et la meilleure
formule pour θ.

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC115
- CUDA
/ 118-op
Méthode de Schur
Considerons le probleme d’algebre linéaire avec A ∈ Rn×n , b ∈ Rn :
Trouver x ∈ Rn tel que Ax = b
Soit une partition de A en 4 blocks A11 ∈ Rl×l , A12 ∈ Rl×(n−l) ,
A21 ∈ R(n−l)×l et A22 ∈ R(n−l)×(n−l) tel que:
 11
A12

A
A= .
A21 A22
Soit b1 le vecteur des l premiere entrées de b et b2 le reste et de
même pour x. On a:
 11
A12
  1  1
A x b
=
A21 A22 x2 b2
−1
Si (A11 )−1 existe, alors x 1 = (A11 ) (b1 − A12 x 2 ), et
−1 12 −1 1
(A22 − A21 (A11 ) A )x 2 = b2 − A21 (A11 ) b
−1 12
La matrice A22 − A21 (A11 ) A est le complément de Schur de A.
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC116
- CUDA
/ 118-op
Une Méthode lagrangienne (I) Principe

−∆u = f in Ω, u|Γ = 0

et une partition sans recouvrement: Ω = Ω1 ∪ Ω2 , Σ = Ω1 ∩ Ω2 ,


Ω1 ∩ Ω2 = ∅. Soit

∂u i
−∆u i = f in Ωi , u i |Γ = 0, |Σ = λ,
∂n
où nest une normale de Σ et où λ sera ajusté pour avoir u 1 = u 2 sur
Σ. Tout ceci se est équivalent à trouver
{u 1 , u 2 , λ} ∈ H 1 (Ω1 ) × H 1 (Ω2 ) × L2 (Σ) tel sque
i · ∇w dx + (−1)i 1
R R R
Ωi ∇u Σ λw = Ωi fw dx, ∀w ∈ H0 (Ω), i = 1, 2,
2 1 2
R
Σ (u − u )µ = 0, ∀µ ∈ L (Σ).

Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC117
- CUDA
/ 118-op
Implémentation
Prenons des éléments finis de degré 1 pour u et 0 pour λ:
Trouver uh ∈ H0h et λh ∈ Lh tels que
i dx + (−1)i Σh λh wh = Ωhi fwh dx, ∀w ∈ H0h ,
R R R
Ωhi ∇uh · ∇wh R
2 1
Σh (uh − uh )µh = 0, ∀µh ∈ Lh ,
Le système linéaire généré:
 11
0 B1
  1  1
A U b
 0 A22 B 2  U 2  = b2  .
B 1T B 2T 0 Λ 0
On note w i ∈ Hh et w̄ i ∈ L2 (Σ) les fonctions de base des 2 espaces,
U i les componsantes de uji et Λ = ((λk )). Alors
Z Z
kk i j k k
Aij = ∇w ∇w dx, Bij = (−1) w i w̄ j , k = 1, 2.
Ωhk Σh

La méthode de Schur est bien adaptée pour construire un système


linéaire en Λ par élimination de U.
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI
MPE- UPC118
- CUDA
/ 118-op

Vous aimerez peut-être aussi