[c++][H ] Cuda Programmierung Linux (Pointer evtl?)

Man möge mir den Doppelpost verzeihen.
Ich habe deine Lösung. Das Problem liegt in den (cuda)memcpy-Zeilen. Dort kopierst du int** nach int* und int* nach int**. Das geht so nicht.
C:
#include <cuda.h>
#include <stdio.h>
#include <stdlib.h>
 
 
#define N 5
#define BLOCK_DIM 5
 
__global__ void matrixAdd (int *a, int *b, int *c);
void InitData(int** data, int n);
void RandomInit(int** data, int n);
 
int main() 
{
   int** a;
   int** b;
   int** c;
   int*  dev_a;
   int*  dev_b;
   int*  dev_c;
   int size = N * N * sizeof(int);
 
   // initialize a and b with real values (NOT SHOWN)
   cudaMalloc((void**)&dev_a, size);
   cudaMalloc((void**)&dev_b, size);
   cudaMalloc((void**)&dev_c, size);
 
   a = (int**) malloc((N) * sizeof(int*));
   InitData(a, N);
   RandomInit(a, N);
   /*-------------------------------------------------------------------------*/
   b = (int**) malloc((N) * sizeof(int*));
   InitData(b, N);
   RandomInit(b, N);
   /*------------------------------------------------------------------------*/
   c = (int**) malloc((N) * sizeof(int*));
   InitData(c, N);
   
   for(int i = 0;i<N;i++)
   {
      cudaMemcpy(dev_a +(i*N), a[i], N*sizeof(int), cudaMemcpyHostToDevice);
      cudaMemcpy(dev_b +(i*N), b[i], N*sizeof(int), cudaMemcpyHostToDevice);
   }
 
   
 
   dim3 dimBlock(BLOCK_DIM, BLOCK_DIM);
  
   dim3 dimGrid((int)ceil(N/dimBlock.x),(int)ceil(N/dimBlock.y)); 
   matrixAdd<<<dimGrid,dimBlock>>>(dev_a,dev_b,dev_c);
 
   cudaThreadSynchronize();

   for(int i = 0;i<N;i++)
   {
        cudaMemcpy(c[i], dev_c +(i*N), N*sizeof(int), cudaMemcpyDeviceToHost);
   }
 
   for(int i = 0; i < N; i++)
   {
      for(int j = 0; j < N; j++)
      {
         printf("%i + %i \n", a[i][j],b[i][j]);
      }
 
   }
   
   for(int i = 0; i < N; i++)
   {
      for(int j = 0; j < N; j++)
      {
         printf("%i \n", c[i][j]);
      }
 
   }
 
   cudaFree(dev_a); 
   cudaFree(dev_b); 
   cudaFree(dev_c);
   free(a); 
   free(b); 
   free(c);
}
 
/*******************************************************************************
*******************************************************************************/
__global__ void matrixAdd (int *a, int *b, int *c) 
{
   int col = blockIdx.x * blockDim.x + threadIdx.x;
   int row = blockIdx.y * blockDim.y + threadIdx.y;
   int index = col * N + row;
   
   if (col < N && row < N) 
   {
      c[index] = a[index] + b[index];
   }
}
 
 
/*******************************************************************************
*******************************************************************************/
void RandomInit(int** data, int n)
{
   for(int i = 0; i < n; ++i)
   {
      for(int j = 0; j < n; ++j)
      {
         data[i][j] = rand()%(int)100;
      }
   }
}
 
/*******************************************************************************
*******************************************************************************/
void InitData(int** data, int n)
{
   for (int i = 0; i < N; ++i)
   {
      data[i] = (int*) malloc((N) * sizeof(int));
      if (data[i] == NULL)
      {
         printf("ERROR(%s, %d): Speicher konnte nicht alloziiert werden.\n",
                __FILE__, __LINE__);
      }
   }
}

Einige Dinge habe ich jetzt nicht berücksichtigt, aber das Optimieren überlasse ich mal dir :-)

Gruss
cwriter
 
Zuletzt bearbeitet:
es funktioniert. wunderbar. Vielen lieben Dank.

Kannst du die stelle bitte nochmal haar genau erklären?
Ich muss es auch verstehen.

Weil ich verstehe gerade nicht warum c[N][N] funktioniert. Also wenn ich es nicht dynamisch initialisiere und wenn ich es dynamisch initiallisiere es krachen geht an dieser stelle.

Das herrausschreiben der dev_a und dev_b werte war ein test ob es da krachen geht. Wird aber jetzt rausgelöscht.
Die optimierung des Codes mache ich nochmal selber. auch die kleinen tipps mit den variablen wir noch gemacht.

Danke an alle nochmal.
 
Das
C:
cudaMemcpy(dev_a, a, size, cudaMemcpyHostToDevice);
(ich nehme mal a als Beispiel) sieht für den Compiler so aus:
C:
cudaMemcpy(int*, int**, size_t, int);
Der Letzte Parameter ist erstmal egal.
Am einfachsten ist das Kopieren wohl mit cstrings zu erklären:
C:
char* c = (char*)malloc(100);
strcpy(c,"Das ist ein Text");
//*c        == *(c+0) == c[0] == 'D'
//             *(c+1) == c[1] == 'a'
//usw.
free(c);
c zeigt jetzt auf ein Byte des Arbeitsspeichers, in diesem Fall ein 'D'. Das ist noch nicht der ganze String, also wird solange gelesen, bis ein '\0' auftritt. Ein Pointer setzt bloss einen Anfangspunkt.
Wenn du nun ein int** hast, ist das ein Pointer auf einen Pointer.
D.h.:
C:
cudaMemcpy(int*, int**,size_t, int);
kopiert vom Anfangspunkt von int** die Menge von size_t bytes. Ein Pointer ist auf x86 32bit (4bytes), auf x64 64bit (8 bytes).
Wenn du mehr als diese Bytezahl zu kopieren versuchst (in deinem Fall 5*5*4 = 100), liest du Speicher, der dir nicht gehört -> Speicherzugriffsfehler). Mal abgesehen davon, dass es nicht der Wert dessen ist, worauf der Pointer zeigt, sondern der Wert des Pointers selbst.
Eine Möglichkeit wäre gewesen, auf den Wert des Pointers (den anderen Pointer) zuzugreifen, indem man ein Asterisk vor die Variable setzt.
C:
cudaMemcpy(dev_a, *a, size, cudaMemcpyHostToDevice);
Jedoch wird da nur auf eine Dimension zugegriffen, die nicht reicht.
Deshalb ist eine Schlaufe nötig (meiner Meinung nach, vielleicht weiss jemand mehr?):
C:
for(int i = 0;i<N;i++)
{
   cudaMemcpy(dev_a +(i*N), a[i], N*sizeof(int), cudaMemcpyHostToDevice);
}
Nun: pointer+zahl verändert die Position des Pointers, den Anfangspunkt. Siehe beim Beispiel des cstrings: Es wird auf den Wert zugegriffen, der um Zahl von c verschoben ist.
Hier werden nur 5er-Blöcke (Ner-Blöcke) gelesen, und dann der Punkt, wo der nächste Block hinkommt, um 5 (oder N) verschoben, sodass die alten Werte nicht überschrieben werden.

Ich hoffe, das macht es klarer. Ansonsten noch ein sehr gutes Tutorial: http://www.cplusplus.com/doc/tutorial/pointers/

Gruss
cwriter

//EDIT: Zum c[N][N]: Wie genau hast du es statisch gemacht?
 
Zuletzt bearbeitet:
Zurück