Comment puis-je additionner deux tableaux 2d (en hauteur) en utilisant des boucles nestedes pour?

Je suis nouveau à Cuda. Je veux append deux tableaux 2D dans un troisième tableau. J’utilise le code suivant:

cudaMallocPitch((void**)&device_a, &pitch, 2*sizeof(int),2); cudaMallocPitch((void**)&device_b, &pitch, 2*sizeof(int),2); cudaMallocPitch((void**)&device_c, &pitch, 2*sizeof(int),2); 

maintenant, mon problème est que je ne veux pas utiliser ces tableaux comme des tableaux 2-d aplatis tout dans le code de mon kernel, je veux utiliser deux pour la boucle et placer le résultat dans le troisième tableau comme

 __global__ void add(int *dev_a ,int *dev_b,int* dec_c) { for i=0;i<2;i++) { for j=0;j<2;j++) { dev_c[i][j]=dev_a[i][j]+dev_b[i][j]; } } } 

Comment puis-je faire cela dans CUDA? s’il vous plaît dites-moi comment utiliser tableau 2-D de cette façon?

Quel devrait être l’appel du kernel pour utiliser 2d-array? Si possible, veuillez expliquer en utilisant des exemples de code.

La réponse courte est que vous ne pouvez pas. La fonction cudaMallocPitch() fait exactement ce que son nom implique, elle alloue de la mémoire linéaire en hauteur, où la hauteur est choisie pour être optimale pour le contrôleur de mémoire GPU et le matériel de texture.

Si vous voulez utiliser des tableaux de pointeurs dans le kernel, le code du kernel devrait ressembler à ceci:

 __global___ void add(int *dev_a[] ,int *dev_b[], int* dec_c[]) { for i=0;i<2;i++) { for j=0;j<2;j++) { dev_c[i][j]=dev_a[i][j]+dev_b[i][j]; } } } 

vous aurez ensuite besoin d'appels nesteds cudaMalloc du côté de l'hôte pour construire le tableau de pointeurs et le copier dans la mémoire du périphérique. Pour votre exemple 2x2 plutôt sortingvial, le code pour allouer un seul tableau ressemblerait à ceci:

 int ** h_a = (int **)malloc(2 * sizeof(int *)); cudaMalloc((void**)&h_a[0], 2*sizeof(int)); cudaMalloc((void**)&h_a[1], 2*sizeof(int)); int **d_a; cudaMalloc((void ***)&d_a, 2 * sizeof(int *)); cudaMemcpy(d_a, h_a, 2*sizeof(int *), cudaMemcpyHostToDevice); 

Ce qui laisserait le tableau de périphériques alloué dans d_a, et vous le transmetsortingez à votre kernel.

Pour des raisons de complexité du code et de performances, vous ne voulez vraiment pas faire cela, utiliser des tableaux de pointeurs dans le code CUDA est à la fois plus difficile et plus lent que l'alternative utilisant la mémoire linéaire.


Pour montrer ce qu’est folie d’utiliser des tableaux de pointeurs dans CUDA, voici un exemple de travail complet de votre exemple de problème, qui combine les deux idées ci-dessus:

 #include  __global__ void add(int * dev_a[], int * dev_b[], int * dev_c[]) { for(int i=0;i<2;i++) { for(int j=0;j<2;j++) { dev_c[i][j]=dev_a[i][j]+dev_b[i][j]; } } } inline void GPUassert(cudaError_t code, char * file, int line, bool Abort=true) { if (code != 0) { fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code),file,line); if (Abort) exit(code); } } #define GPUerrchk(ans) { GPUassert((ans), __FILE__, __LINE__); } int main(void) { const int aa[2][2]={{1,2},{3,4}}; const int bb[2][2]={{5,6},{7,8}}; int cc[2][2]; int ** h_a = (int **)malloc(2 * sizeof(int *)); for(int i=0; i<2;i++){ GPUerrchk(cudaMalloc((void**)&h_a[i], 2*sizeof(int))); GPUerrchk(cudaMemcpy(h_a[i], &aa[i][0], 2*sizeof(int), cudaMemcpyHostToDevice)); } int **d_a; GPUerrchk(cudaMalloc((void ***)&d_a, 2 * sizeof(int *))); GPUerrchk(cudaMemcpy(d_a, h_a, 2*sizeof(int *), cudaMemcpyHostToDevice)); int ** h_b = (int **)malloc(2 * sizeof(int *)); for(int i=0; i<2;i++){ GPUerrchk(cudaMalloc((void**)&h_b[i], 2*sizeof(int))); GPUerrchk(cudaMemcpy(h_b[i], &bb[i][0], 2*sizeof(int), cudaMemcpyHostToDevice)); } int ** d_b; GPUerrchk(cudaMalloc((void ***)&d_b, 2 * sizeof(int *))); GPUerrchk(cudaMemcpy(d_b, h_b, 2*sizeof(int *), cudaMemcpyHostToDevice)); int ** h_c = (int **)malloc(2 * sizeof(int *)); for(int i=0; i<2;i++){ GPUerrchk(cudaMalloc((void**)&h_c[i], 2*sizeof(int))); } int ** d_c; GPUerrchk(cudaMalloc((void ***)&d_c, 2 * sizeof(int *))); GPUerrchk(cudaMemcpy(d_c, h_c, 2*sizeof(int *), cudaMemcpyHostToDevice)); add<<<1,1>>>(d_a,d_b,d_c); GPUerrchk(cudaPeekAtLastError()); for(int i=0; i<2;i++){ GPUerrchk(cudaMemcpy(&cc[i][0], h_c[i], 2*sizeof(int), cudaMemcpyDeviceToHost)); } for(int i=0;i<2;i++) { for(int j=0;j<2;j++) { printf("(%d,%d):%d\n",i,j,cc[i][j]); } } return cudaThreadExit(); } 

Je vous recommande de l'étudier jusqu'à ce que vous compreniez ce qu'il fait et pourquoi c'est une si mauvaise idée par rapport à l'utilisation de la mémoire linéaire.

Vous n’avez pas besoin d’utiliser de boucles pour l’intérieur de l’appareil. Essayez ce code.

 #include  #include  #include  #include  #define N 800 __global__ void masortingxAdd(float* A, float* B, float* C){ int i = threadIdx.x; int j = blockIdx.x; C[N*j+i] = A[N*j+i] + B[N*j+i]; } int main (void) { clock_t start = clock(); float a[N][N], b[N][N], c[N][N]; float *dev_a, *dev_b, *dev_c; cudaMalloc((void **)&dev_a, N * N * sizeof(float)); cudaMalloc((void **)&dev_b, N * N * sizeof(float)); cudaMalloc((void **)&dev_c, N * N * sizeof(float)); for (int i = 0; i < N; i++){ for (int j = 0; j < N; j++){ a[i][j] = rand() % 10; b[i][j] = rand() % 10; } } cudaMemcpy(dev_a, a, N * N * sizeof(float), cudaMemcpyHostToDevice); cudaMemcpy(dev_b, b, N * N * sizeof(float), cudaMemcpyHostToDevice); matrixAdd <<>> (dev_a, dev_b, dev_c); cudaMemcpy(c, dev_c, N * N * sizeof(float), cudaMemcpyDeviceToHost); for (int i = 0; i < N; i++){ for (int j = 0; j < N; j++){ printf("[%d, %d ]= %f + %f = %f\n",i,j, a[i][j], b[i][j], c[i][j]); } } printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC); cudaFree(dev_a); cudaFree(dev_b); cudaFree(dev_c); return 0; }