代码之家  ›  专栏  ›  技术社区  ›  noobie2023

使用CUDA的前缀和

  •  0
  • noobie2023  · 技术社区  · 6 年前

    我很难理解简单前缀和的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”变量?他们是做什么的?因为这里最多只使用一个块和1024个线程,所以我们只能使用threadId。x指定块中的元素?
    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,如果有人能回答我的问题,我将不胜感激。。。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Barış Tanyeri    6 年前

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


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

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

    第一次迭代;pout=1,pin=0。第二次迭代;pout=0,pin=1。 它在奇数迭代时偏移N个数量的输出,在偶数迭代时偏移输入。回到您的问题上来,使用threadId无法实现同样的效果。因为它在循环中不会改变。


    3和;4-CUDA执行线程来运行内核。这意味着每个线程分别运行该代码。如果您查看伪代码并与CUDA代码进行比较,那么您已经使用CUDA并行化了外部循环。因此,每个线程将在内核中运行循环,直到循环结束,并等待每个线程完成,然后再写入全局内存。


    希望有帮助。

    推荐文章