CUDA : [cours]    [mise en pratique]

4. Courbe de Julia

L'objectif du TD est de comparer les temps de calcul entre CPU et GPU pour calculer une courbe ou ensemble de Julia. On se réfère ici au chapitre 4 de CUDA par L'exemple.

courbe de julia

4.1. Contexte

Etant donnés deux nombres complexes, $c$ et $z_0$, on définit la suite $z_n$ par la relation de récurrence :

$z_{n+1} = z_n^2 + c$

Pour une valeur donnée de $c$, l'ensemble de Julia correspondant est la frontière de l'ensemble des valeurs initiales $z_0$ pour lesquelles la suite est bornée (l’ensemble de ces valeurs étant lui désigné comme l'ensemble de Julia rempli).

Voici une listes de valeurs à tester pour $c$:

4.2. Implantation sur le CPU

Récupérer l'archive et étudier le code.

4.2.1. fonction principale (kernel)

Le kernel qui est exécuté sur le CPU consiste à déterminer, pour chaque point de l'image de coordonnées complexes $(x + yi)$, s'il appartient à l'ensemble de Julia.

4.2.2. la fonction julia

Elle détermine si un point de l'écran est dans l'ensemble en retournant la norme de $z$ sauf si celle-ci dépasse la valeur limite (NORM_THRESOLD = 4.0), on considère alors que la suite $z_n$ ne converge pas.

On centre les pixels sur le milieu de l'image et on les place dans l'intervalle $x=[-2.4 , +2.4]$ et $y=[-1.5 , +1.5]$.

on calcule 200 itérations de la fonction (soit 200 $z_i$), tout en vérifiant si l'équation diverge à chaque itération.

4.3. Implantation sur le GPU (version 1)

Réaliser une première implantation sur le GPU. On fera en sorte de créer une grille 2D de de la taille de l'image. Chaque bloc contient donc 1 seul thread qui se charge de calculer si le point de coordonnées $(threadIdx.x, threadIdx.y)$ appartient ou non à l'ensemble de Julia.

4.3.1. Comparaison CPU vs GPU

Modifier le fichier initial pour qu'on puisse réaliser l'exécution sur le GPU, puis comparer en terme de temps, les deux versions. On donnera un tableau comparatif des temps pour les valeurs suivantes de l'image :

4.4. Amélioration GPU

On s'arrange pour que la grille soit composée de moins de blocs qui contiennent plus de thread (grille 2D de blocs 2D). Notez l'amélioration obtenue par rapport à la première version GPU et donner les temps comparatifs pour les tailles d'images de l'exercice précédent ainsi que pour :

4.5. Meilleure configuration

Déterminer la meilleure configuration possible pour votre GPU. Pour cela faire un test de peformance avec différentes tailles de blocs et comparer les temps GPU.

On fixera les variables suivantes pour récupérer le résultat dans le fichier julia.log

export CUDA_PROFILE=1
export CUDA_PROFILE_LOG=julia.log
export CUDA_PROFILE_CSV=1

ou alors on utilisera nvprof.

4.6. Quelques résultats

Voici à présent plusieurs résultats comparatifs entre CPU et carte graphique pour une représentation en simple précision et double précision.

 hardware   dim   CPU   CPU (4 threads)   CPU (8 threads)   GPU 
 i5-4570 @ 3.20GHz, GeForce GTX 770   256   196   193   194   2 
 i5-4570 @ 3.20GHz, GeForce GTX 770   512   775   775   775   6 
 i5-4570 @ 3.20GHz, GeForce GTX 770   1024   3115   3169   3203   19 
 i5-4570 @ 3.20GHz, GeForce GTX 770   2048   12688   12808   12473   64 
 i5-4570 @ 3.20GHz, GeForce GTX 770   4096   49763   49803   49728   230 
 i5-3570K @ 3.40GHz, GeForce GTX 560 Ti   256   221   83   75   5 
 i5-3570K @ 3.40GHz, GeForce GTX 560 Ti   512   884   332   283   18 
 i5-3570K @ 3.40GHz, GeForce GTX 560 Ti   1024   3538   1327   1045   63 
 i5-3570K @ 3.40GHz, GeForce GTX 560 Ti   2048   14126   5303   4514   210 
 i5-3570K @ 3.40GHz, GeForce GTX 560 Ti   4096   56482   21207   16526   756 
 Xeon E5-2670 v2 @ 2.50GHz, Tesla K20m   256   829   326   218   3 
 Xeon E5-2670 v2 @ 2.50GHz, Tesla K20m   512   3314   1334   781   10 
 Xeon E5-2670 v2 @ 2.50GHz, Tesla K20m   1024   13262   5094   3080   30 
 Xeon E5-2670 v2 @ 2.50GHz, Tesla K20m   2048   52952   19881   12211   114 
 Xeon E5-2670 v2 @ 2.50GHz, Tesla K20m   4096   212095   79500   48853   591 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 660   256   175   68   45   3 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 660   512   700   266   169   8 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 660   1024   2799   1073   675   28 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 660   2048   11219   4287   2657   98 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 660   4096   44613   17009   10637   346 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 970   256   174   68   44   2 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 970   512   697   267   167   5 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 970   1024   2797   1071   665   16 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 970   2048   11173   4297   2668   59 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 970   4096   44705   17209   10484   204 
Comparaison CPU vs. GPU (temps ms) - float - 10.000 itérations
 hardware   dim   CPU   CPU (4 threads)   CPU (8 threads)   GPU 
 i5-4570 CPU @ 3.20GHz, GeForce GTX 770   256   195   88   65   24 
 i5-4570 CPU @ 3.20GHz, GeForce GTX 770   512   791   357   250   67 
 i5-4570 CPU @ 3.20GHz, GeForce GTX 770   1024   3140   1312   1034   218 
 i5-4570 CPU @ 3.20GHz, GeForce GTX 770   2048   12417   4774   3824   702 
 i5-4570 CPU @ 3.20GHz, GeForce GTX 770   4096   50733   20532   16305   2569 
 i5-3570K @ 3.40GHz, GeForce GTX 560 Ti   256   221   84   67   30 
 i5-3570K @ 3.40GHz, GeForce GTX 560 Ti   512   884   332   273   84 
 i5-3570K @ 3.40GHz, GeForce GTX 560 Ti   1024   3537   1327   1097   277 
 i5-3570K @ 3.40GHz, GeForce GTX 560 Ti   2048   14121   5304   4257   967 
 i5-3570K @ 3.40GHz, GeForce GTX 560 Ti   4096   56465   21193   17258   3514 
 Xeon E5-2670 v2 @ 2.50GHz, Tesla K20m   256   256   98   61   4 
 Xeon E5-2670 v2 @ 2.50GHz, Tesla K20m   512   1033   388   238   17 
 Xeon E5-2670 v2 @ 2.50GHz, Tesla K20m   1024   4135   1616   953   41 
 Xeon E5-2670 v2 @ 2.50GHz, Tesla K20m   2048   16504   6192   3799   159 
 Xeon E5-2670 v2 @ 2.50GHz, Tesla K20m   4096   66000   24762   15194   700 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 660   256   177   70   45   29 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 660   512   711   271   172   98 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 660   1024   2855   1098   693   314 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 660   2048   11344   4320   2696   1001 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 660   4096   45309   17509   10831   3656 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 970   256   177   69   45   28 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 970   512   708   274   172   69 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 970   1024   2846   1084   693   214 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 970   2048   11378   4355   2753   776 
 i7-4790 CPU @ 3.60GHz, GeForce GTX 970   4096   45407   17501   10811   2670 
Comparaison CPU vs. GPU (temps ms) - double - 10.000 itérations

Ces tableaux appellent quelques commentaires :

Recherche du bloc de taille optimale

Exemple avec Tesla K20m : meilleur temps 608 ms avec un bloc de 16 x 16

 block size   time (ms)   occupancy 
 2   12122   0.250 
 3   5794   0.250 
 4   3514   0.250 
 5   2378   0.250 
 6   1438   0.500 
 7   1131   0.500 
 8   931   0.500 
 9   929   0.750 
 10   718   1.000 
 11   655   1.000 
 12   691   0.938 
 13   706   0.938 
 14   756   0.984 
 15   641   1.000 
 16   608   1.000 
 17   683   0.938 
 18   705   0.859 
 19   637   0.938 
 20   702   0.812 
 21   682   0.875 
 22   637   1.000 
 23   707   0.797 
 24   747   0.844 
 25   650   0.938 
 26   907   0.688 
 27   791   0.719 
 28   725   0.781 
 29   693   0.844 
 30   712   0.906 
 31   658   0.969 
 32   654   1.000 
Recherche de la taille de bloc la plus performante - float - 10.000 itérations