2013-08-05 31 views
6

Tôi đang lập trình trong OpenCL bằng cách sử dụng một thẻ GeForce GT 610 trong Linux. Kết quả chính xác gấp đôi CPU và GPU của tôi không nhất quán. Tôi có thể đăng một phần của mã ở đây, nhưng trước tiên tôi muốn biết liệu có ai khác đã phải đối mặt với vấn đề này hay không. Sự khác biệt giữa kết quả chính xác gấp đôi GPU và CPU được phát âm khi tôi chạy các vòng lặp với nhiều lần lặp lại. Không có gì đặc biệt về mã, nhưng tôi có thể đăng nó ở đây nếu có ai quan tâm. Cảm ơn rất nhiều. Đây là mã của tôi. Xin vui lòng tha thứ cho __ và định dạng xấu như tôi mới ở đây :) Như bạn có thể thấy, tôi có hai vòng và mã CPU của tôi về cơ bản gần như là một phiên bản giống hệt nhau.OpenCL đôi độ chính xác khác nhau từ CPU chính xác đôi

#ifdef cl_khr_fp64 
#pragma OPENCL EXTENSION cl_khr_fp64 : enable 
#elif defined(cl_amd_fp64) 
#pragma OPENCL EXTENSION cl_amd_fp64 : enable 
#else 
#error "Double precision floating point not supported by OpenCL implementation." 

#endif

__kernel void simpar(__global double* fp, __global double* fp1, 
    __global double* fp3, __global double* fp5, 
__global double* fp6, __global double* fp7, 
__global double* fp8, __global double* fp8Plus, 
__global double* x, __global double* v, __global double* acc, 
__global double* keBuf, __global double* peBuf, 
unsigned int prntstps, unsigned int nprntstps, double dt 
) { 
unsigned int m,i,j,k,l,t; 
unsigned int chainlngth=100; 
double dxi, twodxi, dxipl1, dximn1, fac, fac1, fac2, fac13, fac23; 
double ke,pe,tke,tpe,te,dx; 
double hdt, hdt2; 
double alpha=0.16; 
double beta=0.7; 
double cmass; 
double peTemp; 
nprntstps=1001; 
dt=0.01; 
prntstps=100; 
double alphaby4=beta/4.0; 
hdt=0.5*dt; 
hdt2=dt*0.5*dt; 
double Xlocal,Vlocal,Acclocal; 
unsigned int global_id=get_global_id(0); 
if (global_id<chainlngth){ 
Xlocal=x[global_id]; 
Vlocal=v[global_id]; 
Acclocal=acc[global_id]; 
for (m=0;m<nprntstps;m++){ 

for(l=0;l<prntstps;l++){ 
       Xlocal =Xlocal+dt *Vlocal+hdt2*Acclocal; 
       x[global_id]=Xlocal; 
       barrier(CLK_LOCAL_MEM_FENCE); 

       Vlocal =Vlocal+ hdt * Acclocal; 
       barrier(CLK_LOCAL_MEM_FENCE); 

      j = global_id - 1; 
      k = global_id + 1; 
      if (j == -1) { 
        dximn1 = 0.0; 
      } else { 
        dximn1 = x[j]; 
      } 
      if (k == chainlngth) { 
        dxipl1 = 0.0; 
      } else { 
        dxipl1 = x[k]; 
      } 
      dxi = Xlocal; 
      twodxi = 2.0 * dxi; 
      fac = dxipl1 + dximn1 - twodxi; 
      fac1 = dxipl1 - dxi; 
      fac2 = dxi - dximn1; 
      fac13 = fac1 * fac1 * fac1; 
      fac23 = fac2 * fac2 * fac2; 
      Acclocal = alpha * fac + beta * (fac13 - fac23); 

      barrier(CLK_GLOBAL_MEM_FENCE); 

      Vlocal += hdt * Acclocal; 
      v[global_id]=Vlocal; 
      acc[global_id]=Acclocal; 
      barrier(CLK_GLOBAL_MEM_FENCE); 
     } 
      barrier(CLK_GLOBAL_MEM_FENCE); 

      tke = tpe = te = dx = 0.0; 
      ke=0.5*Vlocal*Vlocal;//Vlocal*Vlocal; 
      barrier(CLK_GLOBAL_MEM_FENCE); 
      fp6[(m*100)+global_id]=ke; 
      keBuf[global_id]=ke; 
      ke=0.0; 
      barrier(CLK_GLOBAL_MEM_FENCE); 


      j = global_id - 1; 
      k = global_id + 1; 
      if (j == -1) { 
        dximn1 = 0.0; 
      } else { 
        dximn1 = x[j]; 
      } 
      if (k == chainlngth) { 
        dxipl1 = 0.0; 
      } else { 
        dxipl1 = x[k]; 
      } 
      dxi = Xlocal; 
      twodxi = 2.0 * dxi; 
      fac = dxipl1 + dximn1 - twodxi; 
      fac1 = dxipl1 - dxi; 
      fac2 = dxi - dximn1; 
      fac13 = fac1 * fac1 * fac1; 
      fac23 = fac2 * fac2 * fac2; 
      Acclocal = alpha * fac + beta * (fac13 - fac23); 

      barrier(CLK_GLOBAL_MEM_FENCE); 

      Vlocal += hdt * Acclocal; 
      v[global_id]=Vlocal; 
      acc[global_id]=Acclocal; 
      barrier(CLK_GLOBAL_MEM_FENCE); 
     } 
      barrier(CLK_GLOBAL_MEM_FENCE); 

      tke = tpe = te = dx = 0.0; 
      ke=0.5*Vlocal*Vlocal;//Vlocal*Vlocal; 
      barrier(CLK_GLOBAL_MEM_FENCE); 
      fp6[(m*100)+global_id]=ke; 
      keBuf[global_id]=ke; 
      ke=0.0; 
      barrier(CLK_GLOBAL_MEM_FENCE); 
      j = global_id - 1; 
      k = global_id + 1; 
      if (j == -1) { 
        dximn1 = 0.0; 
      } else { 
        dximn1 = x[j]; 
      } 
      if (k == chainlngth) { 
        dxipl1 = 0.0; 
      } else { 
        dxipl1 = x[k]; 
      } 
      dxi = Xlocal; 
      twodxi = 2.0 * dxi; 
      fac = dxipl1 + dximn1 - twodxi; 
      fac1 = dxipl1 - dxi; 
      fac2 = dxi - dximn1; 
      fac13 = fac1 * fac1 * fac1; 
      fac23 = fac2 * fac2 * fac2; 
      Acclocal = alpha * fac + beta * (fac13 - fac23); 

      barrier(CLK_GLOBAL_MEM_FENCE); 

      Vlocal += hdt * Acclocal; 
      v[global_id]=Vlocal; 
      acc[global_id]=Acclocal; 
      barrier(CLK_GLOBAL_MEM_FENCE); 
     } 
      barrier(CLK_GLOBAL_MEM_FENCE); 

      tke = tpe = te = dx = 0.0; 
      ke=0.5*Vlocal*Vlocal;//Vlocal*Vlocal; 
      barrier(CLK_GLOBAL_MEM_FENCE); 
      fp6[(m*100)+global_id]=ke; 
      keBuf[global_id]=ke; 
      ke=0.0; 
      barrier(CLK_GLOBAL_MEM_FENCE); 
    if (global_id ==0){ 
      for(t=0;t<100;t++) 
        tke+=keBuf[t]; 
      } 

      barrier(CLK_GLOBAL_MEM_FENCE); 
      k = global_id-1; 
      if (k == -1) { 
       dx = Xlocal; 
      }else{ 
       dx = Xlocal-x[k]; 
      } 

       fac = dx * dx; 
       peTemp = alpha * 0.5 * fac + alphaby4 * fac * fac; 
       fp8[global_id*m]=peTemp; 
       if (global_id == 0) 
        tpe+=peTemp; 

       barrier(CLK_GLOBAL_MEM_FENCE); 
       cmass=0.0; 
       dx = -x[100-1]; 
       fac = dx*dx; 

       pe=alpha*0.5*fac+alphaby4*fac*fac; 
       if (global_id==0){ 
       fp8Plus[m]=pe; 
       tpe+=peBuf[0]; 
       fp5[m*2]=i; 
       fp5[m*2+1]=cmass; 
       te=tke+tpe; 
       fp[m*2]=m; 
       fp[m*2+1]=te; 

      } 
    barrier(CLK_GLOBAL_MEM_FENCE); 
       //cmass /=100; 
      fp1[(m*chainlngth)+global_id]=Xlocal-cmass; 
      // barrier(CLK_GLOBAL_MEM_FENCE); 
       fp3[(m*chainlngth)+global_id]=Vlocal; 
      // barrier(CLK_GLOBAL_MEM_FENCE); 
      fp7[(m*chainlngth)+global_id]=Acclocal; 

       barrier(CLK_GLOBAL_MEM_FENCE); 
    } 
} 

}

+0

Khi bạn nói "không nhất quán", ý bạn thực sự là gì? Bạn có thể minh họa sự khác biệt về số lượng (lỗi tuyệt đối và tương đối, số chữ số cuối cùng trong thỏa thuận) không? – talonmies

+0

Tôi đang thực hiện cùng (hai) vòng lặp lồng nhau. Vòng lặp bên trong thực hiện 100 lần và sau đó vòng lặp bên ngoài in ra một số kết quả. Đây là một mẫu từ phiên đầu tiên của vòng ngoài: CPU: 0,0000000011 0,0000030832 0,0005244239 0,1400572807 1,5213598941 1,5213598941 0,1400572807 0,0005244239 0,0000030832 0,0000000011 GPU: 0,0000000012 0,0000032002 0,0005183133 0,1401775827 1,5249561626 1.5249561626 0.1401775827 0.0005183133 0.0000032002 0.0000000012 – Newbee

+2

Khi bạn nói "Độ chính xác gấp đôi CPU", bạn có nghĩa là thực thi cùng một hạt nhân trên thiết bị CPU hay bạn đang so sánh với một cài đặt gốc? Ngoài ra, hãy đảm bảo rằng bạn không chuyển bất kỳ cờ nào đến trình biên dịch OpenCL, điều này có thể làm giảm độ nghiêm ngặt của IEEE (ví dụ: cho phép các thao tác thêm mul nhanh và vân vân). Và có mã chắc chắn sẽ giúp đỡ để mọi người có thể tái sản xuất và làm bài kiểm tra của riêng họ, mà không có mã tốt nhất chúng ta có thể làm là suy đoán. – Thomas

Trả lời

5

này được phần nào mong đợi hành vi, thực sự.

Trên CPU x86 cũ hơn, số dấu phẩy động dài 80bits (Intel "long double"), và cắt ngắn thành 64 bit chỉ khi cần. Khi các đơn vị SIMD/hướng dẫn cho các điểm nổi điểm đến cho CPU x86, độ chính xác hai điểm nổi trở thành 64 bit theo mặc định; tuy nhiên, 80bit vẫn có thể, tùy thuộc vào cài đặt trình biên dịch của bạn. Có rất nhiều điều để đọc về điều này: Wikipedia: Floating Point.

Kiểm tra cài đặt trình biên dịch của bạn cho OpenCL mã máy chủ trên điểm nổi "thủ thuật ảo thuật" để nhận được thỏa thuận tốt hơn về kết quả của bạn. Hãy tính số absoluterelative error giá trị của bạn và kiểm tra xem biên độ lỗi này có an toàn cho ứng dụng của bạn hay không.

+0

Cảm ơn rất nhiều! Tôi đã sử dụng tùy chọn "-logger-store" với gcc, không có sự khác biệt. Bạn có thể vui lòng đề xuất bất kỳ tùy chọn trình biên dịch khác cho gcc có thể làm cho nó tuân theo các tiêu chuẩn IEEE nghiêm ngặt không? – Newbee

+0

@Newbee Tóm tắt các tùy chọn gcc được xếp vào độ chính xác của dấu phẩy động: http://gcc.gnu.org/wiki/FloatingPointMath – sbabbi

+0

Hãy thử ** - funsafe-math-optimizations -O3 ** cho "trường hợp xấu nhất" và hoạt động của bạn xuống dưới ** - O0 **. Ngoài ra, hãy kiểm tra các tùy chọn cho công tắc ** - mfpmath = unit ** và các công tắc ** - m ___ ** để tạo mã cho các đơn vị khác nhau. ** Giả sử của tôi ** là mã OpenCL được tối ưu hóa rất nhiều, do đó, cho phép tối ưu hóa "không an toàn" sẽ khiến cho kết quả CPU của bạn gần hơn với kết quả OpenCL. – Sven

Các vấn đề liên quan