Cuda Dot产品失败,非倍数1024

时间:2015-11-16 21:20:30

标签: cuda

在计算两个数组的点积时,我只是在寻求一些帮助。

我想说我将数组大小设置为2500,每个块的最大线程数设置为1024.

本质上,我想计算每个块的点积,然后在另一个核函数中求和点积。我计算了这样的块数:

nblcks = (n + 1024 -1)/1024

所以,nblcks = 3

这是我的核心功能:

// calculate the dot product block by block
__global__ void dotProduct(const float* a, const float* b, float* c, int n){
    // store the product of a[i] and b[i] in shared memory
    // sum the products in shared memory
    // store the sum in c[blockIdx.x]

    __shared__ float s[ntpb];
    int tIdx = threadIdx.x;
    int i = blockDim.x * blockIdx.x + threadIdx.x;

    //calc product
    if (i < n)
        s[tIdx] = a[i] * b[i];
    __syncthreads();

    for (int stride = 1; stride < blockDim.x; stride <<= 1) {
         if (tIdx % (2 * stride) == 0)
             s[tIdx] += s[tIdx + stride];
         __syncthreads();
     }

    if (threadIdx.x == 0){
        c[blockIdx.x] = s[0];
    }

}

我打电话给内核:

dotProduct<<<nblocks, ntpb>>>(d_a, d_b, d_c, n);

一切正常!好吧,差不多。

d_c,它有3个元素 - 每个元素都是块的点积在最后一个元素上抛出。

d_c[0] = correct
d_c[1] = correct
d_c[2] = some massive number of 10^18

有人能指出为什么会这样吗?它似乎只适用于1024的倍数。所以... 2048,3072等...我是否迭代空值或堆栈溢出?

谢谢!

编辑:

 // host vectors
    float* h_a = new float[n];
    float* h_b = new float[n];
    init(h_a, n);
    init(h_b, n);
    // device vectors (d_a, d_b, d_c)
    float* d_a;
    float* d_b;
    float* d_c;
    cudaMalloc((void**)&d_a, n * sizeof(float));
    cudaMalloc((void**)&d_b, n * sizeof(float));
    cudaMalloc((void**)&d_c, nblocks * sizeof(float));

    // copy from host to device h_a -> d_a, h_b -> d_b
    cudaMemcpy(d_a, h_a, n * sizeof(float), cudaMemcpyHostToDevice);
    cudaMemcpy(d_b, h_b, n * sizeof(float), cudaMemcpyHostToDevice);

数组的初始化在此函数中完成(n次):

void init(float* a, int n) {
    float f = 1.0f / RAND_MAX;
    for (int i = 0; i < n; i++)
        a[i] = std::rand() * f; // [0.0f 1.0f]
}

1 个答案:

答案 0 :(得分:2)

这里的基本问题是,当每个块具有两个线程的舍入功率时,总和减少只能正常工作,共享内存中的每个条目都被初始化。如果您执行以下操作,那么这不是实践中的限制:

__global__ void dotProduct(const float* a, const float* b, float* c, int n){
    // store the product of a[i] and b[i] in shared memory
    // sum the products in shared memory
    // store the sum in c[blockIdx.x]

    __shared__ float s[ntpb];
    int tIdx = threadIdx.x;
    int i = blockDim.x * blockIdx.x + threadIdx.x;

    //calc product
    s[tIdx] = 0.f;
    while (i < n) {
        s[tIdx] += a[i] * b[i];
        i += blockDim.x * gridDim.x;
    }
    __syncthreads();

    for (int stride = 1; stride < blockDim.x; stride <<= 1) {
         if (tIdx % (2 * stride) == 0)
             s[tIdx] += s[tIdx + stride];
         __syncthreads();
     }

    if (threadIdx.x == 0){
        c[blockIdx.x] = s[0];
    }
}

并且每块运行两个线程的功率(即32,64,128,256,512或1024)。 while循环累积多个值并将该部分点积存储在共享内存中,每个条目包含0或有效的部分和,然后减少正常发生。不是运行与数据大小相同的块,而是运行尽可能多的同时“填充”您的GPU(或者如果问题大小很小,则比您认为的要少一个)。在较大的问题规模下,性能也将得到改善。

如果您还没有看过它,here is a very instructive whitepaper由NVIDIA的Mark Harris编写,逐步优化基本的并行缩减。我强烈建议你阅读它。