当它是结构的属性时,如何通过引用传递多维数组?

时间:2012-11-27 19:05:21

标签: c++ arrays pointers struct cuda

我有以下内容:

struct LR { double eps_dielect; 
        double sgm_conductivity; 
        double eno_ns_surfref;
        double frq_mhz; 
        double conf; 
        double rel;
        double erp;
        int radio_climate;  
        int pol;
        float antenna_pattern[361][1001];
          } LR;

我需要将LR.antenna_pattern传递给一个函数,在CUDA设备中分配内存然后复制它。 float **类型应该代表LR.antenna_pattern [361] [1001]就好但我不知道如何实例化float **变量,以便它是一个指向LR.antenna_pattern的指针

我尝试浮动** antennaPattern =(void **)& LR.antenna_pattern但它不起作用。如何创建指向LR.antenna_pattern的指针?

1 个答案:

答案 0 :(得分: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执行此操作。有关示例,请参阅我对this question的回答中的第一个代码示例。要想出这个,你需要从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++;