2012-07-26 47 views
1

我正在測試CUDA中的一些代碼(我是CUDA的新手,這是我的第一個應用程序)。到目前爲止,我已經在CUDA中獲得了與通過在CPU上串行運行代碼所獲得的結果相同的結果。我正在使用Visual Studio 2010,並且構建配置是調試。但是,只要我將構建配置更改爲「發佈」,我就開始得到錯誤的結果。我目前還沒有能夠使用Nvidia論壇。有CUDA經驗的人可以指出這個問題。的代碼如下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); 


     } 
    } 
} 

}

由於

+1

結果如何「錯誤」?只有一些小的數字差異,或結果完全垃圾? CPU和GPU結果之間以及GPU上調試和發佈版本之間存在數值差異並不罕見。這並不意味着結果是錯誤的,它們實際上可能更準確。請參閱NVIDIA的以下白皮書:http://developer.download.nvidia.com/assets/cuda/files/NVIDIA-CUDA-Floating-Point。pdf您可以檢查nvcc標誌-fmad = false是否消除了差異,這表明這些差異是由於FMA合併造成的,因此無害。 – njuffa 2012-07-26 19:22:57

+0

非常感謝njuffa。我不知道爲什麼,但使用-fmad = false flag起作用......請將此作爲答案,我會將其標記爲已接受。 – umbersar 2012-07-27 00:41:24

回答

2

用於向CPU和GPU結果之間存在差別的數值的情況並不少見,並且建立在GPU調試和釋放之間。這並不意味着任何一組結果都是不正確的,但其中一個可能比另一個更準確。請參閱從NVIDIA以下白皮書,討論各種機制,可以導致數值不符:

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

您可以檢查NVCC標誌-fmad是否=假消除您所看到的差異,這表明,這些由於FMA/FMAD合併,因此可能無害。

GPU提供FMAD和FMA(融合乘加)操作,將浮點乘法和從屬浮點加法組合成一個單獨的操作。這對性能有幫助,因爲組合操作通常需要與其每個組成部分相似的時間量。但是,任一組合操作的舍入行爲都不同於使用兩個單獨舍入的操作:

單精度FMAD(計算能力< 2.0)截斷乘法結果,然後根據IEEE舍入最終加法的結果-754最接近或最接近。相比之下,FMA(計算能力的單精度> = 2.0和雙精度)計算未被佔用的雙倍寬度產品,向其中添加第三個操作數,並根據IEEE-754輪到最近值舍入最終總和-甚至。由於這一舍入,FMA提供的平均精度優於使用兩個單獨的舍入操作。 FMA操作在2008版IEEE-754浮點標準中有詳細說明。

默認情況下,對於發佈版本,CUDA編譯器主動生成合並操作(FMAD,FMA)以實現最佳性能。換句話說,編譯器的默認值是-fmad = true,它允許編譯器合併浮點乘法和相加。通過指定-fmad = false,可以禁止乘法和加法的合併,因爲大多數CPU不提供FMA操作,所以通常可以提供與CPU結果更高的一致性。顯然,禁用合併操作會對性能產生負面影響,因此-fmad = false主要用作完整性檢查。如果懷疑精度問題,我通常建議與更高精度的參考實現(例如基於四倍精度或雙倍技術的實現)進行比較,以準確評估CPU和GPU上的錯誤,而不是使用CPU版本作爲參考(因爲CPU結果也受到舍入誤差的影響)。