我在CUDA中分配数组数组时遇到了一些麻烦。
void ** data;
cudaMalloc(&data, sizeof(void**)*N); // allocates without problems
for(int i = 0; i < N; i++) {
cudaMalloc(data + i, getSize(i) * sizeof(void*)); // seg fault is thrown
}
我错了什么?
答案 0 :(得分:11)
您必须将指针分配给主机内存,然后为每个阵列分配设备内存并将其指针存储在主机内存中。 然后分配内存以将指针存储到设备中 然后将主机内存复制到设备内存。 一个例子值1000字:
__global__ void multi_array_kernel( int N, void** arrays ){
// stuff
}
int main(){
const int N_ARRAYS = 20;
void *h_array = malloc(sizeof(void*) * N_ARRAYS);
for(int i = 0; i < N_ARRAYS; i++){
cudaMalloc(&h_array[i], i * sizeof(void*));
//TODO: check error
}
void *d_array = cudaMalloc(sizeof(void*) * N_ARRAYS);
// Copy to device Memory
cudaMemcpy(d_array, h_array, sizeof(void*) * N_ARRAYS, cudaMemcpyHostToDevice);
multi_array_kernel<1,1>(N_ARRAYS, d_array);
cudaThreadSynchronize();
for(int i = 0; i < N_ARRAYS; i++){
cudaFree(h_array[i]); //host not device memory
//TODO: check error
}
cudaFree(d_array);
free(h_array);
}
答案 1 :(得分:4)
我不相信这是支持的。 cudaMalloc()
分配设备内存,但将地址存储在主机上的变量中。在你的for循环中,你将它的地址传递给设备内存。
根据您要完成的操作,您可能希望在调用for循环之前将data
与普通主机malloc()
分配,就像您当前拥有它一样。或者分配一大块设备内存并手动计算偏移量。
请查看CUDA Programming Guide的第2.4,3.2.1和B.2.5节(底部),以便对此进行更多讨论。具体来说,在第108页的底部:
通过获取
__device__
,__shared__
或地址获得的地址__constant__
变量只能在设备代码中使用。
答案 2 :(得分:2)
我认为在第一个循环中它应该是&h_array[i]
而不是&d_array[i]
。
答案 3 :(得分:1)
你不能使用
cudaMalloc(&h_array[i], i * sizeof(void*));
表示声明为void *
使用已定义的数据类型
CUdeviceptr *h_array = malloc(sizeof(CUdeviceptr *) * N);
或
int *h_array = malloc(sizeof(int *) * N);
并将其投放到void *
cudaMalloc((void *)&h_array[i], i * sizeof(void*));
答案 4 :(得分:1)
nvidia论坛中的类似主题 - http://forums.nvidia.com/index.php?showtopic=69403&st=20
答案 5 :(得分:1)
我有同样的问题并设法解决它。
FabrizioM的答案对我来说是一个很好的开始并帮助了我很多。但是当我尝试将代码传输到我的项目时,我遇到了一些问题。使用其他评论和帖子,我能够编写一个工作示例(VS2012,CUDA7.5)。因此,我将发布我的代码作为额外的答案,并作为开始其他人的点。
理解命名:我使用OpenCV cv :: Mat矢量作为输入,从多个摄像头捕获,我在内核中处理这些图像。
void TransferCameraImageToCuda(const std::vector<cv::Mat*>* Images)
{
int NumberCams = Images->size();
int imageSize = Images->at(0)->cols*Images->at(0)->rows;
CUdeviceptr* CamArraysAdressOnDevice_H;
CUdeviceptr* CamArraysAdressOnDevice_D;
//allocate memory on host to store the device-address of each array
CamArraysAdressOnDevice_H = new CUdeviceptr[NumberCams];
// allocate memory on the device and store the arrays on the device
for (int i = 0; i < NumberCams; i++){
cudaMalloc((void**)&(CamArraysAdressOnDevice_H[i]), imageSize * sizeof(unsigned short));
cudaMemcpy((void*)CamArraysAdressOnDevice_H[i], Images->at(i)->data, imageSize * sizeof(unsigned short), cudaMemcpyHostToDevice);
}
// allocate memory on the device to store the device-adresses of the arrays
cudaMalloc((void**)&CamArraysAdressOnDevice_D, sizeof(CUdeviceptr*)* NumberCams);
// Copy the adress of each device array to the device
cudaMemcpy(CamArraysAdressOnDevice_D, CamArraysAdressOnDevice_H, sizeof(CUdeviceptr*)* NumberCams, cudaMemcpyHostToDevice);
}
在内核启动中,我将设备指针转换为数据类型指针(unsigned short **)
DummyKernel<<<gridDim,blockDim>>>(NumberCams, (unsigned short**) CamArraysAdressOnDevice_D)
,内核定义例如:
__global__ void DummyKernel(int NumberImages, unsigned short** CamImages)
{
int someIndex = 3458;
printf("Value Image 0 : %d \n", CamImages[0][someIndex]);
printf("Value Image 1 : %d \n", CamImages[1][someIndex]);
printf("Value Image 2 : %d \n", CamImages[2][someIndex]);
}