1

私はC++バインディングを使用してOpenCLでプログラミングしています。NVidiaハードウェアで、OpenCLコードが自発的に非常に大きな数を生成し、次に(次の実行で)「1.#QNaN」を生成するという問題があります。私のコードは、方程式x = vt * .5at^2を使用した非常に単純な物理シミュレーションです。奇妙なことに気付いたのは、粒子の速度が突然約6e + 34に達することです。これは、そのマシンの最大浮動小数点値だと思います。ただし、それ以前の速度/力は非常に小さく、多くの場合、値は1未満です。

私が使用している特定のGPUは、最新のドライバーを備えたTeslaM2050です。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関数を使用するだけであり、カーネルは、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]);
}

いつものように、私のコードにはもっと多くのものがありますが、これはカーネルに関連しているものです。

私はこの質問を見ましたが、これは似ていますが、私は可能な限りcl_float4を使用しているので、それがアライメントの問題であるとは思わない。他に関連する質問は実際にはありません。

これはおそらく簡単な質問ではないことはわかっていますが、オフィスで新しいハードウェアをテストできるようになるまで、アイデアが不足しています。誰かが私を助けることができますか?

4

1 に答える 1

0

誰も答えてくれなかったので、これまでに学んだことを貢献するだけだと思います。

明確な結論はありませんが、少なくとも、なぜそれが頻繁に行われているのかを理解しました。これ(および他の同様のカーネル)を実行して時間の順序の見積もりを計算しているので、リストをクリアし、サイズを変更してから、計算を再実行していました。しかし、私がしていなかったのは、バッファーのサイズを変更することでした。これにより、いくつかの未定義の数値がスレッドによってプルされました。

ただし、これでは、プログラムを長期間実行することで得られるQNaNは解決されません。それらは単に自発的に現れます。見落としているのと同じような問題かもしれませんが、言えません。誰かがこの問題についてさらに意見を持っているなら、それはありがたいです。

于 2012-06-03T23:13:16.380 に答える