Memory CUDA中全局内存与常量内存的使用
嘿,那里, 我有以下代码:Memory CUDA中全局内存与常量内存的使用,memory,cuda,Memory,Cuda,嘿,那里, 我有以下代码: #if USE_CONST == 1 __constant__ double PNT[ SIZE ]; #else __device__ double *PNT; #endif 过了一会儿,我有: #if USE_CONST == 0 cudaMalloc((void **)&PNT, sizeof(double)*SIZE); cudaMemcpy(PNT, point, sizeof(double)*SIZE, c
#if USE_CONST == 1
__constant__ double PNT[ SIZE ];
#else
__device__ double *PNT;
#endif
过了一会儿,我有:
#if USE_CONST == 0
cudaMalloc((void **)&PNT, sizeof(double)*SIZE);
cudaMemcpy(PNT, point, sizeof(double)*SIZE, cudaMemcpyHostToDevice);
#else
cudaMemcpyToSymbol(PNT, point, sizeof(double)*SIZE);
#endif
然而,点
在前面的代码中有定义。当使用时,使用_CONST=1
一切都能按预期工作,但如果不使用它,则不会。我通过访问内核函数中的数组
PNT[索引]
这两种变体之间的问题在哪里?
谢谢 CUDA 4.0之前CUDAMEMCPITOSYMBOL的正确用法是:
cudaMemcpyToSymbol("PNT", point, sizeof(double)*SIZE)
或者:
double *cpnt;
cudaGetSymbolAddress((void **)&cpnt, "PNT");
cudaMemcpy(cpnt, point, sizeof(double)*SIZE, cudaMemcpyHostToDevice);
如果您计划多次从主机API访问符号,那么这可能会快一点
编辑:误解了这个问题。对于全局内存版本,执行与第二个版本类似的操作以获得恒定内存
double *gpnt;
cudaGetSymbolAddress((void **)&gpnt, "PNT");
cudaMemcpy(gpnt, point, sizeof(double)*SIZE. cudaMemcpyHostToDevice););
虽然这是一个老问题,但我还是为未来的谷歌用户补充了这个问题: 问题在于:
cudaMalloc((void **)&PNT, sizeof(double)*SIZE);
cudaMemcpy(PNT, point, sizeof(double)*SIZE, cudaMemcpyHostToDevice);
cudamaloc
写入主机版本的PNT
,这实际上是一个不能从主机访问的设备变量。正确的做法是分配内存,将地址复制到设备符号,并将内存复制到该符号指向的内存:
void* memPtr;
cudaMalloc(&memPtr, sizeof(double)*SIZE);
cudaMemcpyToSymbol(PNT, &memPtr, sizeof(memPtr));
// In other places you'll need an additional:
// cudaMemcpyFromSymbol(&memPtr, PNT, sizeof(memPtr));
cudaMemcpy(memPtr, point, sizeof(double)*SIZE, cudaMemcpyHostToDevice);
更容易的办法是:
#if USE_CONST == 1
__constant__ double PNT[ SIZE ];
#else
__device__ double PNT[ SIZE ];
#endif
// No #if required anymore:
cudaMemcpyToSymbol(PNT, point, sizeof(double)*SIZE);
好的,首先谢谢。奇怪的是,它在没有引语的情况下工作。。。但我要求的是在没有
USE_CONST=1
时的访问,这意味着使用带有全局内存的块<代码>\uuuu设备\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu代码>等。。。然后它就不正确了:(有什么不对吗?Talonmes关于如何做的回答是正确的(所以我投了赞成票),但它缺乏解释。解释是:*PNT
是一个\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu设备变量,而不是一个包含设备变量地址的主机变量。(我知道这很混乱。)因此,如果您试图通过(void**)和PNT在主机上访问它,则您试图从主机读取一个不允许的设备变量。从主机代码的角度来看,它只是一个符号,因此您需要使用cudaGetSympolAddress()
将设备地址存储在主机变量中,然后您可以将其传递给@talonmies所示的cudaMemcpyToSymbol()。此处显示的用法无法正确使用!cudaMemcpyToSymbol
的使用已经使用了cudaGetSymbolAddress
,因此两次使用它可能会打破访问越界的情况。未初始化的常量内存设置为0,因为它在全局空间中未定义。