CUDA内核中的大型迭代循环会导致内存错误

时间:2017-02-01 04:45:13

标签: cuda

我正在尝试编写一个CUDA内核,其中每个线程执行一个单独的迭代算法。有点像许多独立的Newton-Raphson解决方案。问题是经过一定次数的迭代后出现了问题。谷歌搜索表明它可能是一个分段错误,但我不知道如何纠正这一点。我写了一些再现错误的玩具代码:

#include <iostream>
#include <cuda_runtime.h>
#include <assert.h>

#define N 3

__device__ void devFunc(float4 *in, float4 *out){

    out[0] = in[0];

    //Placeholder useless computations
    for (int i = 0; i < 1000; ++i){
        out[0].w = out[0].w + 1.0;
        out[0].x = out[0].w + 1.0;
        out[0].y = out[0].w + 1.0;
        out[0].z = out[0].w + 1.0;
        out[0].w = out[0].w - 1.0;
        out[0].x = out[0].w - 1.0;
        out[0].y = out[0].w - 1.0;
        out[0].z = out[0].w - 1.0;
    }

    out[0].w = 26.0;
    out[0].x = 26.0;
    out[0].y = 26.0;
    out[0].z = 26.0;
}


__global__ void testKernel(float4 *vects){

    const int i = blockIdx.x;

    //Iterative algorithm, fails for 1000 iterations
    for (int j = 0; j < 1000; ++j){
        devFunc(&vects[i], &vects[i]);
    }

}


int main(){

    float4 vects[N];

    //Preprare original data
    for (int i = 0; i < N; ++i){
        vects[i].w = 5.0;
        vects[i].x = 5.0;
        vects[i].y = 5.0;
        vects[i].z = 5.0;
    }

    //Print original data
    std::cout << "Original data:" << std::endl;
    for (int i = 0; i < N; ++i){
        std::cout << vects[i].w 
            << "\t" << vects[i].x 
            << "\t" << vects[i].y 
            << "\t" << vects[i].z 
            << "\t" << std::endl;
    }

    cudaError_t stat = cudaSuccess;

    float4 *d_vects;
    stat = cudaMalloc(&d_vects, sizeof(float4)*N);
    assert(stat == cudaSuccess);
    stat = cudaMemcpy(d_vects, vects, sizeof(float4)*N, cudaMemcpyHostToDevice);
    assert(stat == cudaSuccess);

    testKernel<<<N, 1>>>(d_vects);

    stat = cudaMemcpy(vects, d_vects, sizeof(float4)*N, cudaMemcpyDeviceToHost);
    assert(stat == cudaSuccess);
    stat = cudaFree(d_vects);
    assert(stat == cudaSuccess);

    //Print processed data
    std::cout << "Processed data:" << std::endl;
    for (int i = 0; i < N; ++i){
        std::cout << vects[i].w
            << "\t" << vects[i].x
            << "\t" << vects[i].y
            << "\t" << vects[i].z
            << "\t" << std::endl;
    }

}

玩具代码以非常低效的方式将一些5的向量更改为26的向量,但更重要的是再现错误。因此,当我在__global__内核中运行for循环1000次迭代时,会触发cudaMemcpy d_vects上的错误代码4返回主机。如果我将迭代降级到100,一切都会正常工作。我也尝试了上面代码的一个版本,其中__device__函数接受并返回float4而不是指针......同样的错误。

我的一个理论是,根据CUDA编程指南的大小和对齐要求,我的数据结构可能没有“自然对齐”:

  

“读取非自然对齐的8字节或16字节字会产生不正确的结果(关闭几个字),因此必须特别注意保持这些值的任何值或数组的起始地址对齐类型“。 see here

但这不是问题,因为我正在使用CUDA的float4编程指南说满足要求。我的硬件计算能力是5.2。

所以我的问题是导致此错误的原因以及如何纠正?谢谢。

我尝试过的其他一些事情:

•调整执行配置<<<Dg, Db, Ns, S>>>的第3个参数,即动态分配的共享内存中的字节数

•调整heap memory allocation

注意上面“//Placeholder useless computations”中的计算量会更改在发生memcpy错误之前可能执行的迭代次数,这也很有用。例如,如果我用更接近牛顿迭代的东西替换占位符,则仅在8次迭代后出现错误。

谢谢。

0 个答案:

没有答案