07.01.2013 Views

Le calcul numérique de haute performance - Université de Laval

Le calcul numérique de haute performance - Université de Laval

Le calcul numérique de haute performance - Université de Laval

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Le</strong> <strong>calcul</strong> <strong>numérique</strong> <strong>de</strong> <strong>haute</strong> <strong>performance</strong><br />

en astrophysique<br />

Hugo Martel<br />

<strong>Université</strong> <strong>Laval</strong><br />

Québec, 31 août 2007


1) Introduction<br />

<strong>Le</strong> <strong>calcul</strong> <strong>de</strong> <strong>haute</strong> <strong>performance</strong> (CHP) s’est développé selon 3 axes:<br />

1) Résolution (nombre <strong>de</strong> particules N)<br />

2) Précision <strong>de</strong>s algorithmes<br />

3) Détails <strong>de</strong>s processus physiques<br />

précision<br />

P 3 M<br />

PM<br />

Arbre + Quad<br />

512 3<br />

64 3<br />

1000<br />

Arbre<br />

résolution<br />

2048 3<br />

256 3<br />

32 3 (1985)<br />

50<br />

Gravité<br />

Hydrodynamique Transfer radiatif<br />

Réactions<br />

chimiques<br />

Relativité<br />

physique


À partir <strong>de</strong> quand un <strong>calcul</strong> <strong>de</strong>vient “<strong>haute</strong> <strong>performance</strong>” ?<br />

Réponse: à partir du moment où il est dans notre intérêt<br />

d’optimiser le programme.<br />

Exemple: Supposons qu’en travaillant pendant 1 mois sur<br />

l’optimisation d’un programme, on peut quadrupler sa vitesse<br />

d’exécution.<br />

• Temps d’exécution <strong>de</strong> une minute: on investi 1 mois <strong>de</strong> travail<br />

pour sauver 45 secon<strong>de</strong>s: ça ne vaut pas la peine.<br />

• Temps d’exécution <strong>de</strong> 2 ans: on investi 1 mois <strong>de</strong> travail pour<br />

sauver 18 mois: ça vaut la peine.<br />

L’optimisation est le concept fondamental du CHP<br />

optimisation <strong>performance</strong><br />

Langage <strong>de</strong> programation: FORTRAN<br />

3 types d’architectures: • Ordinateurs sériels<br />

• Ordinateurs vectoriels<br />

• Ordinateurs parallèles


2) Ordinateurs sériels<br />

Tous les ordinateurs datant d’avant 1980.<br />

Tous les ordinateurs portables.<br />

Toutes les stations <strong>de</strong> travail.<br />

En gros, tous les ordinateurs qu’on n’appelle pas “superordinateur”.<br />

Ordinateur sériel: <strong>Le</strong>s instructions sont exécutées en série (une à la fois).


Exemple concret: <strong>calcul</strong> <strong>de</strong> la correction à courte distance dans l’algorithme P 3 M<br />

�(r) =<br />

Volume cubique contenant N particules.<br />

On i<strong>de</strong>ntifie les paires <strong>de</strong> particules séparées<br />

par une courte distance r < 2.8� (particules<br />

voisines).<br />

Pour chaque paire <strong>de</strong> particules, on <strong>calcul</strong>e<br />

la fonction �(r).<br />

� est la longeur d’adoucissement.<br />

�(224x�224x 3 +70x 4 +48x 5 �21x 6 )/35� 2 , x < 1;<br />

�(12/x 2 �224+896x�840x 2 +224x 3 +70x 4 �48x 5 +7x 6 )/35� 2 , 1 < x < 2;<br />

�1/r 2 , x > 2.<br />

où x = 2r/�


subroutine shortrange(r,pairs,src,npairs,nmax,np)<br />

integer pairs(nmax,2)<br />

dimension src(nmax), r(np,3)<br />

do m=1,npairs<br />

i=pairs(m,1)<br />

j=pairs(m,2)<br />

dx=r(i,1)-r(j,1)<br />

dy=r(i,2)-r(j,2)<br />

dz=r(i,3)-r(j,3)<br />

r2=dx*dx+dy*dy+dz*dz<br />

r=sqrt(r2)<br />

src(m)=CHI(r)<br />

enddo<br />

return<br />

end<br />

*--------------------------------------------------------------function<br />

chi(r)<br />

parameter (epsilon=0.00001)<br />

c1=-1./(35.*epsilon*epsilon)<br />

x=2*r/epsilon<br />

if(x.lt.1.) then<br />

chi=c1*x*(224.+x*x*(-224.+x*(70.+x*(48.-21.*x))))<br />

else if(x.lt.2.) then<br />

chi=c1*(12.+x*x*(-224.+x*(896.+x*(-840.+x*(224.+x*<br />

+ (70.+x*(-48.+7.*x)))))))/x/x<br />

else<br />

chi=-1./r**2<br />

endif<br />

return<br />

end


chi(0:npt)<br />

0<br />

1<br />

2<br />

3<br />

4<br />

5<br />

6<br />

7<br />

8<br />

9<br />

npt<br />

�(0)<br />

�(�r)<br />

�(2�r)<br />

�(3�r)<br />

�(4�r)<br />

�(5�r)<br />

�(6�r)<br />

�(7�r)<br />

�(8�r)<br />

�(9�r)<br />

...<br />

�(npt*�r)<br />

Table d’interpolation pour �(r)<br />

chi(k+1)<br />

chi(k)<br />

�<br />

c = (r � k�r) / �r<br />

� = (1 � c) chi(k) + c chi(k+1)<br />

k�r r (k+1)�r<br />

d = r / �r<br />

k = int(d), c = frac(d)


subroutine shortrange(r,pairs,src,npairs,nmax,np)<br />

parameter (npt=10000)<br />

integer pairs(nmax,2)<br />

dimension src(nmax), r(np,3)<br />

common /short/ chi(0:npt), dr<br />

do m=1,npairs<br />

i=pairs(m,1)<br />

j=pairs(m,2)<br />

dx=r(i,1)-r(j,1)<br />

dy=r(i,2)-r(j,2)<br />

dz=r(i,3)-r(j,3)<br />

r2=dx*dx+dy*dy+dz*dz<br />

r=sqrt(r2)<br />

d=r/dr<br />

k=int(d)<br />

c=d-k<br />

src(m)=(1.-c)*chi(k)+c*chi(k+1)<br />

enddo<br />

return<br />

end<br />

+ + � � �


� = (1 � c) chi(k) + c chi(k+1)<br />

� = chi(k) + c [ chi(k+1) � chi(k) ]<br />

� = chi(k) + c �chi(k)<br />

où: �chi(k) = chi(k+1) � chi(k)<br />

chi(0:npt)<br />

0<br />

1<br />

2<br />

3<br />

4<br />

5<br />

6<br />

7<br />

8<br />

9<br />

npt<br />

�(0)<br />

�(�r)<br />

�(2�r)<br />

�(3�r)<br />

�(4�r)<br />

�(5�r)<br />

�(6�r)<br />

�(7�r)<br />

�(8�r)<br />

�(9�r)<br />

...<br />

�(npt*�r)<br />

0<br />

1<br />

2<br />

3<br />

4<br />

5<br />

6<br />

7<br />

8<br />

9<br />

npt-1<br />

dchi(0:npt-1)<br />

�(�r)��(0)<br />

�(2�r)��(�r)<br />

�(3�r)��(2�r)<br />

�(4�r)��(3�r)<br />

�(5�r)��(4�r)<br />

�(6�r)��(5�r)<br />

�(7�r)-�(6�r)<br />

�(8�r)��(7�r)<br />

�(9�r)��(8�r)<br />

�(10�r)��(9�r)<br />

...<br />

�(npt*�r)-�[(npt-1)*�r]


subroutine shortrange(r,pairs,src,npairs,nmax,np)<br />

parameter (npt=10000)<br />

integer pairs(nmax,2)<br />

dimension src(nmax), r(np,3)<br />

common /short/ chi(0:npt), dchi(0:npt-1), dr<br />

do m=1,npairs<br />

i=pairs(m,1)<br />

j=pairs(m,2)<br />

dx=r(i,1)-r(j,1)<br />

dy=r(i,2)-r(j,2)<br />

dz=r(i,3)-r(j,3)<br />

r2=dx*dx+dy*dy+dz*dz<br />

r=sqrt(r2)<br />

d=r/dr<br />

k=int(d)<br />

c=d-k<br />

src(m)=chi(k)+c*dchi(k)<br />

enddo<br />

return<br />

end<br />

+ + �


subroutine shortrange(r,pairs,src,npairs,nmax,np)<br />

parameter (npt=10000)<br />

integer pairs(nmax,2)<br />

dimension src(nmax), r(np,3)<br />

common /short/ chi(0:npt), dchi(0:npt-1), dr<br />

do m=1,npairs<br />

i=pairs(m,1)<br />

j=pairs(m,2)<br />

dx=r(i,1)-r(j,1)<br />

dy=r(i,2)-r(j,2)<br />

dz=r(i,3)-r(j,3)<br />

r2=dx*dx+dy*dy+dz*dz<br />

r=sqrt(r2)<br />

d=r/dr<br />

k=int(d)<br />

c=d-k<br />

src(m)=chi(k)+c*dchi(k)<br />

enddo<br />

return<br />

end<br />

+ + + +<br />

- � � �<br />

� � � �<br />

/<br />

int()<br />

sqrt()


Une racine carrée est 10 à 20 fois plus<br />

longue à <strong>calcul</strong>er qu’une addition ou une<br />

multiplication.<br />

Solution: considérer la fonction � comme<br />

étant une fonction <strong>de</strong> r 2 plutôt que r.<br />

On crée <strong>de</strong> nouvelles tables d’interpolation<br />

dans lesquelles la fonction est évaluée à<br />

<strong>de</strong>s intervalles constants en r 2 .<br />

Nouvel incrément: �r 2<br />

chi(0:npt)<br />

0<br />

1<br />

2<br />

3<br />

4<br />

5<br />

6<br />

7<br />

8<br />

9<br />

npt<br />

�(0)<br />

�(�r 2 )<br />

�(2�r 2 )<br />

�(3�r 2 )<br />

�(4�r 2 )<br />

�(5�r 2 )<br />

�(6�r 2 )<br />

�(7�r 2 )<br />

�(8�r 2 )<br />

�(9�r 2 )<br />

...<br />

�(npt*�r 2 )<br />

0<br />

1<br />

2<br />

3<br />

4<br />

5<br />

6<br />

7<br />

8<br />

9<br />

npt-1<br />

dchi(0:npt-1)<br />

�(�r 2 )��(0)<br />

�(2�r 2 )��(�r 2 )<br />

�(3�r 2 )��(2�r 2 )<br />

�(4�r 2 )��(3�r 2 )<br />

�(5�r 2 )��(4�r 2 )<br />

�(6�r 2 )��(5�r 2 )<br />

�(7�r 2 )-�(6�r 2 )<br />

�(8�r 2 )��(7�r 2 )<br />

�(9�r 2 )��(8�r 2 )<br />

�(10�r 2 )��(9�r 2 )<br />

...<br />

�(npt*�r 2 )-�[(npt-1)*�r 2 ]


subroutine shortrange(r,pairs,src,npairs,nmax,np)<br />

parameter (npt=10000)<br />

integer pairs(nmax,2)<br />

dimension src(nmax), r(np,3)<br />

common /short/ chi(0:npt), dchi(0:npt-1), dr2<br />

do m=1,npairs<br />

i=pairs(m,1)<br />

j=pairs(m,2)<br />

dx=r(i,1)-r(j,1)<br />

dy=r(i,2)-r(j,2)<br />

dz=r(i,3)-r(j,3)<br />

r2=dx*dx+dy*dy+dz*dz<br />

d=r2/dr2<br />

k=int(d)<br />

c=d-k<br />

src(m)=chi(k)+c*dchi(k)<br />

enddo<br />

return<br />

end


<strong>Le</strong>s 4 opérations mathématiques <strong>de</strong> base (être humain) : + � � /<br />

<strong>Le</strong>s 4 opérations mathématiques <strong>de</strong> base (ordinateur) : + CS � INV<br />

Soustraction: a � b a + CS(b)<br />

Division: a / b a � INV(b)<br />

Temps <strong>de</strong> <strong>calcul</strong>:<br />

Comparable pour + � INV (typically 1 ns)<br />

Beaucoup plus court pour CS (1 bit vs 64 bits).<br />

Comparable pour + � �<br />

2 fois plus long pour /<br />

On a intérêt à éliminer les divisions.


subroutine shortrange(r,pairs,src,npairs,nmax,np)<br />

parameter (npt=10000)<br />

integer pairs(nmax,2)<br />

dimension src(nmax), r(np,3)<br />

common /short/ chi(0:npt), dchi(0:npt-1), dr2<br />

odr2=1./dr2<br />

do m=1,npairs<br />

i=pairs(m,1)<br />

j=pairs(m,2)<br />

dx=r(i,1)-r(j,1)<br />

dy=r(i,2)-r(j,2)<br />

dz=r(i,3)-r(j,3)<br />

r2=dx*dx+dy*dy+dz*dz<br />

d=r2*odr2<br />

k=int(d)<br />

c=d-k<br />

src(m)=chi(k)+c*dchi(k)<br />

enddo<br />

return<br />

end


subroutine shortrange(r,pairs,src,npairs,nmax,np)<br />

parameter (npt=10000)<br />

integer pairs(nmax,2)<br />

dimension src(nmax), r(np,3)<br />

common /short/ chi(0:npt), dchi(0:npt-1), dr2<br />

odr2=1./dr2<br />

do m=1,npairs<br />

i=pairs(m,1)<br />

j=pairs(m,2)<br />

dx=r(i,1)-r(j,1)<br />

dy=r(i,2)-r(j,2)<br />

dz=r(i,3)-r(j,3)<br />

r2=dx*dx+dy*dy+dz*dz<br />

d=r2*odr2<br />

k=int(d)<br />

c=d-k<br />

src(m)=chi(k)+c*dchi(k)<br />

enddo<br />

return<br />

end<br />

Alternative<br />

dx2=dx*dx<br />

dy2=dy*dy<br />

dz2=dz*dz<br />

r2=dx2+dy2+dz2<br />

Très mauvaise idée!<br />

Raison: existence<br />

<strong>de</strong>s MADD’s


MADD’s : “Multiply - Add’s”<br />

(a+b)*c Addition: 1 ns<br />

Multiplication: 1 ns<br />

Temps total: 2 ns 1.1 ns<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

1<br />

0<br />

0<br />

0<br />

0<br />

0<br />

1<br />

1<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

1<br />

0<br />

1<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

1<br />

a<br />

b<br />

a+b<br />

c<br />

(a+b)*c


MADD’s : “Multiply - Add’s”<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

1<br />

0<br />

0<br />

0<br />

0<br />

0<br />

1<br />

1<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

1<br />

0<br />

1<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

1<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

1<br />

a<br />

b<br />

a+b<br />

c<br />

(a+b)*c<br />

L’addition commence


MADD’s : “Multiply - Add’s”<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

1<br />

0<br />

0<br />

0<br />

0<br />

0<br />

1<br />

1<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

1<br />

0<br />

1<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

1<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

1<br />

0<br />

0<br />

1<br />

0<br />

0<br />

1<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

1<br />

0<br />

1<br />

0<br />

1<br />

1<br />

0<br />

0<br />

0<br />

1<br />

1<br />

1<br />

0<br />

1<br />

a<br />

b<br />

a+b<br />

c<br />

(a+b)*c<br />

La multiplication commence,<br />

l’addition continue


Boucles multiples<br />

Optimisation: A) Remonter vers les boucles extérieures<br />

B) Ordre <strong>de</strong>s boucles


A) Remonter vers les boucles extérieures<br />

Dans le cas <strong>de</strong> boucles multiples, le gros du travail<br />

est effectué par la boucle intérieure<br />

C’est la boucle intérieure qu’il faut optimiser<br />

parameter (n=128)<br />

dimension a(n), b(n), c(n)<br />

dimension x(n**3)<br />

in<strong>de</strong>x=0<br />

do i=1,n<br />

do j=1,n<br />

do k=1,n<br />

in<strong>de</strong>x=in<strong>de</strong>x+1<br />

x(in<strong>de</strong>x)=a(i)*a(i)+b(j)*b(j)+c(k)*c(k)<br />

enddo<br />

enddo<br />

enddo<br />

parameter (n=128)<br />

dimension a(n), b(n), c(n)<br />

dimension x(n**3)<br />

in<strong>de</strong>x=0<br />

do i=1,n<br />

a2=a(i)*a(i)<br />

do j=1,n<br />

b2=b(j)*b(j)<br />

a2b2=a2+b2<br />

do k=1,n<br />

in<strong>de</strong>x=in<strong>de</strong>x+1<br />

x(in<strong>de</strong>x)=a2b2+c(k)*c(k)<br />

enddo<br />

enddo<br />

enddo<br />

+ : 4,194,304<br />

� : 6,291,456<br />

+ : 2,113,536<br />

� : 2,113,664


Autre example<br />

parameter (m=64,n=128)<br />

dimension a(m), b(n)<br />

t=0.<br />

do i=1,m<br />

x=a(i)<br />

do j=1,n<br />

y=b(j)<br />

t=t+sin(sqrt(x)+sqrt(y))<br />

enddo<br />

enddo<br />

parameter (m=64,n=128)<br />

dimension a(m), b(n)<br />

t=0.<br />

do i=1,m<br />

x=a(i)<br />

sqx=sqrt(x)<br />

do j=1,n<br />

y=b(j)<br />

t=t+sin(sqx+sqrt(y))<br />

enddo<br />

enddo<br />

Incorrect<br />

Correct


B) Ordre <strong>de</strong>s boucles.<br />

Considérons 2 boucles <strong>de</strong> tailles très différentes<br />

n m<br />

t = � � exp ( a i x j + b i y j + c i z j )<br />

i=1 j=1<br />

où n = 2 000 000 et m = 10


1 e approche<br />

parameter (n=2000000,m=10)<br />

dimension a(n), b(n), c(n)<br />

dimension x(m), y(m), z(m)<br />

t=0.<br />

do i=1,n<br />

ai=a(i)<br />

bi=b(i)<br />

ci=c(i)<br />

do j=1,m<br />

t=t+exp(ai*x(j))+exp(bi*y(j))+exp(ci*z(j))<br />

enddo<br />

enddo<br />

2 e approche<br />

parameter (n=2000000,m=10)<br />

dimension a(n), b(n), c(n)<br />

dimension x(m), y(m), z(m)<br />

t=0.<br />

do j=1,m<br />

xj=x(j)<br />

yj=y(j)<br />

zj=z(j)<br />

do i=1,n<br />

t=t+exp(a(i)*xj)+exp(b(i)*yj)+exp(c(i)*zj)<br />

enddo<br />

enddo<br />

Boucle intérieure<br />

exécutée 2 000 000 <strong>de</strong><br />

fois.<br />

Chaque fois: 30 “fetch”.<br />

Nombre total <strong>de</strong> “fetch”:<br />

60 000 000.<br />

Boucle intérieure<br />

exécutée 10 fois.<br />

Chaque fois: 6 000 000<br />

“fetch”.<br />

Nombre total <strong>de</strong> “fetch”:<br />

60 000 000.


Cache<br />

Rapi<strong>de</strong><br />

<strong>Le</strong>nt<br />

Cache : Capacité très faible<br />

Processeur<br />

Mémoire<br />

Vitesse d’accès très élevée<br />

<strong>Le</strong>nt<br />

Utile lorsqu’on a un petit nombre <strong>de</strong> variables utilisées très souvant.


1 e approche<br />

parameter (n=2000000,m=10)<br />

dimension a(n), b(n), c(n)<br />

dimension x(m), y(m), z(m)<br />

t=0.<br />

do i=1,n<br />

ai=a(i)<br />

bi=b(i)<br />

ci=c(i)<br />

do j=1,m<br />

t=t+exp(ai*x(j))+exp(bi*y(j))+exp(ci*z(j))<br />

enddo<br />

enddo<br />

2 e approche<br />

parameter (n=2000000,m=10)<br />

dimension a(n), b(n), c(n)<br />

dimension x(m), y(m), z(m)<br />

t=0.<br />

do j=1,m<br />

xj=x(j)<br />

yj=y(j)<br />

zj=z(j)<br />

do i=1,n<br />

t=t+exp(a(i)*xj)+exp(b(i)*yj)+exp(c(i)*zj)<br />

enddo<br />

enddo<br />

30 variables utilisées<br />

2 000 000 <strong>de</strong> fois<br />

chacunes.<br />

La cache permet<br />

d’accélérer le <strong>calcul</strong>.<br />

6 000 000 <strong>de</strong> variables<br />

utilisées 10 fois<br />

chacunes.<br />

La cache ne sert à rien.


1 e approche<br />

parameter (n=2000000,m=10)<br />

dimension a(n), b(n), c(n)<br />

dimension x(m), y(m), z(m)<br />

t=0.<br />

do i=1,n<br />

ai=a(i)<br />

bi=b(i)<br />

ci=c(i)<br />

do j=1,m<br />

t=t+exp(ai*x(j))+exp(bi*y(j))+exp(ci*z(j))<br />

enddo<br />

enddo<br />

• Itération i=1 : <strong>Le</strong> processeur va chercher les 30 variables x(j), y(j),<br />

z(j) dans la mémoire principale (lent), et ces variables sont copiées<br />

dans la cache (lent).<br />

• Itérations i=2, 3, ..., 2 000 000 : <strong>Le</strong> processeur va chercher les 30<br />

variables x(j), y(j), z(j) directement dans la cache (rapi<strong>de</strong>).<br />

En général, on a intérêt à mettre la petite boucle à l’intérieur <strong>de</strong> la<br />

gran<strong>de</strong>. EXCEPTION: Machines vectorielles.


3) Ordinateurs vectoriels<br />

Ex: Somme <strong>de</strong> 2 vecteurs: a(i) + b(i) = c(i), i = 1, … , n<br />

a<br />

b<br />

c<br />

dimension a(n), b(n), c(n)<br />

do i=1,n<br />

c(i)=a(i)+b(i)<br />

enddo<br />

ordinateur sériel :<br />

c(1) = a(1) + b(1)<br />

c(2) = a(2) + b(2)<br />

c(3) = a(3) + b(3)<br />

c(4) = a(4) + b(4)<br />

…<br />

ordinateur vectoriel : toutes les<br />

additions se font simultanément


Autres examples:<br />

copie<br />

dimension a(n), b(n)<br />

do i=1,n<br />

b(i)=a(i)<br />

enddo<br />

dimension a(n), b(n)<br />

do i=1,n<br />

b(i)=a(i)+x<br />

enddo<br />

addition et remplacement<br />

dimension a(n)<br />

do i=1,n<br />

a(i)=a(i)+x<br />

enddo<br />

multiplication<br />

dimension a(n), b(n)<br />

do i=1,n<br />

b(i)=a(i)*x<br />

enddo<br />

addition multiplication et remplacement<br />

dimension a(n)<br />

do i=1,n<br />

a(i)=a(i)*x<br />

enddo<br />

fonction intrinsèque<br />

dimension a(n), b(n)<br />

do i=1,n<br />

b(i)=sin(a(i))<br />

enddo


• Boucles multiples: seule la boucles intérieure peut<br />

se vectoriser.<br />

• <strong>Le</strong>s boucles ne sont pas toutes vectorisables. <strong>Le</strong><br />

compilateur déci<strong>de</strong> automatiquement quelles<br />

boucles peuvent être vectorisées, et les vectorise<br />

automatiquement.<br />

• Un bon compilateur va expliquer pourquoi<br />

certaines boucles ne vectorisent pas.


2 métho<strong>de</strong>s pour déterminer si une boucle est vectorisable:<br />

a) les itérations <strong>de</strong> la boucles pourrait-elles physiquement s’exécuter<br />

simultanément?<br />

b) le résultat serait-il i<strong>de</strong>ntique si les itérations s`exécutaient dans un<br />

autre ordre?<br />

dimension a(8), b(8), c(8)<br />

do i=1,8<br />

c(i)=a(i)+b(i)<br />

enddo<br />

ordre normal: m = 1, 2, 3, 4, 5, 6, 7, 8<br />

autre ordre: m = 5, 8, 3, 6, 1, 2, 7, 4<br />

Si les réponses sont OUI, la boucle est vectorisable.<br />

Si les réponses sont NON, la boucle n’est pas vectorisable.


Examples <strong>de</strong> boucles non-vectorisables:<br />

a) Input/Output<br />

dimension a(n)<br />

do i=1,n<br />

read(1,*) a(i)<br />

enddo<br />

b) Fonctions externes ou sousroutines.<br />

dimension a(n)<br />

do i=1,n<br />

x=a(i)<br />

call SUB(x)<br />

enddo<br />

--------------------------------------subroutine<br />

SUB(x)<br />

print *, x<br />

if(x.lt.0.) stop<br />

return<br />

end


Dans certains cas, on résout le problème gràce au inlining.<br />

non-vectorisable<br />

vectorisable<br />

dimension a(n)<br />

do i=1,n<br />

x=a(i)<br />

call WINDOW(x,xmin,xmax)<br />

a(i)=x<br />

enddo<br />

--------------------------------------subroutine<br />

WINDOW(x,xmin,xmax)<br />

x=AMAX1(x,xmin)<br />

x=AMIN1(x,xmax)<br />

return<br />

end<br />

dimension a(n)<br />

do i=1,n<br />

x=a(i)<br />

x=AMAX1(x,xmin)<br />

x=AMIN1(x,xmax)<br />

a(i)=x<br />

enddo


c) Interruption prématurée<br />

dimension a(n), b(n), c(n)<br />

do i=1,n<br />

c(i)=a(i)+b(i)<br />

if(c(i).lt.0.) stop<br />

enddo<br />

dimension a(n), b(n), c(n)<br />

do i=1,n<br />

c(i)=a(i)+b(i)<br />

if(c(i).lt.0.) go to 10<br />

enddo<br />

10 continue


d) Sélection<br />

dimension a(n), b(n), c(n)<br />

do i=1,n<br />

if(a(i).ge.1.) then<br />

c(i)=a(i)+b(i)**2<br />

else<br />

c(i)=a(i)-b(i)**2<br />

endif<br />

enddo<br />

Cray et IBM ont créé <strong>de</strong>s fonctions implicites spéciales pour permettre la<br />

vectorisation: CVMGP, CVMGM, CVMGZ, CVGMN, CVMGT<br />

Example: CVGMP(x,y,z) =<br />

dimension a(n), b(n), c(n)<br />

x, z � 0;<br />

y, z < 0.<br />

do i=1,n<br />

c(i)=a(i)+CVMGP(b(i)**2,-b(i)**2,a(i)-1.)<br />

enddo


e) Indices compliqués<br />

dimension a(n), b(n), in<strong>de</strong>x(n)<br />

do i=1,n<br />

b(in<strong>de</strong>x(i))=b(in<strong>de</strong>x(i))+a(i)<br />

enddo<br />

Exemple concret: <strong>calcul</strong> <strong>de</strong> la <strong>de</strong>nsité dans le programme P 3 M.<br />

Volume cubique contenant NP particules.<br />

On place dans le volume une grille cubique<br />

N � N � N.<br />

Bût: Calculer la <strong>de</strong>nsité sur la grille à partir<br />

<strong>de</strong>s particules.<br />

Chaque particules comtribuera à la <strong>de</strong>nsité<br />

au point <strong>de</strong> grille le plus proche, et aux 26<br />

points voisins (Triangular-Shaped Cloud).


subroutine assmass(r,b)<br />

parameter (n=256,np=2097152)<br />

dimension r(np,3), b(0:n-1,0:n-1,0:n-1)<br />

do m=1,np<br />

x=r(m,1)<br />

y=r(m,2)<br />

z=r(m,3)<br />

ir=int(n*x)<br />

jr=int(n*y)<br />

kr=int(n*z)<br />

dx=x-ir/float(n)<br />

dy=y-jr/float(n)<br />

dz=z-kr/float(n)<br />

do i=-1,1<br />

do j=-1,1<br />

do k=-1,1<br />

ii=ir+i<br />

jj=jr+j<br />

kk=kr+k<br />

t1=0.75-0.625*i*i+dx*(0.5*i+dx*(1.5*i*i-1.))<br />

t2=0.75-0.625*j*j+dy*(0.5*j+dy*(1.5*j*j-1.))<br />

t3=0.75-0.625*k*k+dz*(0.5*k+dz*(1.5*k*k-1.))<br />

b(ii,jj,kk)=b(ii,jj,kk)+t1*t2*t3<br />

enddo<br />

enddo<br />

enddo<br />

enddo<br />

return<br />

end


subroutine assmass(r,b)<br />

parameter (n=256,np=2097152)<br />

dimension r(np,3), b(0:n-1,0:n-1,0:n-1)<br />

do i=-1,1<br />

do j=-1,1<br />

do k=-1,1<br />

do m=1,np<br />

x=r(m,1)<br />

y=r(m,2)<br />

z=r(m,3)<br />

ir=int(n*x)<br />

jr=int(n*y)<br />

kr=int(n*z)<br />

dx=x-ir/float(n)<br />

dy=y-jr/float(n)<br />

dz=z-kr/float(n)<br />

ii=ir+i<br />

jj=jr+j<br />

kk=kr+k<br />

t1=0.75-0.625*i*i+dx*(0.5*i+dx*(1.5*i*i-1.))<br />

t2=0.75-0.625*j*j+dy*(0.5*j+dy*(1.5*j*j-1.))<br />

t3=0.75-0.625*k*k+dz*(0.5*k+dz*(1.5*k*k-1.))<br />

b(ii,jj,kk)=b(ii,jj,kk)+t1*t2*t3<br />

enddo<br />

enddo<br />

enddo<br />

enddo<br />

return<br />

end


subroutine assmass(r,b)<br />

parameter (n=256,np=2097152)<br />

dimension r(np,3), b(0:n-1,0:n-1,0:n-1)<br />

dimension aux(np)<br />

do i=-1,1<br />

do j=-1,1<br />

do k=-1,1<br />

do m=1,np<br />

x=r(m,1)<br />

y=r(m,2)<br />

z=r(m,3)<br />

ir=int(n*x)<br />

jr=int(n*y)<br />

kr=int(n*z)<br />

dx=x-ir/float(n)<br />

dy=y-jr/float(n)<br />

dz=z-kr/float(n)<br />

t1=0.75-0.625*i*i+dx*(0.5*i+dx*(1.5*i*i-1.))<br />

t2=0.75-0.625*j*j+dy*(0.5*j+dy*(1.5*j*j-1.))<br />

t3=0.75-0.625*k*k+dz*(0.5*k+dz*(1.5*k*k-1.))<br />

aux(np)=t1*t2*t3<br />

enddo<br />

do m=1,np<br />

ir=int(n*x)<br />

jr=int(n*y)<br />

kr=int(n*z)<br />

ii=ir+i<br />

jj=jr+j<br />

kk=kr+k<br />

b(ii,jj,kk)=b(ii,jj,kk)+aux(np)<br />

enddo<br />

enddo<br />

enddo<br />

enddo<br />

return<br />

end


subroutine assmass(r,b)<br />

parameter (n=256,np=2097152)<br />

dimension r(np,3), b(0:n-1,0:n-1,0:n-1)<br />

dimension aux(np)<br />

common /tsc/ a(-1:1), b(-1:1), c(-1:1)<br />

do i=-1,1<br />

do j=-1,1<br />

do k=-1,1<br />

do m=1,np<br />

x=r(m,1)<br />

y=r(m,2)<br />

z=r(m,3)<br />

ir=int(n*x)<br />

jr=int(n*y)<br />

kr=int(n*z)<br />

dx=x-ir/float(n)<br />

dy=y-jr/float(n)<br />

dz=z-kr/float(n)<br />

t1=b(i)+dx*(c(i)+dx*a(i))<br />

t2=b(j)+dy*(c(j)+dy*a(j))<br />

t3=b(k)+dz*(c(k)+dz*a(k))<br />

aux(np)=t1*t2*t3<br />

enddo<br />

do m=1,np<br />

ir=int(n*x)<br />

jr=int(n*y)<br />

kr=int(n*z)<br />

ii=ir+i<br />

jj=jr+j<br />

kk=kr+k<br />

b(ii,jj,kk)=b(ii,jj,kk)+aux(np)<br />

enddo<br />

enddo<br />

enddo<br />

enddo<br />

return<br />

end<br />

a(i) = 1.5*i*i-1<br />

b(i) = 0.75-0.625*i*i<br />

c(i) = 0.5*i


subroutine assmass(r,b)<br />

parameter (n=256,np=2097152)<br />

dimension r(np,3), b(0:n-1,0:n-1,0:n-1)<br />

dimension ir(np), jr(np), kr(np), dx(np), dy(np), dz(np)<br />

dimension aux(np)<br />

common /tsc/ a(-1:1), b(-1:1), c(-1:1)<br />

do m=1,np<br />

x=r(m,1)<br />

y=r(m,2)<br />

z=r(m,3)<br />

ir(m)=int(n*x)<br />

jr(m)=int(n*y)<br />

kr(m)=int(n*z)<br />

dx(m)=x-ir/float(n)<br />

dy(m)=y-jr/float(n)<br />

dz(m)=z-kr/float(n)<br />

enddo<br />

do i=-1,1<br />

do j=-1,1<br />

do k=-1,1<br />

do m=1,np<br />

t1=b(i)+dx(m)*(c(i)+dx(m)*a(i))<br />

t2=b(j)+dy(m)*(c(j)+dy(m)*a(j))<br />

t3=b(k)+dz(m)*(c(k)+dz(m)*a(k))<br />

aux(np)=t1*t2*t3<br />

enddo<br />

do m=1,np<br />

ii=ir(m)+i<br />

jj=jr(m)+j<br />

kk=kr(m)+k<br />

b(ii,jj,kk)=b(ii,jj,kk)+aux(np)<br />

enddo<br />

enddo<br />

enddo<br />

enddo<br />

return<br />

end


subroutine assmass(r,b)<br />

parameter (n=256,np=2097152)<br />

dimension r(np,3), b(0:n-1,0:n-1,0:n-1)<br />

dimension ir(np), jr(np), kr(np), dx(np), dy(np), dz(np)<br />

dimension aux(np)<br />

common /tsc/ a(-1:1), b(-1:1), c(-1:1)<br />

on=1./float(n)<br />

do m=1,np<br />

x=r(m,1)<br />

y=r(m,2)<br />

z=r(m,3)<br />

ir(m)=int(n*x)<br />

jr(m)=int(n*y)<br />

kr(m)=int(n*z)<br />

dx(m)=x-ir*on<br />

dy(m)=y-jr*on<br />

dz(m)=z-kr*on<br />

enddo<br />

do i=-1,1<br />

do j=-1,1<br />

do k=-1,1<br />

do m=1,np<br />

t1=b(i)+dx(m)*(c(i)+dx(m)*a(i))<br />

t2=b(j)+dy(m)*(c(j)+dy(m)*a(j))<br />

t3=b(k)+dz(m)*(c(k)+dz(m)*a(k))<br />

aux(np)=t1*t2*t3<br />

enddo<br />

do m=1,np<br />

ii=ir(m)+i<br />

jj=jr(m)+j<br />

kk=kr(m)+k<br />

b(ii,jj,kk)=b(ii,jj,kk)+aux(np)<br />

enddo<br />

enddo<br />

enddo<br />

enddo<br />

return<br />

end


4) Ordinateurs parallèles<br />

Ordinateur vectoriel: Un seul processeur, qui peux faire <strong>de</strong>s opérations<br />

simultanément sur toutes les composantes <strong>de</strong> vecteurs.<br />

Ordinateur parallèle: Plusieurs processeurs sériels qui se partage le <strong>calcul</strong>.


CPU1<br />

Exécution d’un programme parallèle<br />

région sériele région parallèle région sériele région parallèle région sériele<br />

processeur maître<br />

CPU1 CPU1 CPU1 CPU1<br />

CPU2<br />

CPU3<br />

CPU4<br />

CPU5<br />

CPU6<br />

CPU7<br />

CPU8<br />

CPU2<br />

CPU3<br />

CPU4<br />

CPU5<br />

CPU6<br />

CPU7<br />

CPU8


CPU1<br />

Cache 1<br />

Mémoire Partagée<br />

CPU2<br />

Cache 2<br />

Mémoire<br />

CPU3<br />

Cache 3<br />

CPU4<br />

Cache 4


CPU1<br />

Cache 1<br />

Mem1<br />

CPU2<br />

Cache 2<br />

Mémoire Distribuée<br />

CPU3<br />

Cache 3<br />

CPU4<br />

Cache 4<br />

Mem2 Mem3 Mem4


Ordinateur vectoriel: <strong>Le</strong> compilateur vectorise les boucles<br />

automatiquement.<br />

Ordinateur parallèle: <strong>Le</strong> programme doit contenir <strong>de</strong>s<br />

instructions pour parallèliser les boucles.<br />

Systèmes avec mémoire partagée: OpenMP<br />

Systèmes avec mémoire distribuée: MPI


Exemple: parallèlisation d’une boucle avec OpenMP, sur 8 processeurs.<br />

dimension a(1024), b(1024), c(1024)<br />

!$omp parallel do shared(a,b,c) private(i,x,y,z)<br />

do i=1,1024<br />

x=a(i)<br />

y=b(i)<br />

z=x**2+y**2<br />

if(z.gt.10.) then<br />

c(i)=x<br />

else<br />

c(i)=y<br />

endif<br />

enddo<br />

!$omp end parallel do


processeur 1 processeur 2 processeur 3<br />

do i=1,128<br />

x=a(i)<br />

y=b(i)<br />

z=x**2+y**2<br />

if(z.gt.10.) then<br />

c(i)=x<br />

else<br />

c(i)=y<br />

endif<br />

enddo<br />

do i=385,512<br />

x=a(i)<br />

y=b(i)<br />

z=x**2+y**2<br />

if(z.gt.10.) then<br />

c(i)=x<br />

else<br />

c(i)=y<br />

endif<br />

enddo<br />

do i=769,896<br />

x=a(i)<br />

y=b(i)<br />

z=x**2+y**2<br />

if(z.gt.10.) then<br />

c(i)=x<br />

else<br />

c(i)=y<br />

endif<br />

enddo<br />

do i=129,256<br />

x=a(i)<br />

y=b(i)<br />

z=x**2+y**2<br />

if(z.gt.10.) then<br />

c(i)=x<br />

else<br />

c(i)=y<br />

endif<br />

enddo<br />

do i=513,640<br />

x=a(i)<br />

y=b(i)<br />

z=x**2+y**2<br />

if(z.gt.10.) then<br />

c(i)=x<br />

else<br />

c(i)=y<br />

endif<br />

enddo<br />

do i=897,1024<br />

x=a(i)<br />

y=b(i)<br />

z=x**2+y**2<br />

if(z.gt.10.) then<br />

c(i)=x<br />

else<br />

c(i)=y<br />

endif<br />

enddo<br />

do i=257,384<br />

x=a(i)<br />

y=b(i)<br />

z=x**2+y**2<br />

if(z.gt.10.) then<br />

c(i)=x<br />

else<br />

c(i)=y<br />

endif<br />

enddo<br />

processeur 4 processeur 5 processeur 6<br />

processeur 7 processeur 8<br />

do i=641,768<br />

x=a(i)<br />

y=b(i)<br />

z=x**2+y**2<br />

if(z.gt.10.) then<br />

c(i)=x<br />

else<br />

c(i)=y<br />

endif<br />

enddo


Parallèlisation <strong>de</strong>s boucles:<br />

• Dans le cas <strong>de</strong> boucles multiples, c’est la boucle<br />

extérieure qui se parallèlise.<br />

• Non-parallèlisation: on retrouve en gros les mêmes<br />

critères que la non-vectorisation.<br />

a) Input/Output<br />

b) Interruption prématurée<br />

c) Indices compliqués<br />

Exceptions: o Sélection<br />

o Fonctions externes et sousroutines (dangereux)


Autres concepts:<br />

• Décomposition du domaine.<br />

• Balance <strong>de</strong> charge.<br />

• Relation d’échelle (scalability).


5) Résumé et Conclusion<br />

• <strong>Le</strong> <strong>calcul</strong> <strong>de</strong> <strong>haute</strong> <strong>performance</strong> est <strong>de</strong>venu un outil indispensable <strong>de</strong><br />

l’astrophysique théorique.<br />

• De grands progrès ont été réalisés durant les 30 <strong>de</strong>rnières années.<br />

o Sofware (meilleurs algorithmes)<br />

o Hardware (processeurs plus rapi<strong>de</strong>s, nouvelles architectures)<br />

• <strong>Le</strong>s ordinateurs sériels ne sont pratiquement plus utilisés pour le CHP<br />

(les problèmes sont <strong>de</strong>venus trop gros).<br />

• <strong>Le</strong>s ordinateurs vectoriels ne sont plus très utilisés.<br />

• Présent: ordinateurs parallèles avec mémoire partagée ou distribuée<br />

• Avenir (?): o <strong>Le</strong>s mémoires partagées seront moins utilisées (les problèmes<br />

seront trop gros).<br />

o Ordinateur parallèle avec processeurs vectoriels (existe déjà).<br />

o Ordinateur parallèle avec custom hardware (GRAPE).

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!