CUDA:写入共享内存会增加内核时间执行

时间:2013-03-15 10:31:21

标签: cuda

我试图在CUDA的帮助下减少65536个元素数组(计算其中元素的总和)。内核看起来如下(请忽略* dev_distanceFloats和索引参数)

__global__ void kernel_calcSum(float *d, float *dev_distanceFloats, int index) {
  int tid = threadIdx.x;
  float mySum = 0;
  for (int e = 0; e < 256; e++) {
    mySum += d[tid + e];
  }
} 

ant它作为一个具有256个线程的块启动:

kernel_calcSum <<<1,  256 >>>(dev_spFloats1, dev_distanceFloats, index);

到目前为止,非常好,每个256个线程从全局内存中获取256个元素,并在局部变量mySum中计算它的总和。内核执行时间约为45毫秒。 下一步是在块中的256个线程之间引入共享内存(以计算mySum的总和),因此内核变为如下:

__global__ void kernel_calcSum(float *d, float *dev_distanceFloats, int index) {
  __shared__ float sdata[256];
  int tid = threadIdx.x;
  float mySum = 0;
  for (int e = 0; e < 256; e++) {
    mySum += d[tid + e];
  }
  sdata[tid] = mySum;
}  

我刚刚添加了对共享内存的写入,但执行时间从45毫秒增加到258毫秒(我在NVidia Visual Profiler 5.0.0的帮助下对此进行了检查)。 我发现在写入sdata变量时,每个线程都有8个存储体冲突(我在GTX670上有32个存储区的能力3.0)。作为一个实验 - 我试图在启动内核时将线程减少到32 - 但时间仍然是258毫秒。

问题1:为什么写共享内存需要花费很长时间? 问题2:是否有任何工具,详细显示了“执行计划”(内存访问时间,冲突等)?

感谢您的建议。

更新 玩内核 - 我为每个线程设置了一个常量的sdata:

__global__ void kernel_calcSum(float *d, float *dev_distanceFloats, int index) {
  __shared__ float sdata[256];
  int tid = threadIdx.x;
  float mySum = 0;
  for (int e = 0; e < 256; e++) {
    mySum += d[tid + e];
  }
  sdata[tid] = 111;
} 

时间又恢复到48毫秒。 所以,改变 sdata [tid] = mySum; 至 sdata [tid] = 111; 做了这个。

这个编译器是否优化(可能只是删除了这一行?)或者由于某种原因从本地内存(寄存器?)复制到共享需要很长时间?

2 个答案:

答案 0 :(得分:0)

共享内存不是正确的。你需要的是warp原子操作,在warp中总结,然后在warp之间传递中间结果。这里有一些示例代码,演示了使用CUDA进行此次运送。

总结元素是大量并行化无济于事的任务之一,GPU实际上可以胜过CPU。

答案 1 :(得分:0)

两个内核都没有做任何事情,因为它们不会将结果写出到内核完成后仍然可以访问的内存。

在第一种情况下,编译器足够聪明地注意到这一点并优化掉整个计算。 在涉及共享内存的第二种情况下,编译器不会注意到这一点,因为通过共享内存的信息流将更难以跟踪。因此,它将计算结果。

传入一个指向全局内存的指针(就像你已经做的那样)并通过这个指针写出结果。