Travaux pratiques d'Informatique Parallèle et distribuée, UMONS/Polytech, TP 3 2
3.4.Programmation
a) Sélection du processeur graphique :
La sélection du GPU utilisé par le programme s'effectuer à l'aide de la fonction
cudaSetDevice :
cudaError_t cudaSetDevice (int device)
Cette fonction indique au programme qu'il doit utiliser le GPU d'identifiant device. S'il y a n
GPU sur une machine, device peut valoir une valeur être comprise entre 0 et n-1.
b)Allocation en mémoire device et transfert des données CPU => GPU
L'allocation de la mémoire s'exécute à l'aide de la fonction cudaMalloc :
cudaError_t cudaMalloc (void ** devPtr, size_t size)
Cette fonction réserve, dans la mémoire device, un espace mémoire de taille size dont l'adresse
est contenue dans le pointeur devPtr.
Le transfert des données s'exécute via la fonction cudaMemcpy :
cudaError_t cudaMemcpy (void * dst, const void * src, size_t count,
enum cudaMemcpyKind kind)
Cette fonction transfert count octets de l'espace mémoire src vers l'espace mémoire dst. La
variable kind doit être mise à :
•cudaMemcpyHostToDevice dans le cas d'un transfert CPU ==> GPU
•cudaMemcpyDeviceToHost dans le cas d'un transfert GPU ==> CPU
c)Appel du kernel
Le kernel est une fonction destinée à tourner sur GPU. Elle se distingue des fonctions habituelles
par son en-tête précédé par l'un de ces mots-clés :
•__global__ : indique que la fonction est appelée depuis le CPU
•__device__ : indique que la fonction est appelée depuis le GPU
Lorsque le GPU exécute un kernel, les instructions sont chargées dans les multiprocesseurs et les
ALUs exécutent simultanément la même instruction (mode de fonctionnement SIMD – Single Instruction
Multiple Data). Le nombre de thread s'exécutant ainsi en parallèle est déterminé par l'utilisateur lors de
l'appel au kernel :
kernel<<<Nombre_de_blocs,Nombre_de_threads_par_bloc>>>(arguments);
Les threads se situent dans des blocs et le nombre total de thread lancé est égal à Nombre_de_blocs*
Nombre_de_threads_par_bloc. Ces dernières variables peuvent soit être des scalaires, soit des
variables de types dim3 :
dim3 var(x,y,z)
Dans ce dernier cas, les threads et les blocs occupent plusieurs dimensions, pouvant ainsi mieux
représenter la répartition des données. Par exemple, l'appel kernel<<<(2,2,1),
(2,2,1)>>>(arguments); crée la grille de threads présentée à la page suivante.
UMONS/Polytech
Pierre Manneback, Sébastien Frémal, Sidi Ahmed Mahmoudi 2014-15