如何使用short或char类型的元素将全局内存中的读取正确地合并到共享内存中(假设每个元素有一个线程)?

时间:2012-01-20 23:50:21

标签: cuda gpu nvidia

我对CUDA中合并的全局内存负载有疑问。目前,我需要能够在具有计算能力CUDA 1.1或1.3的CUDA设备上执行。

我正在编写一个CUDA内核函数,它将类型为T的数组从全局内存读入共享内存,进行一些计算,然后将类型T的数组写回全局内存。我正在使用共享内存,因为每个输出元素的计算实际上不仅取决于相应的输入元素,还取决于附近的输入元素。我只想加载每个输入元素一次,因此我想将输入元素缓存在共享内存中。

我的计划是让每个线程在开始计算之前将一个元素读入共享内存,然后__syncthreads()。在这种情况下,每个线程加载,计算和存储一个元素(尽管计算依赖于其他线程加载到共享内存中的元素)。

对于这个问题,我想集中讨论从全局内存到共享内存的读取。

假设数组中有N个元素,我已配置CUDA以执行总共N个线程。对于sizeof(T)== 4的情况,根据我对CUDA的理解,这应该很好地合并,因为线程K将读取单词K(其中K是线程索引)。

但是,在sizeof(T) < 4的情况下,例如如果T = unsigned char或T = short,那么我认为可能存在问题。在这种情况下,我的(天真)计划是:

  • 计算numElementsPerWord = 4 / sizeof(T)
  • if(K%numElementsPerWord == 0),然后读取线程K读取下一个完整的32位字
  • 将32位字存储在共享内存中
  • 在填充共享内存之后(和__syncthreads()调用)然后每个线程K可以处理计算输出元素K的工作

我担心的是它不会合并,因为(例如,在T =短的情况下)

  • 线程0从全局存储器读取字0
  • 线程1无法读取
  • 线程2从全局存储器读取字1
  • 线程3无法读取
  • 等...

换句话说,线程K读取字(K / sizeof(T))。这似乎没有正确地合并。

我考虑的另一种方法是:

  • 以线程数=(N + 3)/ 4启动,这样每个线程将负责加载和处理(4 / sizeof(T))元素(每个线程处理一个32位字 - 可能是1,取决于尺寸(T)的2或4个元素。但是我担心这种方法不会尽可能快,因为每个线程必须做两次(如果T =短)或甚至四倍(如果T = unsigned char)处理量。

有人可以告诉我,我对我的计划的假设是否正确:即:它不能正常合并?

请您评论我的替代方法吗?

您能推荐一种能够正确合并的更佳方法吗?

1 个答案:

答案 0 :(得分:3)

你是对的,你必须做至少32位的加载才能合并,你描述的方案(让其他所有线程都加载)将不会合并。只需将偏移量右移2位,让每个线程执行连续的32位加载,并使用条件代码禁止执行将在超出范围的地址上运行的线程。

由于您的目标是SM 1.x,请注意1)为了进行合并,给定warp的线程0(32个线程的集合)必须为64,128或256字节对齐4 - ,分别为8和16字节操作数,以及2)一旦您的数据在共享内存中,您可能希望将循环展开2x(简称)或4x(对于char),因此相邻的线程引用相邻的32位单词,以避免共享内存库冲突。

相关问题