Ошибки в полиномиальной задаче на CUDA - PullRequest
0 голосов
/ 27 марта 2011

Я пытался использовать CUDA для создания простых циклов на устройстве, но кажется, что Cuda трудно понять.Я получаю 0 от каждого вызова функции, когда я использую функцию ядра CUDA с нормальным кодом C.Оригинальный код:

double evaluate(int D, double tmp[], long *nfeval)
{
/* polynomial fitting problem */
   int   i, j;
   int const M=60;
   double px, x=-1, dx=(double)M, result=0;

   (*nfeval)++;
   dx = 2/dx;
   for (i=0;i<=M;i++)
   {
      px = tmp[0];
      for (j=1;j<D;j++)
      {
     px = x*px + tmp[j];
      }
      if (px<-1 || px>1) result+=(1-px)*(1-px);
      x+=dx;
   }
   px = tmp[0];
   for (j=1;j<D;j++) px=1.2*px+tmp[j];
   px = px-72.661;
   if (px<0) result+=px*px;
   px = tmp[0];
   for (j=1;j<D;j++) px=-1.2*px+tmp[j];
   px =px-72.661;
   if (px<0) result+=px*px;
   return result;
}

Я хотел сначала сделать цикл для CUDA:

    double evaluate_gpu(int D, double tmp[], long *nfeval)
{
/* polynomial fitting problem */
   int    j;
   int const M=60;
   double px, dx=(double)M, result=0;
   (*nfeval)++;
   dx = 2/dx;
   int N = M;
   double *device_tmp = NULL; 
   size_t size_tmp = sizeof tmp;    
   cudaMalloc((double **) &device_tmp, size_tmp);   
   cudaMemcpy(device_tmp, tmp, size_tmp, cudaMemcpyHostToDevice);
   int block_size = 4;
   int n_blocks = N/block_size + (N%block_size == 0 ? 0:1);
   cEvaluate <<< n_blocks, block_size >>> (device_tmp, result, D);
 // cudaMemcpy(result, result, size_result, cudaMemcpyDeviceToHost);
    px = tmp[0];
   for (j=1;j<D;j++) px=1.2*px+tmp[j];
   px = px-72.661;
   if (px<0) result+=px*px;
   px = tmp[0];
   for (j=1;j<D;j++) px=-1.2*px+tmp[j];
   px =px-72.661;
   if (px<0) result+=px*px;
   return result;

}

Где функция устройства выглядит так:

    __global__ void cEvaluate_temp(double* tmp,double result, int D)
{  
  int M =60;
  double px; 
  double x=-1;
  double dx=(double)M ;
  int j;
  dx = 2/dx;
  int idx = blockIdx.x * blockDim.x + threadIdx.x;  
  if (idx < 60)   //<==>if (idx < M)
  {  
      px = tmp[0];
      for (j=1;j<D;j++)
      {
       px = x*px + tmp[j];
      }

      if (px<-1 || px>1) 
      { __syncthreads();
        result+=(1-px)*(1-px); //+=
      }  
       x+=dx;  
  }  
}

Я знаючто я не указал проблему, но мне кажется, что у меня их гораздо больше.

Я не знаю, когда копировать переменную на устройство, и когда она будет скопирована «автоматически».Теперь я использую CUDA 3.2 и есть проблема с эмуляцией (я хотел бы использовать printf), когда я запускаю NVCC с make emu = 1, при использовании printf не возникает ошибка, но я также не получаю никакого вывода.

Существует самая простая версия функции устройства, которую я тестировал.Кто-нибудь может объяснить, что произойдет со значением результата после его параллельного увеличения?Я думаю, что я должен использовать общую память устройства и синхронизацию, чтобы сделать что-то вроде "+ =".

    __global__ void cEvaluate(double* tmp,double result, int D)
{  
  int idx = blockIdx.x * blockDim.x + threadIdx.x;  
  if (idx < 60)   //<==>if (idx < M)
  {  
        result+=1;
        printf("res = %f ",result); //-deviceemu, make emu=1

  }  
} 

1 Ответ

1 голос
/ 29 марта 2011

Нет, переменная результат не распределяется между несколькими потоками.

Я хотел бы предложить иметь матрицу значений результатов в общей памяти, по одному результату для каждого потока, вычислитькаждое значение и свести его к одному значению.

      __global__ void cEvaluate_temp(double* tmp,double *global_result, int D)
{  
  int M =60;
  double px; 
  double x=-1;
  double dx=(double)M ;
  int j;
  dx = 2/dx;
  int idx = blockIdx.x * blockDim.x + threadIdx.x;  

  __shared__ shared_result [blocksize];


  if (idx >= 60) return;

  px = tmp[0];

  for (j=1;j<D;j++)
  {
    px = x*px + tmp[j];
  }

  if (px<-1 || px>1) 
  { 
    result[threadIdx] +=(1-px)*(1-px); 
  }  
       x+=dx;  
 }

 __syncthreads();

if( threadIdx.x == 0) {
total_result = 0.
for (idx in blocksize){
   total_result += result[idx];
}
global_result[0] = total_result;
}

Также вам нужен cudaMemcpy после вызова ядра.Ядра асинхронны и нуждаются в функции синхронизации.

Также используйте функции проверки ошибок при каждый вызов API CUDA.

...