CUDA共享内存编程无法正常工作

时间:2013-11-08 17:12:48

标签: c++ cuda gpu

所有

我正在学习共享内存如何加速GPU编程过程。我使用下面的代码来计算每个元素的平方值加上其左右邻居的平均值的平方值。 但是,代码运行的结果并不像预期的那样。

打印出的前10个结果是0,1,2,3,4,5,6,7,8,9,而我期望结果为25,2,8,18,32,50,72 ,98128162;

代码如下,引用here;

你能告诉我哪个部分出了问题吗?非常感谢您的帮助。

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <cuda.h>

const int N=1024;

 __global__ void compute_it(float *data)
 {
 int tid = threadIdx.x;
 __shared__ float myblock[N];
 float tmp;

 // load the thread's data element into shared memory
 myblock[tid] = data[tid];

 // ensure that all threads have loaded their values into
 // shared memory; otherwise, one thread might be computing
 // on unitialized data.
 __syncthreads();

 // compute the average of this thread's left and right neighbors
 tmp = (myblock[tid>0?tid-1:(N-1)] + myblock[tid<(N-1)?tid+1:0]) * 0.5f;
 // square the previousr result and add my value, squared
 tmp = tmp*tmp + myblock[tid]*myblock[tid];

 // write the result back to global memory
 data[tid] = myblock[tid];
 __syncthreads();
  }

int main (){

char key;

float *a;
float *dev_a;

a = (float*)malloc(N*sizeof(float));
cudaMalloc((void**)&dev_a,N*sizeof(float));

for (int i=0; i<N; i++){
a [i] = i;
}


cudaMemcpy(dev_a, a, N*sizeof(float), cudaMemcpyHostToDevice);

compute_it<<<N,1>>>(dev_a);

cudaMemcpy(a, dev_a, N*sizeof(float), cudaMemcpyDeviceToHost);


for (int i=0; i<10; i++){
std::cout<<a [i]<<",";
}

std::cin>>key;

free (a);
free (dev_a);

2 个答案:

答案 0 :(得分:3)

内核代码中最直接的问题之一是:

data[tid] = myblock[tid];

我想你可能就是这个意思:

data[tid] = tmp;

此外,您将每个启动1024个一个线程的块。这不是一种使用GPU的特别有效的方法,它意味着每个线程块中的tid变量为0(并且只有0,因为每个线程块只有一个线程。)

这种方法存在许多问题,但这里会遇到一个直接的问题:

tmp = (myblock[tid>0?tid-1:(N-1)] + myblock[tid<31?tid+1:0]) * 0.5f;

由于tid始终为零,因此共享内存数组(myblock)中没有其他值被填充,因此该行中的逻辑不合理。如果tid为零,则您为myblock[N-1]的作业中的第一个字词选择tmp,但myblock[1023]永远不会填充任何内容。

您似乎无法理解各种CUDA层次结构:

  • 网格是与内核启动相关联的所有线程
  • 网格由线程块组成
  • 每个threadblock是一组在一个SM上协同工作的线程
  • 共享内存资源是 per-SM资源,而不是设备范围的资源
  • __synchthreads()也基于线程块(不是设备范围)运行
  • threadIdx.x是一个内置变量,它为线程块内的所有线程提供唯一的线程ID,但不是全局的线程ID。

相反,您应该将问题分解为合理大小的线程块(即多个线程)。然后,每个线程块将以与您概述的大致相同的方式运行。然后,您需要特殊处理每个线程块的起点和终点(在您的数据中)的行为。

您也没有做出推荐的cuda error checking,尤其是在您遇到CUDA代码时遇到问题。

如果您进行了我在内核代码中首先指出的更改,并颠倒了块和网格内核启动参数的顺序:

compute_it<<<1,N>>>(dev_a);

正如Kristof所说,我认为你会得到一些与你想要的东西接近的东西。但是,如果没有对代码进行其他更改,您将无法在N = 1024之外方便地进行扩展。

这行代码也不正确:

free (dev_a);

由于使用dev_a在设备上分配cudaMalloc,您应该像这样释放它:

cudaFree (dev_a);

答案 1 :(得分:1)

由于每个块只有一个线程,因此您的tid将始终为0。

尝试以这种方式启动内核: compute_it&LT;&LT;&LT; 1,N&GT;&GT;&GT;(DEV_A);

而不是 compute_it&LT;&LT;&GT;&GT;(DEV_A);