GPU pendant les vacances

À chaque année, je prends des vacances quelque part en été…

Je me donne à chaque année un petit projet pour apprendre un truc nouveau. Cette année, le calcul par carte graphique. La puissance des cartes pour le calcul parallel dépasse maintenant celle des CPU. J’ai donc voulu tester ceci. J’utilise un portable Mac qui a justement une carte supplémentaire installée (AMD Radeon R9 M370X 2048 Mo). Cette carte a 640 coeurs fonctionnant à 0.8Ghz. Sinon, ce Mac a un processeur à 4 coeurs, ce qui permet de faire du OpenMP pour le calcul parallel. Mais je voulais essayer le calcul par GPU (Graphics Processing Unit).

Il y a deux fabriquants de cartes: NVIDIA et AMD. NVIDIA a inventé la première technologie, appelée CUDA, qui est très utilisée sur les cartes NVIDIA. NVIDIA et d’autres ont conçu récemment OpenACC qui ressemble à OpenMP.  C’est très prometteur, mais pour le moment il n’existe que des solutions commerciales pour une utilisation sans trop de problèmes (voir pgi fortran). Apple a plutôt proposé le standard OpenCL, qui n’est pas restreint aux cartes NVIDIA et qui va en plus utiliser le processeur Intel et d’autres ressources (si on en a). On peut appeler sous C. J’utilise plutôt Fortran pour faire du calcul. Afin d’utiliser OpenCL, je suis allé chercher l’excellent package CLFortran qui fait l’interface entre C et Fortran. J’ai fait les tests sans trop de problème avec le compilateur gfortran. Maintenant, une petite application pour voir les gains de vitesses possibles.

En OpenCL, il faut deux composantes: le code principal (fortran) et le code cl. Le code cl contient le « kernel », le code exécuté sur un coeur du GPU.  Ce code est en C. Puisque le coeur n’a pas une grande puissance, le calcul doit être simple. Le gain viendra du fait qu’il y a beaucoup de coeurs pour faire le travail…

Dans ma petite application, voici le kernel:

__kernel void sum(const int size, const __global float * vec1, __global float * vec2){
int ii = get_global_id(0);
for (int jj = 0; jj < 10000; jj++) {
vec2[ii] += 1.0;
}

J’ajoute de façon séquentielle 10000 fois 1.0 a un chiffre. Le code principal lui demande de faire ceci 1,000,000 de fois.

Si on roule avec un seul coeur du CPU sans GPU, ça prend 24 secondes. Avec 4 coeurs en OpenMP, environ 6 secondes. Avec le processeur graphique, ca prend 0.3 secondes. Il y a donc un gain de calcul énorme, même par rapport à OpenMP. Bien sur, il faut que la tâche qui soit faite en parallèle ne soit pas trop intense en calcul… Si on fait plutôt une somme sur 1000000 pour seulement 1000 points, alors OpenCL fait en 0.181 secondes et le code parallel OpenMP en 0.78 secondes. Le gain demeure appréciable.