【问题标题】:Sequential programing in CUDACUDA 中的顺序编程
【发布时间】:2016-08-10 23:23:59
【问题描述】:

我想在 CUDA 中实现这个简单的循环。

for (int i = 1; i <= N; i++)
    {
        for (int j = 1; j <= N; j++)
        {
        x[i, j] = (x0[i, j] + a*(x[i - 1, j] + x[i + 1, j] + x[i, j - 1] + x[i, j + 1])) / c;
        }
    }

问题是:计算例如X[i,j] 我需要知道 X[i-1,j] 和 X[i,j-1] 的新值,如果我想在 CPU 上计算它很容易(计算是连续的)。但是 GPU 正在并行计算所有内容,因此从 CPU 和 GPU 收到的结果是不同的。我在 CUDA 和 cudaDeviceSynchronize() 中找到了一些关于动态并行的信息,并相信它可能很有用,但无论如何仍然不知道如何在内核中实现这个循环。我会很感激你的帮助。

【问题讨论】:

  • 您想实现过滤器吗?如果是这样,您的 CPU 代码是错误的。您应该在计算之前复制源数据
  • 考虑到您正在访问可能已被另一个线程并行修改的数据(似乎您正在实现某种过滤器),最简单的解决方法是从一个缓冲区读取值(例如“输入“)并将您的计算写入另一个(因此“输出”)。这就是我做一些需要相邻像素值的过滤器的方式,例如模糊或中值。
  • 不,它不是过滤器,它是来自液体模拟器的线性方程求解器(由 Stam 提供)。我现在的目标是将他的代码更改为 GPU 代码。但你的建议可能是正确的......所以我应该复制输入数据然后......不,我猜它仍然是并行的。我需要像 CPU 版本一样按顺序制作。

标签: c++ cuda


【解决方案1】:

上面的cmets是对的,即使是纯顺序实现,也需要复制数据。这里可能是你的内核(没有内存管理代码或任何进一步的细节):

   __global__ void update(...)
    for(int i = threadIdx.x + blockDim.x * blockIdx.x; i <= N; i += blockDim.x * gridDim.x)
{
    for(int j = threadIdx.y + blockDim.y * blockIdx.y; j <= N; j += blockDim.y * gridDim.y)
    {
        output[i,j] = update_func(input, i, j);
    }
}

你可以调用(从主机),使用

update<<<dim3(16, 16), dim3(64, 64)>>>(input, output, width, height);

用适合你的硬件的任何值替换发射边界

【讨论】:

  • Regis Portalez 谢谢你,我的意思是避免在内核中使用标准的 for 循环,但如果不可能......它不是比 CPU 版本慢吗?
  • 你可以避免它们是你的数组大小足够小并且你的线程网格足够大。如果你的行数多于线程*块,你仍然需要一个 for 循环。考虑到您的代码,我会说它在 GPU 上会快得多,只要您不经常将数据返回到 CPU。但最好的办法是运行实际代码以获得准确的答案。
  • 也许你应该阅读这篇link
  • Regis Portalez 非常感谢。听起来很合理。还有一个问题。如果我想收到与 CPU 代码中完全相同的内容,为什么我需要复制数据(第一篇)?
  • 考虑 1d 中的相同代码,在其中计算压力/热量/任何标量场的二阶导数。你得到(2次连续迭代): x[i] = x[i-1] + x[i+1] - 2.0*x[i]; x[i+1] = x[i] + x[i+2] - 2.0*x[i+1];如果你直接在 x 中写入,x[i+1] 的计算将涉及 x[i],其中你已经写了一些不是原始值的东西。也许这就是你想要的,但从代码和应用程​​序域 (PDE) 来看,我猜不是,你想计算某种拉普拉斯算子
猜你喜欢
  • 2012-07-15
  • 2014-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-19
  • 2023-03-15
  • 1970-01-01
相关资源
最近更新 更多