1つのアプローチは、2D配列をフラット化し、行と列の次元を処理するためのポインター演算を使用して1D形式で処理することです。まず、構造体定義で、antenna_pattern要素を次のように置き換えます。
struct LR {
.
.
float *antenna_pattern;
} LR;
次に、スペースを割り当てるためにホスト側のmallocを実行する必要があります。
#define COL 1001
#define ROW 361
#define DSIZE (ROW*COL)
LR.antenna_pattern = (float *)malloc(DSIZE*sizeof(float));
そして、デバイス側のcuda malloc:
float *d_antenna_pattern;
cudaMalloc((void **) &d_antenna_pattern, DSIZE*sizeof(float));
デバイスへのコピーは次のようになります。
cudaMemcpy(d_antenna_pattern, LR.antenna_pattern, DSIZE*sizeof(float), cudaMemcpyHostToDevice);
これらの配列を参照する場合は、次のようなポインタ演算を行う必要があります。
float my_val_xy = ap[(x*COL)+y]; // to access element at [x][y] on the device
float my_val_xy = LR.antenna_pattern[(x*COL)+y]; // on the host
全体を通して2D配列の添え字を維持したい場合は、適切なtypedefを使用してこれを行うことができます。例については、この質問に対する私の回答の最初のコードサンプルを参照してください。これを図解するには、typedefから始める必要があります。
#define COL 1001
#define ROW 361
#define DSIZE (ROW*COL)
typedef float aParray[COL];
構造定義を変更します。
struct LR {
.
.
aParray *antenna_pattern;
} LR;
ホスト側のmallocは次のようになります。
LR.antenna_pattern = (aParray *)malloc(DSIZE*sizeof(float));
デバイス側のcudamallocは次のようになります。
aParray *d_antenna_pattern;
cudaMalloc((void **) &d_antenna_pattern, DSIZE*sizeof(float));
デバイスへのコピーは次のようになります。
cudaMemcpy(d_antenna_pattern, LR.antenna_pattern, DSIZE*sizeof(float), cudaMemcpyHostToDevice);
デバイスカーネル定義には、次のような関数パラメーターが必要です。
__global__ void myKernel(float ap[][COL]) {
次に、カーネル内で、次のようにx、yの要素にアクセスできます。
float my_val_xy = ap[x][y];
LRを変更できない場合の対処方法を尋ねるフォローアップの質問に答えて、LR構造を変更せずにこれらのアイデアのいくつかを組み合わせた完全なサンプルコードを次に示します。
#include<stdio.h>
// for cuda error checking
#define cudaCheckErrors(msg) \
do { \
cudaError_t __err = cudaGetLastError(); \
if (__err != cudaSuccess) { \
fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
msg, cudaGetErrorString(__err), \
__FILE__, __LINE__); \
fprintf(stderr, "*** FAILED - ABORTING\n"); \
return 1; \
} \
} while (0)
struct LR {
int foo;
float antenna_pattern[361][1001];
} LR;
__global__ void mykernel(float ap[][1001]){
int tid = threadIdx.x + (blockDim.x*blockIdx.x);
float myval = 0.0;
if (tid == 0){
for (int i=0; i<361; i++)
for (int j=0; j<1001; j++)
ap[i][j] = myval++;
}
}
int main(){
typedef float aParray[1001];
aParray *d_antenna_pattern;
cudaMalloc((void **) &d_antenna_pattern, (361*1001)*sizeof(float));
cudaCheckErrors("cudaMalloc fail");
float *my_ap_ptr;
my_ap_ptr = &(LR.antenna_pattern[0][0]);
for (int i=0; i< 361; i++)
for (int j=0; j<1001; j++)
LR.antenna_pattern[i][j] = 0.0;
cudaMemcpy(d_antenna_pattern, my_ap_ptr, (361*1001)*sizeof(float), cudaMemcpyHostToDevice);
cudaCheckErrors("cudaMemcpy fail");
mykernel<<<1,1>>>(d_antenna_pattern);
cudaCheckErrors("Kernel fail");
cudaMemcpy(my_ap_ptr, d_antenna_pattern, (361*1001)*sizeof(float), cudaMemcpyDeviceToHost);
cudaCheckErrors("cudaMemcpy 2 fail");
float myval = 0.0;
for (int i=0; i<361; i++)
for (int j=0; j<1001; j++)
if (LR.antenna_pattern[i][j] != myval++) {printf("mismatch at offset x: %d y: %d actual: %f expected: %f\n", i, j, LR.antenna_pattern[i][j], --myval); return 1;}
printf("Results match!\n");
return 0;
}
フラット化された方法を使用する場合は、d_antenna_pattern
定義を次のように置き換えます。
float *d_antenna_pattern;
そして、それに応じてカーネル関数パラメータを変更します。
__global__ void mykernel(float *ap){
次に、カーネルのポインタ演算メソッドを使用してアクセスします。
ap[(i*1001)+j] = myval++;