Dans ce fichier, on commence par inclure le fichier calcul_cuda.h :
1
|
#include "calcul_cuda.h"
|
Ensuite, on définit une structure qui contient tout les variables globales dont on a besoin pour le calcul :
1
2
3
4
5
|
struct GlobalVarMatrix{
float *matriceLeftd;
float *matriceRightd;
float *matriceResultd;
};
|
Ensuite on crée la variable globale proprement dite, et on l'initialise :
1
|
GlobalVarMatrix globalVarMatrix = {NULL, NULL, NULL};
|
Maintenant, on peut créer la fonction qui fera le calcul :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
__global__ void matrixMulKernel(float * matriceResultd, float * matriceLeftd, float * matriceRightd, int width){
int tx = threadIdx.x;
int ty = threadIdx.y;
float pResult = 0;
for(int i = 0; i < width; ++i){
float mdElement = matriceLeftd[ty*width + i];
float ndElement = matriceRightd[i*width + tx];
pResult += mdElement * ndElement;
}
matriceResultd[ty*width + tx] = pResult;
}
|
Heu... Il ne manque pas des boucles là ? On fait bien un produit matriciel avec 3 boucles.
Oui, il y a bien trois boucles dans un produit matriciel, mais qui vous dit qu'il en manque deux ?
Ben, il n'y a qu'un seul for
Voici une des subtilité de la programmation CUDA, dans notre programme il y aura bien trois boucles, mais c'est la carte graphique qui fera les deux boucles principales, en hardware et pas en software. C'est donc le matériel qui fait deux boucles à notre place. Donc le compte est bon.
En fait ce sont les variables threadIdx.x et threadIdx.y qui nous permettent de faire deux boucles avec le matériel.
Et rappeler-vous qu'une fonction __global__ ne retourne rien.
Nous pouvons donc ajouter la fonction qui appelle notre fonction CUDA :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
///fonction qui appelle la fonction en cuda de multiplication de matrice
extern "C" void matrixMulOnDevice(float * matriceResult, float * matriceLeft, float * matriceRight, int width){
int size = width*width*sizeof(float);
cudaMalloc(&globalVarMatrix.matriceLeftd, size);
cudaMemcpy(globalVarMatrix.matriceLeftd, matriceLeft, size, cudaMemcpyHostToDevice) ;
cudaMalloc(&globalVarMatrix.matriceRightd, size);
cudaMemcpy(globalVarMatrix.matriceRightd, matriceRight, size, cudaMemcpyHostToDevice);
cudaMalloc(&globalVarMatrix.matriceResultd, size);
dim3 dimGrid(1, 1);
dim3 dimBlock(width, width);
matrixMulKernel<<<dimGrid, dimBlock>>>(globalVarMatrix.matriceLeftd, globalVarMatrix.matriceRightd, globalVarMatrix.matriceResultd, width);
cudaMemcpy(matriceResult, globalVarMatrix.matriceResultd, size, cudaMemcpyDeviceToHost);
cudaFree(globalVarMatrix.matriceLeftd);
cudaFree(globalVarMatrix.matriceRightd);
cudaFree(globalVarMatrix.matriceResultd);
}
|
N'oubliez pas que cudaMalloc prend un void** donc il faut un & devant le pointeur à allouer.
Voici le fichier calcul_cuda.cu en entier :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
#include "calcul_cuda.h"
///on définit une variable globale pour avoir les matrices pour la carte graphique
struct GlobalVarMatrix{
float *matriceLeftd;
float *matriceRightd;
float *matriceResultd;
};
GlobalVarMatrix globalVarMatrix = {NULL, NULL, NULL};
///fonction qui va calculer la multiplication de la matrice dans la carte graphique
__global__ void matrixMulKernel(float * matriceResultd, float * matriceLeftd, float * matriceRightd, int width){
int tx = threadIdx.x;
int ty = threadIdx.y;
float pResult = 0;
for (int i = 0; i < width; ++i){
float mdElement = matriceLeftd[ty*width + i];
float ndElement = matriceRightd[i*width + tx];
pResult += mdElement * ndElement;
}
matriceResultd[ty*width + tx] = pResult;
}
///fonction qui appelle la fonction en cuda de multiplication de matrice
extern "C" void matrixMulOnDevice(float * matriceResult, float * matriceLeft, float * matriceRight, int width){
int size = width*width*sizeof(float);
cudaMalloc(&globalVarMatrix.matriceLeftd, size);
cudaMemcpy(globalVarMatrix.matriceLeftd, matriceLeft, size, cudaMemcpyHostToDevice) ;
cudaMalloc(&globalVarMatrix.matriceRightd, size);
cudaMemcpy(globalVarMatrix.matriceRightd, matriceRight, size, cudaMemcpyHostToDevice);
cudaMalloc(&globalVarMatrix.matriceResultd, size);
dim3 dimGrid(1, 1);
dim3 dimBlock(width, width);
matrixMulKernel<<<dimGrid, dimBlock>>>(globalVarMatrix.matriceLeftd, globalVarMatrix.matriceRightd, globalVarMatrix.matriceResultd, width);
cudaMemcpy(matriceResult, globalVarMatrix.matriceResultd, size, cudaMemcpyDeviceToHost);
cudaFree(globalVarMatrix.matriceLeftd);
cudaFree(globalVarMatrix.matriceRightd);
cudaFree(globalVarMatrix.matriceResultd);
}
|
Vous pouvez le récupérer ici.
|