optimisation des performances et parallélisme en c/c++

118
Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCL http://www.ann.jussieu.fr/pironneau Olivier Pironneau 1 1 University of Paris VI, Laboratoire J.-L. Lions, [email protected] Cours Mastère 2, Automne 2009 Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -op MPE 1 / 118

Upload: others

Post on 29-Mar-2022

4 views

Category:

Documents


0 download

TRANSCRIPT

Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCL - http://www.ann.jussieu.fr/pironneauOptimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCL
http://www.ann.jussieu.fr/pironneau
Cours Mastère 2, Automne 2009
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 1 / 118
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 P1
Parallélisation en OpenMP Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 2 / 118
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 - UPC - CUDA -openCLMPE 3 / 118
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 - UPC - CUDA -openCLMPE 4 / 118
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 - UPC - CUDA -openCLMPE 5 / 118
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 - UPC - CUDA -openCLMPE 6 / 118
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 - UPC - CUDA -openCLMPE 7 / 118
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 - UPC - CUDA -openCLMPE 8 / 118
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 + +){ gn = Axn − f
γ = |gn|2
ρ = hn · gn
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 9 / 118
CBLAS mementoLevel 1 BLAS dim scalar vector vector scalars 5-element array prexesSUBROUTINE xROTG ( A, B, C, S ) Generate plane rotation S, DSUBROUTINE xROTMG( D1, D2, A, B, PARAM ) Generate modied plane rotation S, DSUBROUTINE xROT ( N, X, INCX, Y, INCY, C, S ) Apply plane rotation S, DSUBROUTINE xROTM ( N, X, INCX, Y, INCY, PARAM ) Apply modied plane rotation S, DSUBROUTINE xSWAP ( N, X, INCX, Y, INCY ) x$ y S, D, C, ZSUBROUTINE xSCAL ( N, ALPHA, X, INCX ) x x S, D, C, Z, CS, ZDSUBROUTINE xCOPY ( N, X, INCX, Y, INCY ) y x S, D, C, ZSUBROUTINE xAXPY ( N, ALPHA, X, INCX, Y, INCY ) y x+ y S, D, C, ZFUNCTION xDOT ( N, X, INCX, Y, INCY ) dot xT y S, D, DSFUNCTION xDOTU ( N, X, INCX, Y, INCY ) dot xT y C, ZFUNCTION xDOTC ( N, X, INCX, Y, INCY ) dot xHy C, ZFUNCTION xxDOT ( N, X, INCX, Y, INCY ) dot + xT y SDSFUNCTION xNRM2 ( N, X, INCX ) nrm2 jjxjj2 S, D, SC, DZFUNCTION xASUM ( N, X, INCX ) asum jjre(x)jj1 + jjim(x)jj1 S, D, SC, DZFUNCTION IxAMAX( N, X, INCX ) amax 1stk 3 jre(xk)j+ jim(xk)j S, D, C, Z= max(jre(xi)j+ jim(xi)j)Level 2 BLASoptions dim b-width scalar matrix vector scalar vectorxGEMV ( TRANS, M, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax+ y; y AT x+ y; y AHx+ y;Am n S, D, C, ZxGBMV ( TRANS, M, N, KL, KU, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax+ y; y AT x+ y; y AHx+ y;Am n S, D, C, ZxHEMV ( UPLO, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax+ y C, ZxHBMV ( UPLO, N, K, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax+ y C, ZxHPMV ( UPLO, N, ALPHA, AP, X, INCX, BETA, Y, INCY ) y Ax+ y C, ZxSYMV ( UPLO, N, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax+ y S, DxSBMV ( UPLO, N, K, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax+ y S, DxSPMV ( UPLO, N, ALPHA, AP, X, INCX, BETA, Y, INCY ) y Ax+ y S, DxTRMV ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) x Ax; x AT x; x AHx S, D, C, ZxTBMV ( UPLO, TRANS, DIAG, N, K, A, LDA, X, INCX ) x Ax; x AT x; x AHx S, D, C, ZxTPMV ( UPLO, TRANS, DIAG, N, AP, X, INCX ) x Ax; x AT x; x AHx S, D, C, ZxTRSV ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) x A1x; x ATx; x AHx S, D, C, ZxTBSV ( UPLO, TRANS, DIAG, N, K, A, LDA, X, INCX ) x A1x; x ATx; x AHx S, D, C, ZxTPSV ( UPLO, TRANS, DIAG, N, AP, X, INCX ) x A1x; x ATx; x AHx S, D, C, Zoptions dim scalar vector vector matrixxGER ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyT +A;Am n S, DxGERU ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyT +A;Am n C, ZxGERC ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyH +A;Am n C, ZxHER ( UPLO, N, ALPHA, X, INCX, A, LDA ) A xxH + A C, ZxHPR ( UPLO, N, ALPHA, X, INCX, AP ) A xxH + A C, ZxHER2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyH + y(x)H +A C, ZxHPR2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, AP ) A xyH + y(x)H +A C, ZxSYR ( UPLO, N, ALPHA, X, INCX, A, LDA ) A xxT + A S, DxSPR ( UPLO, N, ALPHA, X, INCX, AP ) A xxT + A S, DxSYR2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyT + yxT +A S, DxSPR2 ( UPLO, N, ALPHA, X, INCX, Y, INCY, AP ) A xyT + yxT +A S, DLevel 3 BLASoptions dim scalar matrix matrix scalar matrixxGEMM ( TRANSA, TRANSB, M, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) C op(A)op(B) + C; op(X) = X;XT ;XH ; C m n S, D, C, ZxSYMM ( 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, ZxHEMM ( SIDE, UPLO, M, N, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) C AB + C;C BA + C;C m n;A = AH C, ZxSYRK ( UPLO, TRANS, N, K, ALPHA, A, LDA, BETA, C, LDC ) C AAT + C;C ATA+ C;C n n S, D, C, ZxHERK ( UPLO, TRANS, N, K, ALPHA, A, LDA, BETA, C, LDC ) C AAH + C;C AHA+ C;C n n C, ZxSYR2K( UPLO, TRANS, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) C ABT + BAT + C;C ATB + BTA+ C;C n n S, D, C, ZxHER2K( UPLO, TRANS, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) C ABH + BAH + C;C AHB + BHA+ C;C n n C, ZxTRMM ( 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, ZxTRSM ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA, B, LDB ) B op(A1)B;B Bop(A1); op(A) = A;AT ; AH ; B m n S, D, C, Z2 Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 10 / 118
CBLAS
}
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 - UPC - CUDA -openCLMPE 11 / 118
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 - UPC - CUDA -openCLMPE 12 / 118
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++) {
} }
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 13 / 118
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 - UPC - CUDA -openCLMPE 14 / 118
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 - UPC - CUDA -openCLMPE 15 / 118
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 - UPC - CUDA -openCLMPE 16 / 118
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 - UPC - CUDA -openCLMPE 17 / 118
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 return 0;}
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 18 / 118
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 P1
Parallélisation en OpenMP Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 19 / 118
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 - UPC - CUDA -openCLMPE 20 / 118
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 - UPC - CUDA -openCLMPE 21 / 118
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 - UPC - CUDA -openCLMPE 22 / 118
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 - UPC - CUDA -openCLMPE 23 / 118
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 - UPC - CUDA -openCLMPE 24 / 118
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 - UPC - CUDA -openCLMPE 25 / 118
Exemple 1. Calcul d’une option en finance
Le sousjacent St est modélisé par une EDO-S
dSt = St (rdt + σdWt ), S(0) = S0
Le put est calculé par P0 = e−rT E(K − ST )+
La loi des grands nombres⇒ P0 ≈ e−rT
M (K − Si T )+
dtN (0,1),
N (0,1) = √ −2 log x cos(2πy) x,y aleatoires uniformes ∈ (0,1).
Le calcul des Si T est “embarrassingly parallel".
Voici le code C
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 26 / 118
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 - UPC - CUDA -openCLMPE 27 / 118
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;
}
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 - UPC - CUDA -openCLMPE 28 / 118
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 P1
Parallélisation en OpenMP Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 29 / 118
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 - UPC - CUDA -openCLMPE 30 / 118
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 - UPC - CUDA -openCLMPE 31 / 118
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 - UPC - CUDA -openCLMPE 32 / 118
Hello world
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 - UPC - CUDA -openCLMPE 33 / 118
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 - UPC - CUDA -openCLMPE 34 / 118
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 - UPC - CUDA -openCLMPE 35 / 118
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 - UPC - CUDA -openCLMPE 36 / 118
edostochOMP.c I
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 37 / 118
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 - UPC - CUDA -openCLMPE 38 / 118
Produit Matrice Vecteur (Juvigny) I
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 39 / 118
Produit Matrice Vecteur (Juvigny) II
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 40 / 118
Produit Matrice Vecteur (Juvigny) III
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 41 / 118
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 - UPC - CUDA -openCLMPE 42 / 118
Equation de la chaleur
∂tu − ∂x (κ∂xu) = f , u(0, t) = u(L, t) = 0, u(x ,0) = u0(x) ∀x , t ∈ (0,L)× (0,T )
Formulation variationnelle et differences finies en temps∫ L
0
∫ L
0 (0,L)
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 Um+1 ∈ RN :
B(Um+1 − Um) + AUm+1 = F ∈ RN ,
avec Bij = 1 δt
∫ L
0 κ∇w i∇w jdx
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 - UPC - CUDA -openCLMPE 43 / 118
Equation de la chaleur: discretisation
Il est facile de voir que A et B sont tridiagonales avec
Bii = 2h δt , Bi,i−1 = Bi,i+1 =
h δt , Aii =
h
A priori le système tridiagonal pourUm+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:
∂tu + ru − rx∂xu − σ2x2
2 ∂xxu = 0, u(t = 0) = max(K − x ,0)
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 - UPC - CUDA -openCLMPE 44 / 118
Le code vanilafem.c (I)
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 45 / 118
Le code vanilafem.c (II)
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 46 / 118
Le code vanilafem.c (III)
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 47 / 118
Le code vanilafem.c (IV)
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 48 / 118
Le code vanilafem.c (V)
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 49 / 118
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 P1
Parallélisation en OpenMP Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 50 / 118
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 - UPC - CUDA -openCLMPE 51 / 118
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 - UPC - CUDA -openCLMPE 52 / 118
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 - UPC - CUDA -openCLMPE 53 / 118
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 - UPC - CUDA -openCLMPE 54 / 118
Produit matrice vecteur
On exploite le fait que A est tridiagonal: si {xi}iM−1
im est dans un banc mémoire p Axi = aixi−1 + bixi + cixi+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,Vector& Ax) { 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 - UPC - CUDA -openCLMPE 55 / 118
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.
}
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 - UPC - CUDA -openCLMPE 56 / 118
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 - UPC - CUDA -openCLMPE 57 / 118
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 - UPC - CUDA -openCLMPE 58 / 118
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 P1
Parallélisation en OpenMP Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 59 / 118
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 - UPC - CUDA -openCLMPE 60 / 118
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 - UPC - CUDA -openCLMPE 61 / 118
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 - UPC - CUDA -openCLMPE 62 / 118
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 - UPC - CUDA -openCLMPE 63 / 118
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 - UPC - CUDA -openCLMPE 64 / 118
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 - UPC - CUDA -openCLMPE 65 / 118
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)
}
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 - UPC - CUDA -openCLMPE 66 / 118
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; }
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 67 / 118
Exemple: edostch.upc
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 68 / 118
Locks
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 - UPC - CUDA -openCLMPE 69 / 118
Exemple:vanilafem.upc (I)
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 70 / 118
Exemple: vanilafem.upc (II)
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 71 / 118
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 - UPC - CUDA -openCLMPE 72 / 118
Exemple 2(I): vanilafem2.upc
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 73 / 118
Exemple 2(II): vanilafem2.upc
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 74 / 118
Exemple 2(III): vanilafem2.upc
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 75 / 118
Exemple 2(IV): vanilafem2.upc
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 76 / 118
Exemple 2(V): vanilafem2.upc
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 77 / 118
Exemple 2(V): vanilafem2.upc
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 78 / 118
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 - UPC - CUDA -openCLMPE 79 / 118
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 P1
Parallélisation en OpenMP Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 80 / 118
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 - UPC - CUDA -openCLMPE 81 / 118
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 - UPC - CUDA -openCLMPE 82 / 118
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 - UPC - CUDA -openCLMPE 83 / 118
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 - UPC - CUDA -openCLMPE 84 / 118
Le Modèle de mémoires de Nvidia (I)
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 85 / 118
Le Modèle de mémoires de Nvidia (II)
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 86 / 118
Le Modèle de mémoires de Nvidia (III)
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 87 / 118
Programmation en CUDA
Nous allons ecrire un priceur d’option put basé sur la formule
Sn T = S0e(r− 1
N∑ n=1
(K − Sn T )+
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 Nn de la variable aléatoire gaussienne N :
N(0,1) = √ −2 log(x) cos(2πy), x , y aleatoires uniformes sur (0,1)
• xn, yn 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 xn, yn 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 - UPC - CUDA -openCLMPE 88 / 118
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
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 89 / 118
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 - UPC - CUDA -openCLMPE 90 / 118
Transfer du CPU au GPU
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 91 / 118
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 - UPC - CUDA -openCLMPE 92 / 118
Portage de vanilafem.c sous CUDA avec cublas
Preambule Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 93 / 118
Multiplication Matrice Vector (cf. testcublas.cu)
Utilisation de cblas
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 94 / 118
Préparation de l’appel d’une fonction cublas
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 95 / 118
Appel de la fonction de cublas
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 96 / 118
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 - UPC - CUDA -openCLMPE 97 / 118
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 = (ui + 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 - UPC - CUDA -openCLMPE 98 / 118
Programmation en CUDA de la méthode de Jacobi (I)
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 99 / 118
Programmation en CUDA de la méthode de Jacobi (II)
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 100 / 118
openCL sur Mac OSX 10.6
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 101 / 118
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 - UPC - CUDA -openCLMPE 102 / 118
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 - UPC - CUDA -openCLMPE 103 / 118
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 P1
Parallélisation en OpenMP Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 104 / 118
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 - UPC - CUDA -openCLMPE 105 / 118
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 - UPC - CUDA -openCLMPE 106 / 118
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 ./partmesh simpletest.txt 2 avec simpletest =
6 1 1 2 3 2 4 6 2 6 3 4 5 6 5 6 3 7 4 2 . 1
3
5
6
4
7
2
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 - UPC - CUDA -openCLMPE 107 / 118
Metis: contenu des fichiers simpletest.txt
0BBBBBBBBBB@
epart npart 0 0 0 0 1 1 1 0 1 1 0 1
0
3
5
6
4
7
2
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 - UPC - CUDA -openCLMPE 108 / 118
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 - UPC - CUDA -openCLMPE 109 / 118
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 - UPC - CUDA -openCLMPE 110 / 118
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 P1
Parallélisation en OpenMP Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 111 / 118
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 - UPC - CUDA -openCLMPE 112 / 118
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 - UPC - CUDA -openCLMPE 113 / 118
Méthode de Schwarz avec recouvrement
On décompose = 1 ∪ 2 avec 1 ∩ 2 6= ∅: 1 Tant que |uk
1 − uk 2 |1∩2 > ε,
2 calculer uk+1 1 solution de l’EDP dans 1 avec uk+1
1 = uk 2 sur Γ12
3 calculer uk+1 2 solution de l’EDP dans 2 avec uk+1
2 = uk 1 sur Γ21
4 dans 1 ∩ 2 set uk+1 = 1 2 [uk+1
1 + uk+1 2 ].
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 114 / 118
Méthode de Schwarz sans recouvrement
1 Tant que |uk 1 − uk
2 |1∩2 > ε,
2 calculer uk+1 1 solution de l’EDP dans 1 avec uk+1
1 = λk on Γ12; 3 calculer uk+1
2 solution de l’EDP dans 2 avec uk+1 2 = λk on Γ21;
4 Poser λk+1 = λk + θ[∂uk+1
∂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 - UPC - CUDA -openCLMPE 115 / 118
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:
A =
) .
Soit b1le vecteur des l premiere entrées de b et b2 le reste et de même pour x . On a:(
A11 A12
A21 A22
−1 (b1 − A12x2), et
b1
La matrice A22 − A21(A11) −1A12 est le complément de Schur de A.
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 116 / 118
Une Méthode lagrangienne (I) Principe
−u = f in , u|Γ = 0
et une partition sans recouvrement: = 1 ∪ 2, Σ = 1 ∩ 2, 1 ∩ 2 = ∅. Soit
−ui = f in i , ui |Γ = 0, ∂ui
∂n |Σ = λ,
où nest une normale de Σ et où λ sera ajusté pour avoir u1 = u2 sur Σ. Tout ceci se est équivalent à trouver {u1,u2, λ} ∈ H1(1)× H1(2)× L2(Σ) tel sque∫
i ∇ui · ∇w dx + (−1)i ∫
Σ λw = ∫
0 (), i = 1,2,∫ Σ(u2 − u1)µ = 0, ∀µ ∈ L2(Σ).
Olivier Pironneau (LJLL) Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCLMPE 117 / 118
Implémentation
Prenons des éléments finis de degré 1 pour u et 0 pour λ: Trouver uh ∈ H0h et λh ∈ Lh tels que∫
hi ∇ui
∫ hi
0 A22 B2
B1T B2T 0
.
On note w i ∈ Hh et w i ∈ L2(Σ) les fonctions de base des 2 espaces, U i les componsantes de ui
j et Λ = ((λk )). Alors
Akk ij =
∫ Σh
w iw j , k = 1,2.
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 - UPC - CUDA -openCLMPE 118 / 118
Leçon 1 : Architecture des machines
Principes
Le code C
Principes de openMP
Exemples et syntaxes
Analyse de edostochOMP.c
Exemple 2: EDP-1d en éléments finis
Discretisation par Elements Finis P1
Parallélisation en OpenMP
Le code vanilafem.c
Historique et résumé
Leçon 5: UPC: Unified Parallel C
UPC de Berkeley
Historique
Integration les compilateurs dans Eclipse
Bibliothèques pour le calcul parallèle
PetSc
Méthodes de Schwarz
Méthode de Schur