【问题标题】:CUDA kernel - nested for loopCUDA 内核 - 嵌套 for 循环
【发布时间】:2011-03-15 00:11:59
【问题描述】:

你好 我正在尝试编写一个 CUDA 内核来执行以下代码。

for (n = 0; n < (total-1); n++)
{
  a = values[n];

  for ( i = n+1; i < total ; i++)
  {
    b = values[i] - a;
    c = b*b;

    if( c < 10)
        newvalues[i] = c;
    }
}

这是我目前拥有的,但似乎没有给出正确的结果?有谁知道我做错了什么。干杯

__global__ void calc(int total, float *values, float *newvalues){

float a,b,c;

int idx = blockIdx.x * blockDim.x + threadIdx.x;

for (int n = idx; n < (total-1); n += blockDim.x*gridDim.x){
    a = values[n];

    for(int i = n+1; i < total; i++){
        b = values[i] - a;
        c = b*b;

    if( c < 10)
        newvalues[i] = c;

    }
}

【问题讨论】:

  • for ( i = n+1; p &lt; total ; p++) 中的p 是什么?
  • 错字。对不起,应该是我

标签: cuda


【解决方案1】:

在 2D 中实现这个问题并使用 2D 线程块启动您的内核。 x 和 y 维度的线程总数将等于 total 。内核代码应如下所示:

__global__ void calc(float *values, float *newvalues, int total){


float a,b,c;

int n= blockIdy.y * blockDim.y + threadIdx.y;
int i= blockIdx.x * blockDim.x + threadIdx.x;

  if (n>=total || i>=total)
        return;

a = values[n];
b = values[i] - a;
c = b*b;
 if( c < 10)
        newvalues[i] = c;  

// I don't know your problem statement but i think it should be like: newvalues[n*total+i] = c;  


}

更新:

这就是你应该如何调用内核

dim3 block(16,16);
dim3 grid (  (total+15)/16,  (total+15)/16  );
calc<<<grid,block>>>(float *val, float *newval, int T);

还要确保在内核中添加这一行(请参阅更新的内核)

if (n>=total || i>=total)
return;

【讨论】:

  • 只是一个想法,我会这样调用内核 >> 其中 x 是 dim2 (total,total) 或类似的东西?我怎么能考虑到外循环只是为了(total-1)干杯
  • 谢谢。请问你为什么选择16?
  • 一个 16x16 的块有 256 个线程。我选择这是一种安全措施,以便代码可以在所有支持 cuda 的卡上运行。人们应该意识到他们正在使用的卡的瓶颈和限制。 Fermi 架构每块支持 1024 个线程,而前几代只支持每块 512 个线程。因此,您可以制作一个大小为 32x32 的块,以获得 2.0 (fermi) 或更高的计算能力。对于计算能力低于 2.0 的卡,您需要将块大小保持在或等于 22x22。阅读:blog.cuvilib.com/2010/06/09/…
【解决方案2】:

我可能错了,但 n &lt; (total-1) 签到

for (int n = idx; n < (total-1); n += blockDim.x*gridDim.x)

似乎与原始版本不同。

【讨论】:

    【解决方案3】:

    您为什么不直接删除外部循环并使用该循环所需的尽可能多的线程启动内核呢?有一个取决于您的 blockId 的循环有点奇怪。通常你会尽量避免这些循环。 其次,在我看来newvalues[i] 可以被不同的线程覆盖。

    【讨论】:

    • 我不太确定该怎么做。你的意思是用(total-1)个线程开始外循环吗?我认为newvalues[i] 可以被覆盖是对的。如果我把代码改成newvalues[i] += c,会不会是每个线程贡献的总和?
    • 问题会少得多,但问题仍然存在。想象以下场景:线程 1 加载 newvalue[i] 并对其进行修改。在线程 1 将其写入全局内存之前,线程 2 也会读取 newvalue[i] 以对其进行修改。您可以在内核末尾使用原子添加或减少形式
    • 目前,您使用外部 for 循环在一个线程中迭代多次,但通常您以这种方式使用 CUDA,即启动与迭代一样多的线程。所以每个线程将只计算一次外循环的迭代。只有当您的迭代次数多于可以启动的线程数时,您才必须考虑内核中某种形式的循环。但是你的内部循环应该留在内核中。
    • 嗯,好的。我认为总数最多只有 10000 个左右,所以我认为我可以轻松拥有那么多线程。也许我会做这样的事情? kernelcall&lt;&lt;&lt;total-1,1&gt;&gt;&gt;&gt;( ...) 并移除外部 for 循环。另外,感谢 atomicadd 的建议。我尝试实现它,但似乎仍然没有从内核中得到正确的结果
    • 但是您知道您的示例代码也不正确,因为它也覆盖了newvalues[i]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-22
    相关资源
    最近更新 更多