一种方法是展平您的 2D 数组并以 1D 方式处理它,并使用指针算法来处理行和列维度。首先在您的结构定义中,将天线模式元素替换为:
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
如果你想在整个过程中保持二维数组下标,你可以使用适当的 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));
设备端 cuda malloc 看起来像:
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++;