Optimisation des performances et Parallélisme en C/C++ - openMP - MPI - UPC - CUDA -openCL
http://www.ann.jussieu.fr/pironneau
Olivier Pironneau1
1University of Paris VI, Laboratoire J.-L. Lions,Olivier.Pironneau@upmc.fr
Cours Mastère 2, Automne 2009
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 FinisP1 Parallélisation en OpenMP
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
Outline III
Méthodes de Schwarz Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint
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 dubusentre 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".
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.
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.
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];
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 fonctioncblas_daxpy(..) qui remplacey parαx+y.
Rappel: le gradient conjugué pour Ax=f (ou A estn×nsymmétrique) for (n=0;n<N;n+ +){
gn=Axn−f γ = |gn|2
|gn−1|2 hn=γhn−1−gn ρ= hn·gn
hn·Ahn xn=xn−1+ρhn }
CBLAS memento
Level1BLAS
dim scalar vector vector scalars 5-element array prexes
SUBROUTINE xROTG ( A, B, C, S ) Generate plane rotation S, D
SUBROUTINE xROTMG( D1, D2, A, B, PARAM ) Generate modied 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 modied 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 xTy S, D, DS
FUNCTION xDOTU ( N, X, INCX, Y, INCY ) dot xTy C, Z
FUNCTION xDOTC ( N, X, INCX, Y, INCY ) dot xHy C, Z
FUNCTION xxDOT ( N, X, INCX, Y, INCY ) dot + xTy 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 1stk3jre(xk)j+jim(xk)j S, D, C, Z
=max(jre(xi)j+jim(xi)j)
Level2BLAS
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 ATx + y;y AHx + y;A mn S, D, C, Z
xGBMV ( TRANS, M, N, KL, KU, ALPHA, A, LDA, X, INCX, BETA, Y, INCY ) y Ax + y;y ATx + y;y AHx + y;A mn 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 ATx;x AHx S, D, C, Z
xTBMV ( UPLO, TRANS, DIAG, N, K, A, LDA, X, INCX ) x Ax;x ATx;x AHx S, D, C, Z
xTPMV ( UPLO, TRANS, DIAG, N, AP, X, INCX ) x Ax;x ATx;x AHx S, D, C, Z
xTRSV ( UPLO, TRANS, DIAG, N, A, LDA, X, INCX ) x A1x;x ATx;x AHx S, D, C, Z
xTBSV ( UPLO, TRANS, DIAG, N, K, A, LDA, X, INCX ) x A1x;x ATx;x AHx S, D, C, Z
xTPSV ( UPLO, TRANS, DIAG, N, AP, X, INCX ) x A1x;x ATx;x AHx S, D, C, Z
options dim scalar vector vector matrix
xGER ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyT+A;A mn S, D
xGERU ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyT+A;A mn C, Z
xGERC ( M, N, ALPHA, X, INCX, Y, INCY, A, LDA ) A xyH+A;A mn 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
Level3BLAS
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;XT;XH;C mn S, D, C, Z
xSYMM ( SIDE, UPLO, M, N, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) C AB + C;C BA + C;C mn;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 mn;A = AH C, Z
xSYRK ( UPLO, TRANS, N, K, ALPHA, A, LDA, BETA, C, LDC ) C AAT+C;C ATA + C;C nn S, D, C, Z
xHERK ( UPLO, TRANS, N, K, ALPHA, A, LDA, BETA, C, LDC ) C AAH+C;C AHA + C;C nn C, Z
xSYR2K( UPLO, TRANS, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) C ABT+ BAT+C;C ATB + BTA + C;C nn S, D, C, Z
xHER2K( UPLO, TRANS, N, K, ALPHA, A, LDA, B, LDB, BETA, C, LDC ) C ABH+ BAH+C;C AHB + BHA + C;C nn 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 mn S, D, C, Z
xTRSM ( SIDE, UPLO, TRANSA, DIAG, M, N, ALPHA, A, LDA, B, LDB ) B op(A1)B;B Bop(A1);op(A) = A;AT;AH;B mn S, D, C, Z
2
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é aatlasetblitz(mais attention pour la suite) suredpblas.cpple cpu est divisé par 3!
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;
}
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];
} }
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 versionGalileode Eclipse C++, de-zipper et tester (voir plus bas).
Vous avez maintenant les outils pour le C++, l’openMP, le MPI.
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
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 debuggeurgdb
Permet de gérer des makefiles complexes (calcul // entre autre) Diminue le temps de développement
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) avecu(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...
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 FinisP1 Parallélisation en OpenMP
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
Outline III
Méthodes de Schwarz Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint
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!
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
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
Les outils Middleware (intergiciels!)
openMP
MPI (openMPI et MPICH2) Globus et mpich-G
upc-Berkeley, chapel CUDA, openCL
Exemple 1. Calcul d’une option en finance
Le sousjacentSt est modélisé par une EDO-S dSt =St(rdt+σdWt), S(0) =S0
Le put est calculé parP0=e−rTE(K−ST)+ La loi des grands nombres⇒ P0≈ e−rTM (K −STi )+ On utilise des différences finies et on simuledWt =√
dtN(0,1), Sm+1=Sm+δtSm(rδt+σ√
δtN(0,1)) N(0,1) =p
−2 logxcos(2πy)x,y aleatoires uniformes∈(0,1).
Le calcul desSTi est “embarrassingly parallel".
Voici le code C
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;
}
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.
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 FinisP1 Parallélisation en OpenMP
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
Outline III
Méthodes de Schwarz Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint
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
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 avecg++ -fopenmp hellomp.c -o hello(peut demanderexport PATH=/usr/local/bin:$PATH) resultat de ./hello: 0 5 1 6 2 7 3 8 4 9 CPUtime=0.000633Si dans eclipse il faut changer projet/properties/settings/linker
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
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 sascalabilité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.
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
edostochOMP.c I
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.
Produit Matrice Vecteur (Juvigny) I
Produit Matrice Vecteur (Juvigny) II
Produit Matrice Vecteur (Juvigny) III
Exercices pour le TD
1 Lanceredostochomp.cet étudier les perfs en fonctions de P
2 ChangerS[]en une seule variable et utiliserreduce; il faudra aussi utiliser la fonctionrand_r(state)qui, elle, est réentrante.
3 Lancerprog2.cpour comparer openMP et BLAS
4 Modifier le code pour utiliser openMP ET cblas.
5 Mettre des directives openMP dans le prgrammevanilafem.c çi-dessous.
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
Z L 0
um+1−um
δt w(x)dx + Z L
0
κ∂xum+1∂xw = Z L
0
fw ∀w ∈V :=H01(0,L) Discretisation en espace par éléments finis de degrés 1: on remplace V parVh, l’espace des fonctions continues affines par morceaux sur [0,L] =∪i[xi,xi+1]avecxi =ih,i=0..I-1, tel queIh=L. On obtient un système lineaire a chaque itération pourUm+1∈ RN:
B(Um+1−Um) +AUm+1=F ∈ RN, avecBij = 1
δt Z L
0
wiwjdx, Aij = Z L
0
κ∇wi∇wjdx oùwi est la fonction deVhqui vautδij enxj.
Equation de la chaleur: discretisation
Il est facile de voir queAetB sont tridiagonales avec Bii = 2h
δt, Bi,i−1=Bi,i+1= h
δt, Aii = 2κ
h , Ai,i−1=Ai,i+1=−κ h A priori le système tridiagonal pourUm+1is 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 thenu=0 atxm;u=0 atxM anyway but ifxMis 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.
Le code vanilafem.c (I)
Le code vanilafem.c (II)
Le code vanilafem.c (III)
Le code vanilafem.c (IV)
Le code vanilafem.c (V)
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 FinisP1 Parallélisation en OpenMP
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
Outline III
Méthodes de Schwarz Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint
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.
ApresMPI_init()et jusqu’aMPI_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.
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
Produit matrice vecteur
On exploite le fait queAest tridiagonal:
si{xi}iiM−1
m est dans un banc mémoirep
Axi =aixi−1+bixi+cixi+1demande la reception de xim−1et dexiM des bancs mémoiresp−1 etp+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];
}
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].
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);
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.
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 FinisP1 Parallélisation en OpenMP
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
Outline III
Méthodes de Schwarz Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint
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 deshared 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 Churchde CRAY research etCAF/Fortran ainsi queTitanium/Java.
Organisation mémoire
Le programme est recopié dans chaque proc, chaque variable est en
THREADS exemplaires sauf si elle est déclaréeshared; dans ce ca elle est par defaut sur la mémoire du process 0. Lesshared arraysont distribués:
#define N 1000 int i;
shared double x, y[N]
shared [2] double a[N];
Chaque proc accède a toute variablesharedet connait sonaffinity. Si THREADS=10, il y aura 10 instances dei,une seule dexet dans Thread0, une seule de chaquey[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...
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.
Exemple: addition de 2 vecteurs (II)
On peut utiliser une fonction de la bibliothèquebupc
#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!
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;
}
Leupc_forallest un “parallel for” où le dernier argument indique qui fera l’opération. Ici l’affinité deidétermine le proc: commei est local, c’est lorsque lei 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] ;
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
Exemple: edostch.upc
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é enstrict shared doublealors 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
Exemple:vanilafem.upc (I)
Exemple: vanilafem.upc (II)
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
Exemple 2(I): vanilafem2.upc
Exemple 2(II): vanilafem2.upc
Exemple 2(III): vanilafem2.upc
Exemple 2(IV): vanilafem2.upc
Exemple 2(V): vanilafem2.upc
Exemple 2(V): vanilafem2.upc
Exercices pour le TD
1 Lanceredostoch.upcet étudier les perfs en fonctions du nombre de proc
2 Vérifier que le programmevanilafem0.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
programmevanilafem0.upcpour obtenir de bonnes perfs et des résultats justes en multi-proc.
4 Etudier les perf en fonction du nombre de proc
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 FinisP1 Parallélisation en OpenMP
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
Outline III
Méthodes de Schwarz Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint
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 commebrook, puis CUDA; le langage OpenCL est un travail d’équipe (consortium Khronos).
•Intel nous prommet avecLarrabeeun processeurs sur le principe des GPGPU: 32 CPU avec des mémoires hiérarchiques et des communications rapides.
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
Le Modèle de mémoires de Nvidia (I)
Le Modèle de mémoires de Nvidia (II)
Le Modèle de mémoires de Nvidia (III)
Programmation en CUDA
Nous allons ecrire un priceur d’option put basé sur la formule
STn =S0e(r−12σ2)T+σ
√T Nn(0,1), PT = e−rT N
N
X
n=1
(K −STn)+
Cette formule vient d’une solution analytique de l’EDS de
Black-Scholes pourSt lorsquer etσ sont constants. Nous allons utiliser la formule de Cox-Muller pour générer les réalisationsNnde la variable aléatoire gaussienneN :
N(0,1) =p
−2 log(x)cos(2πy), x,y aleatoires uniformes sur (0,1)
•xn,ynsont générées parrandom()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,yndeB1,B2 et
•le resultat est stocké dans B2 et renvoyé par recopié dans A2.
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 faireexport 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
Implémentation des formules (cf. BSCuda.cu)
BSgpu et BScpu appelle BS sur chaque éléments des tableaux.
Transfer du CPU au GPU
Calcul dans le GPU
Exécute BSgpu sur Nthreads=512 chacun prenant en charge Nblocks=256 et copie les résultats dans A2
Portage de vanilafem.c sous CUDA avec cublas
Preambule
Multiplication Matrice Vector (cf. testcublas.cu)
Utilisation de cblas
Préparation de l’appel d’une fonction cublas
Appel de la fonction de cublas
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.
La méthode de Jacobi
En différences finies le probleme−u” =1, u(0) =u(1) =0 devient Au=1 ouAest une matrice tridiagonale d’éléments(−1,2,−1)h−2, oùhest la taille du maillage. Jacobi, c’est itérer sur l’équation:
vi = (ui+1+ui−1+h2)/2, ∀ipuisui =vi ∀i
Gauss-Seidel rouge noir, cela consiste a faire
ui = (ui+1+ui−1+h2)/2, ∀ipairs puis pour tout i impair ui = (ui+1+ui−1+h2)/2
Programmation en CUDA de la méthode de Jacobi (I)
Programmation en CUDA de la méthode de Jacobi (II)
openCL sur Mac OSX 10.6
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;});
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.
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 FinisP1 Parallélisation en OpenMP
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
Outline III
Méthodes de Schwarz Méthode de Schur
Méthodes Lagrangienne et Mortier-Joint
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 fonctionpartmesh, 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.2etsimpletest.txt.npart.2