0

CUDA に 2 つの 2D 配列を追加したいと考えています。

インデックス スキームを使用すると、プログラムは正常に動作します。

#define COLUMNS 3
#define ROWS 2    
__global__ void add(int *a, int *b, int *c)
{
    int x = blockIdx.x;
    int y = blockIdx.y;
    int i = (COLUMNS*y) + x;
    c[i] = a[i] + b[i];
}    

int main()
{
    int a[ROWS][COLUMNS], b[ROWS][COLUMNS], c[ROWS][COLUMNS];
    int *dev_a, *dev_b, *dev_c;
    cudaMalloc((void **) &dev_a, ROWS*COLUMNS*sizeof(int));
    cudaMalloc((void **) &dev_b, ROWS*COLUMNS*sizeof(int));
    cudaMalloc((void **) &dev_c, ROWS*COLUMNS*sizeof(int));
    for (int y = 0; y < ROWS; y++) // Fill Arrays
        for (int x = 0; x < COLUMNS; x++)
        {
            a[y][x] = x;
            b[y][x] = y;
        }
    cudaMemcpy(dev_a, a, ROWS*COLUMNS*sizeof(int), cudaMemcpyHostToDevice);
    cudaMemcpy(dev_b, b, ROWS*COLUMNS*sizeof(int), cudaMemcpyHostToDevice);
    dim3 grid(COLUMNS,ROWS);
    add<<<grid,1>>>(dev_a, dev_b, dev_c);
    cudaMemcpy(c, dev_c, ROWS*COLUMNS*sizeof(int), cudaMemcpyDeviceToHost);
    return 0;
}

ただし、行列 b が上記のインデックス スキームではなく、ポインターの配列として表されている場合は機能しません。

int a[ROWS][COLUMNS], **b, c[ROWS][COLUMNS];
int *dev_a, *dev_b, *dev_c;
b = (int**)malloc(ROWS*sizeof(int*));
for (int i = 0; i < ROWS; i++)
b[i] = (int*) malloc(COLUMNS*sizeof(int));

なんで?

ここの例を使用しました: http://www.math.uaa.alaska.edu/~afkjm/cs448/handouts/cuda-firstprograms.pdf

4

1 に答える 1

1

質問は古いですが、関連する問題を抱えているここに来るすべての人にヒントを与えようとします.

leftaroundabout に同意します。malloc を使用しないコンパイル時定数の割り当て

int a[ROWS][COLUMNS], b[ROWS][COLUMNS], c[ROWS][COLUMNS];

ほとんどの場合、サイズが ROWS*COLUMNS である各変数 (a、b、c) に単一のメモリ ブロックを割り当てます。1 回の memcpy 操作でそのブロックをデバイスにコピーできます。

ポインターからポインターへのケースでは、各列が個別に割り当てられるため、単一の memcpy を使用してデバイスにコピーできるメモリの 1 つの連続したブロックがあるとは限りません。

この**b場合、同様の動作を実現するために、各列のデータを個別にコピーする必要があります。

for (int o=0; o<ROWS; ++o)
{
  cudaMemcpy((dev_b+o*COLUMNS), b[o], COLUMNS*sizeof(int), cudaMemcpyHostToDevice);
}

それにもかかわらず、要素の順序が異なる場合にインデックスの混乱を避けるために、同じスキームを使用して a と b を処理する必要があると思います。a[ROWS][COLUMNS](ただし、変数は行優先順で格納されると主張しています。)

于 2013-02-20T15:13:03.863 に答える