CUDA全局内存复制

时间:2012-05-31 12:48:33

标签: cuda

CUDA C编程指南(p.70)说,

  

全局内存驻留在设备内存中,访问设备内存   通过32,64或128字节的内存事务。这些记忆   事务必须自然对齐:只有32,64或128字节   设备存储器的各个部分与它们的大小对齐(即其大小)   第一个地址是其大小的倍数)可以读取或写入   记忆交易。

所以,如果我想在设备功能中一次访问32,64或128个连续字节,(例如,复制到共享内存)什么是最合适的功能(或赋值)这次行动?

传统的C memcpy函数似乎一次不能访问32个字节(速度非常慢)。因为这不是矢量数据,所以我希望单个线程一次读取这些数据。


到dbaupp

memcpy效果很好,但我说的是速度。 例如,假设我有设备内存指针p并在设备功能中运行以下代码。

a)char c [8]; memcpy(c,p,8);

b)char c [8]; *(double *)c = *(double *)p;

对于上述两种情况,结果相同,但情况b比情况a快了近8倍(我在我的代码中测试并确认)。

而且仅供参考,cudaMemcpy功能在设备功能中不起作用。

所以,我想知道的是,是否有任何方法可以在单个操作中复制16个字节。 (希望比memcpy快16倍(c,p,16);)

1 个答案:

答案 0 :(得分:6)

这并不是100%清楚你想要做什么。如果您尝试将数据从全局复制到共享内存,那么可能它有一些结构,例如一组charfloat s或其他内容。以下答案将假设您正在处理一组char s(您可以用任何数据类型替换char)。

摘要:不要考虑一次显式访问32/64/128字节,只需编写代码,以便可以合并内存访问。


您可以使用CUDA访问数据,就像在普通的C / C ++ /中一样。你甚至可以得到单个字节。编程指南所说的是每当访问数据时,必须读取32/64/128字节的块。例如。如果您有char a[128]并希望获得a[17],则GPU必须从a[0]读取到a[31]才能获取a[17]中的数据。这种情况透明地发生,因为您不需要以任何不同的方式编码以便能够访问单个字节。

主要考虑因素是内存访问速度:如果必须为每个信息字节读取31个垃圾字节,那么您将有效内存带宽减少32倍(这也意味着您必须进行更多的全局内存访问) ,这是sloowww)!

但是,GPU上的内存访问可以在块中的线程之间“合并”(this question为优化合并提供了合理的起点。)。简而言之,合并允许对块中的多个线程同时发生的内存访问可以“批处理”在一起,这样只需要进行一次读取。

关键在于块内的线程(不在单个线程内)之间发生合并,因此对于复制到共享内存,可以做到(array是{{1}的数组在全局内存中):

char

这将使每个线程将一个字节复制到共享阵列中。这个memcpy操作基本上是并行进行的,并且数据访问是合并的,因此没有浪费的带宽(或时间)。

上述策略比单个线程迭代并逐字节复制要好得多

还可以将数组的每个 n 字节块视为单个 n 字节数据类型,并让每个线程复制该数据。例如对于 n == 16,请对__shared__ char shrd[SIZE]; shrd[threadIdx.x] = array[blockDim.x * blockIdx.x + threadIdx.x]; __syncthreads();

进行一些演员表
uint4

这将允许每个线程一次复制16个字节。关于那段代码的注释:

  • 我没有测试或基准测试
  • 我不知道这是不是好习惯(我强烈希望不是这样)。)
  • 指数按比例缩放16(例如__shared__ char shrd[SIZE]; ((uint4*)shrd)[threadIdx.x] = ((uint4*)array)[blockDim.x * blockIdx.x + threadIdx.x]; __syncthreads(); 对应于写入threadIdx.x == 1

作为旁注:根据您的具体用例,built-in cudaMemcpy functions可能会有用。