1

私はCUDAでいくつかのコードをテストしています(私はCUDAが初めてで、これが私の最初のアプリケーションです)。これまでのところ、コードを CPU でシリアルに実行して得られる結果と同じ結果を CUDA で達成しました。Visual Studio 2010 を使用しており、ビルド構成はデバッグです。しかし、ビルド構成を「リリース」に変更するとすぐに、間違った結果が得られ始めます。Nvidia フォーラムは現在ダウンしているため、使用できませんでした。CUDA の経験を持つ人が問題を指摘できますか。コードは次のとおりです。

__global__ void MyKernel(int *Nptr,int *deltaptr, double *gravityptr, double *separationptr, double *fconptr, double *xForce, double *yForce, double *zForce,
double *xPos, double *yPos, double *zPos )
{
int N = *Nptr;
int delta= *deltaptr;
double gravity= *gravityptr;
double separation = *separationptr;
double fcon = *fconptr;

double len=0.0;
double r12X =0.0;
double r12Y =0.0;
double r12Z =0.0;
double PE=0.0;


int nx = blockDim.x * blockIdx.x + threadIdx.x;//use this place of nx
//int ny = blockDim.x * blockIdx.x + threadIdx.y;//use this place of ny
int ny = blockDim.y * blockIdx.y + threadIdx.y;
//printf("nx:%d ny:%d\n", nx,ny);

if(!(nx< N && ny <N))
    return;
//printf("nx:%d ny:%d\n", nx,ny);


xForce[nx*N+ny] = 0.0;
yForce[nx*N+ny] = -gravity;
zForce[nx*N+ny] = 0.0;

int lowerValuedx = maxOnDevice(nx-delta,0);
int upperValuedx=minOnDevice(nx+delta+1,N);
for(int dx=lowerValuedx; dx<upperValuedx;dx++)
{
    int lowerValuedy=maxOnDevice(ny-delta,0);
    int upperValuedy=minOnDevice(ny+delta+1,N);
    for(int dy=lowerValuedy; dy<upperValuedy;dy++)
    {
        len=sqrt((double)((nx-dx)*(nx-dx)+(ny-dy)*(ny-dy)) ) *separation;
        bool condition = ny!=dy;
        bool condition1 = nx!=dx;

        //if (nx!=dx || ny!=dy)
        if (condition || condition1)
        {
            r12X = xPos[dx*N+dy] - xPos[nx*N+ny];
            r12Y = yPos[dx*N+dy] - yPos[nx*N+ny];
            r12Z = zPos[dx*N+dy] - zPos[nx*N+ny];
            xForce[nx*N+ny] = xForce[nx*N+ny] +fcon*normxOnDevice(r12X,r12Y,r12Z)*(magOnDevice(r12X,r12Y,r12Z)-len);
            yForce[nx*N+ny]= yForce[nx*N+ny] +fcon*normyOnDevice(r12X,r12Y,r12Z)*(magOnDevice(r12X,r12Y,r12Z)-len);
            zForce[nx*N+ny]= zForce[nx*N+ny] +fcon*normzOnDevice(r12X,r12Y,r12Z)*(magOnDevice(r12X,r12Y,r12Z)-len);


        }
    }
}   

}

ありがとう

4

1 に答える 1

2

CPU と GPU の結果の間、および GPU のデバッグ ビルドとリリース ビルドの間に数値の違いが存在することは珍しいことではありません。これは、どちらの結果セットも正しくないという意味ではありませんが、一方が他方よりも正確である可能性があります。数値の不一致につながる可能性のあるさまざまなメカニズムについて説明している NVIDIA の次のホワイトペーパーを参照してください。

http://developer.download.nvidia.com/assets/cuda/files/NVIDIA-CUDA-Floating-Point.pdf

nvcc フラグ -fmad=false が表示されている違いを排除するかどうかを確認できます。これは、これらが FMA/FMAD のマージによるものであり、無害である可能性が高いことを示しています。

GPU は、浮動小数点乗算と従属浮動小数点加算を 1 つの演算に結合する FMAD および FMA (融合乗算加算) 演算を提供します。これはパフォーマンスの向上に役立ちます。通常、組み合わせた操作には、その構成要素のそれぞれと同じくらいの時間がかかるためです。ただし、組み合わせた操作の丸め動作は、2 つの個別に丸められた操作を使用する場合とは異なります。

単精度 FMAD (計算能力 < 2.0) は、乗算の結果を切り捨て、IEEE-754 round-to-nearest-or-even に従って最後の加算の結果を丸めます。対照的に、FMA (計算能力 >= 2.0 の単精度、および倍精度) は、丸められていない倍幅の積を計算し、それに 3 番目のオペランドを追加し、IEEE-754 round-to-nearest-or に従って最終的な合計を丸めます。 -平。この単一の丸めにより、FMA によって提供される平均精度は、2 つの別々に丸められた演算を使用するよりも優れています。FMA 演算は、IEEE-754 浮動小数点標準の 2008 バージョンで指定されています。

デフォルトでは、リリース ビルドの場合、CUDA コンパイラはマージされた操作 (FMAD、FMA) を積極的に生成して、最高のパフォーマンスを実現します。つまり、コンパイラのデフォルトは -fmad=true であり、コンパイラは浮動小数点の乗算と加算をマージできます。-fmad=false を指定すると、乗算と加算のマージが禁止されます。ほとんどの CPU は FMA 操作を提供しないため、通常、CPU の結果との一貫性が向上します。マージされた操作の使用を無効にすると明らかにパフォーマンスに悪影響が及ぶため、 -fmad=false は主にサニティ チェックとして役立ちます。

精度の問題が疑われる場合は、CPU のバージョンを参照として使用するのではなく、CPU と GPU の両方でエラーを正確に評価するために、より精度の高い参照実装 (4 倍精度または double-double 技術に基づく実装など) と比較することをお勧めします。 (CPU の結果も丸め誤差の影響を受けるため)。

于 2012-07-27T02:21:48.127 に答える