【问题标题】:Why is the output from my CUDA program unreliable?为什么我的 CUDA 程序的输出不可靠?
【发布时间】:2012-11-03 20:09:18
【问题描述】:

我正在使用 CUDA 提供的编程指南自学 CUDA。为了练习,我做了一个简单的内核,它确定数组的最大值并将其返回给 CPU:

  __global__ void getTheMaximum(float* myArrayFromCPU, float* returnedMaximum) {
    // Store my current value in shared memory.
    extern __shared__ float sharedData[];
    sharedData[threadIdx.x] = myArrayFromCPU[threadIdx.x];

    // Iteratively calculate the maximum.
    int halfScan = blockDim.x / 2;
    while (halfScan > 0 && threadIdx.x < halfScan) {
      if (sharedData[threadIdx.x] < sharedData[threadIdx.x + halfScan]) {
        sharedData[threadIdx.x] = sharedData[threadIdx.x + halfScan];
      }
      halfScan = halfScan / 2;
    }

    // Put maximum value in global memory for later return to CPU.
    returnedMaximum[0] = sharedData[0];
  }

myArrayFromCPU 是一个大小为 1024 的浮点值数组。returnedMaximum 是一个包含单个项目的普通数组:计算的最大值。

我对这个算法的想法是,它会迭代地确定最大值,因为它会从当前值的一半块大小中缩减值。

但是,当我运行此代码时,我得到了不可靠的输出。返回的最大值会有所不同。这是为什么?单个算法如何每次产生不同的值?

更新:

我也只是在一个街区上跑步。我通过设置 X=1024 的一维块大小来保证这一点。

【问题讨论】:

  • 保持线程块的扭曲同步。在每次 while 迭代结束时使用 __syncthreads()
  • 谢谢,不过我只是在一个块上运行。我还需要这样做吗?

标签: cuda


【解决方案1】:

不能保证整个块的所有线程都在同一时刻执行。这保证您只有一个经线(32 个线程组)。

为了避免块内的并发风险 - 您可以使用 __syncthreads() 内在函数,它会停止线程到达它,直到所有线程都到达该点。 请注意,您不应该将__syncthreads() 放在无法保证所有线程一致到达该点的分支代码中。

尝试以下循环:

__syncthreads();
while (halfScan > 0) {
  if (threadIdx.x < halfScan) {
    if (sharedData[threadIdx.x] < sharedData[threadIdx.x + halfScan]) {
      sharedData[threadIdx.x] = sharedData[threadIdx.x + halfScan];
    }
  }
  __syncthreads();
  halfScan = halfScan / 2;
}

请注意,我从 while 循环中删除了条件 threadIdx.x &lt; halfScan,因为我希望 所有 线程在同一位置以相同的次数执行 __syncthreads()

此外,循环之前的__syncthreads() 可能有助于确保循环开始之前来自myArrayFromCPU 的加载完成(对于所有线程)。

【讨论】:

  • 我只使用了一个块。我还需要同步我的线程吗?
  • 除非块只有 1 个 warp(32 个线程),否则您必须同步线程。在 CUDA 中,您使用 __syncthreads() 在单个块中同步经纱。实际上,您根本无法(干净地)在不同块之间同步线程。
  • 啊!谢谢!这让我对扭曲和方块的看法更加清晰。那么warp中的线程是按顺序执行的吗?顺便说一句,我刚刚意识到......如果我打电话给returnedMaximum[0] = sharedData[0];,我是否会多次多次写入全局内存?
  • warp 中的线程是并行执行的,但一个块中的多个 warp 可能碰巧同时执行(请注意,Fermi 和 Kepler 也可以同时运行 2 或 4 个 warp)。是的,returnedMaximum[0] = sharedData[0] 将发出blockDim 写入。你可以在它前面加上if (threadIdx.x==0)——这是一个典型的模式。
猜你喜欢
  • 2014-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-12
  • 2010-09-10
  • 1970-01-01
相关资源
最近更新 更多