我正在尝试在 CUDA 中实现点积并将结果与 MATLAB 返回的结果进行比较。我的 CUDA 代码(基于本教程)如下:
#include <stdio.h>
#define N (2048 * 8)
#define THREADS_PER_BLOCK 512
#define num_t float
// The kernel - DOT PRODUCT
__global__ void dot(num_t *a, num_t *b, num_t *c)
{
__shared__ num_t temp[THREADS_PER_BLOCK];
int index = threadIdx.x + blockIdx.x * blockDim.x;
temp[threadIdx.x] = a[index] * b[index];
__syncthreads(); //Synchronize!
*c = 0.00;
// Does it need to be tid==0 that
// undertakes this task?
if (0 == threadIdx.x) {
num_t sum = 0.00;
int i;
for (i=0; i<THREADS_PER_BLOCK; i++)
sum += temp[i];
atomicAdd(c, sum);
//WRONG: *c += sum; This read-write operation must be atomic!
}
}
// Initialize the vectors:
void init_vector(num_t *x)
{
int i;
for (i=0 ; i<N ; i++){
x[i] = 0.001 * i;
}
}
// MAIN
int main(void)
{
num_t *a, *b, *c;
num_t *dev_a, *dev_b, *dev_c;
size_t size = N * sizeof(num_t);
cudaMalloc((void**)&dev_a, size);
cudaMalloc((void**)&dev_b, size);
cudaMalloc((void**)&dev_c, size);
a = (num_t*)malloc(size);
b = (num_t*)malloc(size);
c = (num_t*)malloc(size);
init_vector(a);
init_vector(b);
cudaMemcpy(dev_a, a, size, cudaMemcpyHostToDevice);
cudaMemcpy(dev_b, b, size, cudaMemcpyHostToDevice);
dot<<<N/THREADS_PER_BLOCK, THREADS_PER_BLOCK>>>(dev_a, dev_b, dev_c);
cudaMemcpy(c, dev_c, sizeof(num_t), cudaMemcpyDeviceToHost);
printf("a = [\n");
int i;
for (i=0;i<10;i++){
printf("%g\n",a[i]);
}
printf("...\n");
for (i=N-10;i<N;i++){
printf("%g\n",a[i]);
}
printf("]\n\n");
printf("a*b = %g.\n", *c);
free(a); free(b); free(c);
cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
}
我编译它:
/usr/local/cuda-5.0/bin/nvcc -m64 -I/usr/local/cuda-5.0/include -gencode arch=compute_20,code=sm_20 -o multi_dot_product.o -c multi_dot_product.cu
g++ -m64 -o multi_dot_product multi_dot_product.o -L/usr/local/cuda-5.0/lib64 -lcudart
有关我的 NVIDIA 卡的信息,请访问http://pastebin.com/8yTzXUuK。我尝试使用以下简单代码在 MATLAB 中验证结果:
N = 2048 * 8;
a = zeros(N,1);
for i=1:N
a(i) = 0.001*(i-1);
end
dot_product = a'*a;
但是随着 N 的增加,我得到了显着不同的结果(例如,对于 N=2048*32 CUDA reutrns 6.73066e+07 而 MATLAB 返回 9.3823e+07。对于 N=2048*64 CUDA 给出 3.28033e+08 而 MATLAB给出 7.5059e+08)。我倾向于相信差异源于float
在我的 C 代码中的使用,但如果我用编译器替换它,则会double
抱怨atomicAdd
不支持双参数。我应该如何解决这个问题?
更新:另外,对于高值N
(例如 2048*64),我注意到 CUDA 返回的结果在每次运行时都会发生变化。N
如果较低(例如 2048*8),则不会发生这种情况。
同时我有一个更基本的问题:变量temp
是一个大小数组,THREADS_PER_BLOCK
在同一块中的线程之间共享。它是否也在块之间共享,或者每个块都对该变量的不同副本进行操作?我应该将该方法dot
视为对每个块的说明吗?有人可以详细说明在这个例子中工作是如何划分的以及变量是如何共享的