假设我有一个32个线程的块需要随机访问1024个元素数组。我想通过最初将块从全局转移到共享来减少全局内存调用的数量。我有两个想法:
A:
my_kernel()
{
CopyFromGlobalToShared(1024 / 32 elements);
UseSharedMemory();
}
或B:
my_kernel()
{
if (first thread in block)
{
CopyFromGlobalToShared(all elements);
}
UseSharedMemory();
}
哪个更好?还是有另一种更好的方法吗?
答案 0 :(得分:4)
A更好。
与CPU相比,GPU具有更高的内存带宽。但是,只有当GPU中运行的线程遵循某种模式时,才能实现峰值带宽。
此模式需要合并mem访问权限。这意味着您需要使用多个线程来访问全局内存中的顺序地址,并特别注意对齐。
您可以在CUDA文档中找到有关Coalesced Access to Global Memory的更多详细信息。
http://docs.nvidia.com/cuda/cuda-c-best-practices-guide/index.html#coalesced-access-global-memory
答案 1 :(得分:0)
A更好,但取决于元素的大小 - 不一定是最好的!
你想要的是每个线程访问32位大小的相邻字(64位也可以在更新的硬件上工作)。如果元素大小更大,您可能更喜欢更有趣:
//assumes sizeof(T) is multiple of sizeof(int)
//assumes single-dimention kernel
//assumes it is launched for all threads in block
template <typename T>
__device__ void memCopy(T* dest, T* src, size_t size) {
int* iDest = (int*)dest;
int* iSrc = (int*)src;
for(size_t i = threadIdx.x; i<size*sizeof(T)/sizeof(int); i+=blockDim.x)
iDest[i] = iSrc[i];
__syncthreads();
}
注意:这适用于所有内存传输(global-&gt; global,global-&gt; shared,shared-&gt; global)。即使是没有统一内存寻址的旧设备也是如此,因为该功能将被内联。
如果对更大的元素使用数组结构方法,则问题不会出现。