【问题标题】:prefix sum using CUDA使用 CUDA 的前缀和
【发布时间】:2018-09-18 01:12:44
【问题描述】:

我无法理解幼稚前缀总和的 cuda 代码。

这是代码来自https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch39.html 在示例 39-1(朴素扫描)中,我们有这样的代码:

 __global__ void scan(float *g_odata, float *g_idata, int n)
    {
    extern __shared__ float temp[]; // allocated on invocation
    int thid = threadIdx.x;
    int pout = 0, pin = 1;
    // Load input into shared memory.
    // This is exclusive scan, so shift right by one
    // and set first element to 0
    temp[pout*n + thid] = (thid > 0) ? g_idata[thid-1] : 0;
 __syncthreads();

 for (int offset = 1; offset < n; offset *= 2)
  {
    pout = 1 - pout; // swap double buffer indices
    pin = 1 - pout;
    if (thid >= offset)
      temp[pout*n+thid] += temp[pin*n+thid - offset];
    else
      temp[pout*n+thid] = temp[pin*n+thid];
    __syncthreads();
  }
  g_odata[thid] = temp[pout*n+thid1]; // write output
}

我的问题是

  1. 为什么我们需要创建共享内存临时?
  2. 为什么我们需要“pout”和“pin”变量?他们在做什么?既然我们这里只用了一个block,最多1024个线程,那我们能不能只用threadId.x来指定block中的元素呢?
  3. 在CUDA中,我们使用一个线程做一个添加操作吗?如果我使用 for 循环(给定一个线程用于数组中的一个元素,循环 OpenMP 中的线程或处理器),一个线程是否可以在一次迭代中完成?
  4. 我之前的两个问题可能看起来很幼稚......我认为关键是我不明白上述实现与伪代码之间的关系如下:

for d = 1 to log2 n do for all k in parallel do if k >= 2^d then x[k] = x[k – 2^(d-1)] + x[k]

这是我第一次使用 CUDA,如果有人能回答我的问题,我将不胜感激......

【问题讨论】:

  • 为什么我的投票被否决了????这不公平
  • 当您已经链接到作为规范参考的 GPU Gems 文章时,我不明白您为什么要求提供“良好而详细的参考”。
  • 该引用在代码中没有很多 cmets。它无法回答我提出的问题。
  • 请求对场外材料的引用在堆栈溢出时明显偏离主题。见第 4 项here
  • 如果这是你第一次使用 CUDA,你不应该从前缀和开始。首先掌握基本原理,如矢量添加和模板算法。在尝试处理前缀和之前,您应该了解共享内存的用途和用途。这里的基本算法是乒乓算法,依次将数据从源缓冲区移动到目标缓冲区,然后以相反的方向再次移动,直到工作完成。所以你需要某种临时缓冲区。共享内存是一个合乎逻辑的选择。

标签: cuda hpc prefix-sum


【解决方案1】:

1- 将内容放入共享内存 (SM) 并在那里进行计算比使用全局内存更快。加载 SM 后同步线程很重要,因此需要 __syncthreads。


2- 这些变量可能是为了澄清算法中的顺序颠倒。它只是用于切换某些部分:

temp[pout*n+thid] += temp[pin*n+thid - offset];

第一次迭代; pout = 1 和 pin = 0。第二次迭代; pout = 0 和 pin = 1。 它在奇数迭代中偏移 N 数量的输出,并在偶数迭代中偏移输入。回到您的问题,您无法使用 threadId.x 实现相同的目标,因为它不会在循环内改变。


3 & 4 - CUDA 执行线程来运行内核。这意味着每个线程单独运行该代码。如果您查看伪代码并与 CUDA 代码进行比较,您已经将外部循环与 CUDA 并行化了。所以每个线程都会在内核中运行循环,直到循环结束,并在写入全局内存之前等待每个线程完成。


希望对你有帮助。

【讨论】:

  • 最后一行是 g_odata[thid] = temp[pout * n+thid1]; ,应该是 g_odata[thid] = temp[pout*n+thid] ?所以 thid1 是 thid,这是一个错误?
猜你喜欢
  • 1970-01-01
  • 2017-09-25
  • 2011-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-31
  • 1970-01-01
相关资源
最近更新 更多