CUDA共享内存速度

时间:2012-11-18 21:24:43

标签: c cuda hpc

这是与性能相关的问题。我根据“CUDA By Example”示例代码编写了以下简单的CUDA内核:

#define N 37426 /* the (arbitrary) number of hashes we want to calculate */
#define THREAD_COUNT 128

__device__ const unsigned char *m = "Goodbye, cruel world!";

__global__ void kernel_sha1(unsigned char *hval) {
  sha1_ctx ctx[1];
  unsigned int tid = threadIdx.x + blockIdx.x * blockDim.x;

  while(tid < N) {
    sha1_begin(ctx);
    sha1_hash(m, 21UL, ctx);
    sha1_end(hval+tid*SHA1_DIGEST_SIZE, ctx);
    tid += blockDim.x * gridDim.x;
  }
}

在我看来,代码是正确的,确实吐出了相同散列的37,426个副本(正如预期的那样。根据我对第5章第5.3节的解读,我假设写入全局内存的每个线程都传入了“ hval“效率极低。

然后,我实现了我认为使用共享内存的性能提升缓存。代码修改如下:

#define N 37426 /* the (arbitrary) number of hashes we want to calculate */
#define THREAD_COUNT 128

__device__ const unsigned char *m = "Goodbye, cruel world!";

__global__ void kernel_sha1(unsigned char *hval) {
  sha1_ctx ctx[1];
  unsigned int tid = threadIdx.x + blockIdx.x * blockDim.x;
  __shared__ unsigned char cache[THREAD_COUNT*SHA1_DIGEST_SIZE];

  while(tid < N) {
    sha1_begin(ctx);
    sha1_hash(m, 21UL, ctx);
    sha1_end(cache+threadIdx.x*SHA1_DIGEST_SIZE, ctx);

    __syncthreads();
    if( threadIdx.x == 0) {
      memcpy(hval+tid*SHA1_DIGEST_SIZE, cache, sizeof(cache));
    }
    __syncthreads();
    tid += blockDim.x * gridDim.x;
  }
}

第二个版本似乎也能正常运行,但比初始版本慢几倍。后一代码在大约8.95毫秒内完成,而前者在大约1.64毫秒内运行。我对Stack Overflow社区的问题很简单:为什么?

1 个答案:

答案 0 :(得分:2)

我通过示例查看了CUDA,找不到任何类似的内容。是的,附录中有一些关于GPU哈希表的讨论,但它看起来不像这样。所以我真的不知道你的函数是做什么的,特别是sha1_end。如果此代码与该书中的内容类似,请指出,我错过了。

但是,如果sha1_end一次(每个线程)写入全局内存并以合并的方式写入全局内存,则没有理由它不能非常高效。据推测,每个线程都写入不同的位置,因此如果它们或多或少相邻,那么肯定有机会进行合并。在不进入合并细节的情况下,可以说它允许多个线程在单个事务中将数据写入内存 。如果你要将你的数据写入全局记忆,你将不得不至少在某个地方支付这笔罚款。

对于你的修改,你完全杀了这个概念。您现在已经从单个线程执行了所有数据复制,而memcpy意味着后续数据写入(整数或字符,无论如何)都发生在单独的事务中。是的,有一个缓存可以帮助解决这个问题,但在GPU上执行它是完全错误的方法。让每个线程更新全局内存,并利用机会并行执行。但是当您在单个线程上强制执行所有更新时,该线程必须按顺序复制数据。这可能是时间差异中最大的单一成本因素。

使用__syncthreads()也会产生额外费用。

CUDA by Example book的第12.2.7节引用了visual profiler(并提到它可以收集有关合并访问的信息)。视觉分析器是帮助尝试回答这类问题的好工具。

如果您想了解有关高效内存技术和合并的更多信息,我建议使用名为“使用CUDA C进行GPU计算 - 高级1(2010)”的NVIDIA GPU计算webinar。与here的直接链接为slides