结构中的指针传递给CUDA
问题描述:
我一直在这里搞乱了一段时间,但似乎无法做到正确。我试图复制包含数组到CUDA设备内存中的对象(和回来,但我会船到桥头时,我来给它):结构中的指针传递给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),我可以访问数据[idx] .dataLen就好了。但是,数据[idx] .data尚未被复制。
我不能在copyToGPU使用d_items.data作为由于主机代码cudaMalloc/cudaMemCpy操作的目的地不能解除引用的装置指针。
怎么办?
答
- 将所有 结构的设备数据分配为单个阵列。
- 将连续数据从主机复制到 GPU。
- 调整GPU指针
例如:
float *d_data;
cudaMalloc((void**)&d_data, N*100*sizeof(float));
for (...) {
h_items[i].data = i*100 + d_data;
}
答
你只提供复印件MyData的结构代码:一个主机地址和一个整数。为了清楚起见,您正在复制指针而不是数据 - 您必须明确复制数据。
如果数据总是相同的LENGTH
,那么你可能只想做一个大阵列:
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]]