OpenCL在NVidia硬件上生成QNaN

时间:2012-05-31 18:42:43

标签: c++ opencl gpgpu

我正在使用C ++绑定在OpenCL中编程。我有一个问题,在NVidia硬件上,我的OpenCL代码自发产生非常大的数字,然后(在下一次运行)“1.#QNaN”。我的代码几乎是一个简单的物理模拟,使用公式x = vt * .5at ^ 2。我唯一注意到的奇怪的是,粒子的速度突然上升到大约6e + 34,我猜这是该机器上的最大浮点值。然而,之前的速度/力非常小,通常值小于1。

我使用的特定GPU是Tesla M2050,带有最新的驱动程序。我使用AMD Fusion CPU作为平台在我的笔记本电脑上进行原型设计(它没有专用的GPU),并且不会出现问题。我不确定这是否是NVidia驱动程序问题,我的计算有问题,或者其他完全不同。

这是内核代码(注意:我有理由确定质量总是非零):

_kernel void update_atom(__global float4 *pos, __global float4 *vel, __global float4 *force,
                        __global const float *mass, __global const float *radius, const float timestep, const int wall)
{
    // Get the index of the current element to be processed
    int i = get_global_id(0);
    float constMult;
    float4 accel;
    float4 part;

    //Update the position, velocity and force
    accel = (float4)(force[i].x/mass[i],
            force[i].y/mass[i],
            force[i].z/mass[i],
            0.0f);
    constMult = .5*timestep*timestep;
    part = (float4)(constMult*accel.x,
            constMult*accel.y,
            constMult*accel.z, 0.0f);
    pos[i] = (float4)(pos[i].x + vel[i].x*timestep + part.x,
                pos[i].y + vel[i].y*timestep + part.y,
                pos[i].z + vel[i].z*timestep + part.z,
                0.0f);
    vel[i] = (float4)(vel[i].x + accel.x*timestep,
                vel[i].y + accel.y*timestep,
                vel[i].z + accel.z*timestep,
                0.0f);
    force[i] = (float4)(force[i].x,
                force[i].y,
                force[i].z,
                0.0f);


    //Do reflections off the wall
    //http://www.3dkingdoms.com/weekly/weekly.php?a=2
    float4 norm;
    float bouncePos = wall - radius[i];
    float bounceNeg = radius[i] - wall;
    norm = (float4)(0.0f, 0.0f, 0.0f, 0.0f);
    if(pos[i].x >= bouncePos)
    {
        //Normal is unit YZ vector
        pos[i].x = bouncePos;
        norm.x = 1.0f;
    }
    else if(pos[i].x <= bounceNeg)
    {
        pos[i].x = bounceNeg;
        norm.x = -1.0f;
    }
    if(pos[i].y >= bouncePos)
    {
        //Normal is unit XZ vector
        pos[i].y = bouncePos;
        norm.y = 1.0f;
    }
    else if(pos[i].y <= bounceNeg)
    {
        //etc
        pos[i].y = bounceNeg;
        norm.y = -1.0f;
    }
    if(pos[i].z >= bouncePos)
    {
        pos[i].z = bouncePos;
        norm.z = 1.0f;
    }
    else if(pos[i].z <= bounceNeg)
    {
        pos[i].z = bounceNeg;
        norm.z = -1.0f;
    }
    float dot = 2 * (vel[i].x * norm.x + vel[i].y * norm.y + vel[i].z * norm.z);
    vel[i].x = vel[i].x - dot * norm.x;
    vel[i].y = vel[i].y - dot * norm.y;
    vel[i].z = vel[i].z - dot * norm.z;
}

以下是我将信息存储到内核中的方法。 PutData只使用std :: vector :: push_back函数对原子的位置,速度和力进入相应的向量,而kernel只是我为OpenCL库编写的包装类(你可以信任我,我把它放在右边)参数放入入队函数的正确位置。)

void LoadAtoms(int kernelNum, bool blocking)
{
    std::vector<cl_float4> atomPos;
    std::vector<cl_float4> atomVel;
    std::vector<cl_float4> atomForce;
    for(int i = 0; i < numParticles; i++)
        atomList[i].PutData(atomPos, atomVel, atomForce);
    kernel.EnqueueWriteBuffer(kernelNum, posBuf, blocking, 0, numParticles*sizeof(cl_float4), &atomPos[0]);
    kernel.EnqueueWriteBuffer(kernelNum, velBuf, blocking, 0, numParticles*sizeof(cl_float4), &atomVel[0]);
    kernel.EnqueueWriteBuffer(kernelNum, forceBuf, blocking, 0, numParticles*sizeof(cl_float4), &atomForce[0]);
}

void LoadAtomTypes(int kernelNum, bool blocking)
{
    std::vector<cl_float> mass;
    std::vector<cl_float> radius;
    int type;
    for(int i = 0; i < numParticles; i++)
    {
        type = atomList[i].GetType();
        mass.push_back(atomTypes[type].mass);
        radius.push_back(atomTypes[type].radius);
    }
    kernel.EnqueueWriteBuffer(kernelNum, massBuf, blocking, 0, numParticles*sizeof(cl_float), &mass[0]);
    kernel.EnqueueWriteBuffer(kernelNum, radiusBuf, blocking, 0, numParticles*sizeof(cl_float), &radius[0]);
}

我的代码与往常一样,但这与内核有关。

我看到了this question,这是类似的,但我在任何地方都使用cl_float4所以我不相信这是一个对齐的问题。实际上没有任何其他相关问题。

我意识到这可能不是一个简单的问题,但我已经没有想法,直到我们可以在办公室获得新硬件进行测试。任何人都可以帮助我吗?

1 个答案:

答案 0 :(得分:0)

由于没有人回答,我想我只会贡献我迄今为止学到的东西。

我没有明确的结论,但至少,我弄清楚为什么经常这样做。由于我正在运行此(以及其他类似的内核)以计算出时间顺序的估计值,因此我正在清除列表,调整它们的大小,然后重新运行计算。然而,我没有做的是调整缓冲区的大小。这导致一些未定义的数字被线程拉动。

然而,这并没有解决我长时间运行程序所得到的QNaN。那些只是自发地出现。也许这是一个我忽略的类似问题,但我不能说。如果有人对此问题有进一步的意见,我们将不胜感激。