结构体中的指针传递给CUDA

4

我已经尝试了一段时间,但似乎无法做到正确。我正在尝试将包含数组的对象复制到CUDA设备内存中(并在需要时再次复制回来):

struct MyData {
  float *data;
  int dataLen;
}

void copyToGPU() {
  // Create dummy objects to copy
  int N = 10;
  MyData *h_items = new MyData[N];
  for (int i=0; i<N; i++) {
    h_items[i].dataLen = 100;
    h_items[i].data = new float[100];
  }

  // Copy objects to GPU
  MyData *d_items;
  int memSize = N * sizeof(MyData);
  cudaMalloc((void**)&d_items, memSize);
  cudaMemCpy(d_items, h_items, memSize, cudaMemcpyHostToDevice);

  // Run the kernel
  MyFunc<<<100,100>>>(d_items);
}

__global__
static void MyFunc(MyData *data) {
  int idx = blockIdx.x * blockDim.x + threadIdx.x;
  for (int i=0; i<data[idx].dataLen; i++) {
    // Do something with data[idx].data[i]
  }
}

当我调用MyFunc(d_items)时,我可以很好地访问data[idx].dataLen。然而,data[idx].data尚未被复制。
由于主机代码无法解引用设备指针,因此我无法在copyToGPU中使用d_items.data作为cudaMalloc/cudaMemCpy操作的目标。
该怎么办?
2个回答

3
  • 为所有结构分配设备数据,作为单个数组。
  • 从主机复制连续的数据到GPU。
  • 调整GPU指针。

示例:

float *d_data;
cudaMalloc((void**)&d_data, N*100*sizeof(float));
for (...) {
    h_items[i].data = i*100 + d_data;
}

2
你提供的代码只复制了MyData结构体:一个主机地址和一个整数。为了更加清晰,你复制的是指针而不是数据 - 你必须显式地复制数据。
如果数据始终相同长度,则可能只需创建一个大数组:
float *d_data;
memSize = N * LENGTH * sizeof(float);
cudaMalloc((void**) &d_data, memSize);

//and a single copy
cudaMemcpy(d_data, h_data, memSize, cudaMemcpyHostToDevice);

如果需要与其他数据结构一起使用,则:

struct MyData {
  float data[LENGTH];
  int other_data;
}

MyData *d_items;
memSize = N * sizeof(MyData);
cudaMalloc((void**) &d_items, memSize);

//and again a single copy
cudaMemcpy(d_data, h_data, memSize, cudaMemcpyHostToDevice);

但是,我假设您拥有各种长度的数据。一种解决方案是将LENGTH设置为最大长度(浪费一些空间),然后按照上述方式进行操作。这可能是最简单的开始方式,然后您可以进行优化。

如果您无法承受丢失的内存和传输时间,则需要三个数组,一个包含所有数据,然后一个包含主机和设备的偏移量和长度:

//host memory
float *h_data;
int h_offsets[N], h_lengths[N]; //or allocate these dynamically if necessary
int totalLength;

//device memory
float *d_data;
int *d_offsets, *d_lengths;

/* calculate totalLength, allocate h_data, and fill the three arrays */

//allocate device memory
cudaMalloc((void**) &d_data, totalLength * sizeof(float));
cudaMalloc((void**) &d_ffsets, N * sizeof(int));
cudaMalloc((void**) &d_lengths, N * sizeof(int));

//and now three copies
cudaMemcpy(d_data, h_data, totalLength * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(d_offsets, h_offsets, N * sizeof(int); cudaMemcpyHostToDevice);
cudaMemcpy(d_lengths, h_lengths, N * sizeof(int); cudaMemcpyHostToDevice);

现在在线程i中,您可以找到从d_data[d_offsets[i]]开始的数据,其长度为d_data[d_lengths[i]]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接