CUDA的cudaMemcpyToSymbol()函数抛出“无效参数”错误

5

问题

我试图将一个 int 数组复制到设备的常量内存中,但是我一直收到以下错误:

[ERROR] 'invalid argument' (11) in 'main.cu' at line '386'

代码

有很多开发代码,所以我将简化我现有的内容。

我已经在主文件 main.cu 的顶部声明了一个设备 __constant__ 变量,在任何函数之外。

__device__ __constant__ int* dic;

我还有一个托管变量flatDic,它是在main()内进行以下方式的分配的:

int* flatDic = (int *)malloc(num_codewords*(bSizeY*bSizeX)*sizeof(int));

接下来我尝试将flatDic的内容复制到dic中,方法如下,在main()函数中实现:

cudaMemcpyToSymbol(dic, flatDic, num_codewords*(bSizeY*bSizeX)*sizeof(int));

这个错误出现在 main.cu 的第 386 行,是由 cudaMemcpyToSymbol() 调用引起的。 我尝试过的方法 到目前为止,我已经尝试了以下所有方法,但仍然返回相同的错误:
cudaMemcpyToSymbol(dic, &flatDic, num_codewords*(bSizeY*bSizeX)*sizeof(int));

cudaMemcpyToSymbol(dic, flatDic, num_codewords*(bSizeY*bSizeX)*sizeof(int));

cudaMemcpyToSymbol(dic, &flatDic, num_codewords*(bSizeY*bSizeX)*sizeof(int), 0, cudaMemcpyHostToDevice);

cudaMemcpyToSymbol(dic, flatDic, num_codewords*(bSizeY*bSizeX)*sizeof(int), 0, cudaMemcpyHostToDevice);

我也尝试使用 cudaMalloc() 分配 dic 变量的内存,在调用 cudaMemcpyToSymbol() 之前。在 cudaMalloc() 中没有出现任何错误,但是 cudaMemcpyToSymbol() 错误仍然存在。

cudaMalloc((void **) &dic, num_codewords*(bSizeY*bSizeX)*sizeof(int));

我也在网上、文档、论坛、示例等地广泛搜索,但都没有结果。

有人看到我的代码有什么问题吗?先谢谢了。


1
我也在网上、文档、论坛、示例等方面进行了广泛的搜索,但都没有结果。对于基本调用,始终从CUDA C编程指南开始:1.按下“Ctrl + S”,在浏览器/PDF阅读器中输入您要查找的调用。2.阅读任何适用的内容并查看指南的代码示例。3.如果第2步失败,那么才去论坛潜水。在这种情况下,信息直接来自NVIDIA指南--这是关于如何处理CUDA API调用问题的一些未来建议。 - Jason R. Mick
1
我通常会先查看参考指南,它以HTML格式提供。这是CUDA 4.1参考指南,通过谷歌搜索调用名称通常也会得到参考指南。在检查参考指南后,再查看编程指南。 - harrism
1个回答

6

cudaMemcpyToSymbol函数用于将数据拷贝到常量变量。在这里,您试图将多个int类型的字节(即已分配的数组)拷贝到int *类型指针中。由于这些类型不同,因此会出现“无效类型”的错误。为了使其工作,您需要将一个已分配的int数组拷贝到设备上静态长度的int常量数组中,例如:

__device__ __constant__ int dic[LEN];

以下是来自CUDA C编程指南中的示例(我建议您阅读该指南——非常好!):

__constant__ float constData[256];
float data[256];
cudaMemcpyToSymbol(constData, data, sizeof(data));
cudaMemcpyFromSymbol(data, constData, sizeof(data));

据我所知,您也可以使用cudaMemcpyToSymbol将指向指针的指针复制(与您的示例不同,您正在将数组复制到指针)。但请注意,只有指针是常量,而不是它指向的设备内存。如果您要走这条路,您需要添加cudaMalloc,然后将结果指针的cudaMemcpyToSymbol复制到您的__constant__设备变量的设备内存中。同样,在这种情况下,数组值将不是常量 - 只有对内存的指针才是常量。
对于此情况,您的调用可能类似于:
int * d_dic;
cudaMalloc((void **) &d_dic, num_codewords*(bSizeY*bSizeX)*sizeof(int));
cudaMemcpyToSymbol(c_dic_ptr, &d_Dic, sizeof(int *));

在调试期间,您应该将CUDA调用包含在错误检查逻辑中。我从talonmies借用了以下逻辑:

__inline __host__ void gpuAssert(cudaError_t code, char *file, int line, 
                 bool abort=true)
{
   if (code != cudaSuccess) 
   {
      fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code),
          file, line);
      if (abort) exit(code);
   }
}

#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }

为了调用它,只需将您的CUDA调用包装在其中,就像这样:

gpuErrchk(cudaMemcpyToSymbol(dic, flatDic, num_codewords*(bSizeY*bSizeX)*sizeof(int)));

如果您遇到分配问题或其他常见错误,程序将退出并显示错误消息。

要检查您的内核,请执行以下操作:

MyKernel<<<BLK,THRD>>>(vars...);

//Make sure nothing went wrong.
gpuErrchk(cudaPeekAtLastError());
gpuErrchk(cudaDeviceSynchronize());

感谢talonmies提供了错误检查代码!

注意:
即使您只是使用基本的cudaMemcpy,您的代码也会失败,因为您尚未为数组分配内存 - 在这种情况下,失败可能是GPU中的段错误等效(可能是 Unspecified launch failure ),因为指针将具有某种垃圾值,您将尝试使用该垃圾值给出的地址写入内存。


请注意,cudaMemcpyToSymbol中的大小为sizeof(int*)而不是sizeof(int),因为它实际上是指针复制。 - Jitendra Kulkarni

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