OpenCL (aparapi) простое сокращение медленно на Radeon

#opencl #aparapi

#opencl #aparapi

Вопрос:

Я пытаюсь закодировать простое сокращение (в данном случае сумму) по большому двойному массиву в OpenCL. Я просмотрел онлайн-руководства и обнаружил, что это, по сути, способ решить мою проблему:

 #pragma OPENCL EXTENSION cl_khr_fp64 : enable

typedef struct This_s{
   __global double *nums;
   int nums__javaArrayLength;
   __local double *buffer;
   __global double *res;
   int passid;
}This;
int get_pass_id(This *this){
   return this->passid;
}
__kernel void run(
   __global double *nums, 
   int nums__javaArrayLength, 
   __local double *buffer, 
   __global double *res, 
   int passid
){
   This thisStruct;
   This* this=amp;thisStruct;
   this->nums = nums;
   this->nums__javaArrayLength = nums__javaArrayLength;
   this->buffer = buffer;
   this->res = res;
   this->passid = passid;
   {
      int tid = get_local_id(0);
      int i = (get_group_id(0) * get_local_size(0))   get_local_id(0);
      int gridSize = get_local_size(0) * get_num_groups(0);
      int n = this->nums__javaArrayLength;
      double cur = 0.0;
      for (; i<n; i = i   gridSize){
         cur = cur   this->nums[i];
      }
      this->buffer[tid]  = cur;
      barrier(CLK_LOCAL_MEM_FENCE);
      barrier(CLK_LOCAL_MEM_FENCE);
      if (tid<32){
         this->buffer[tid]  = this->buffer[tid]   this->buffer[(tid   32)];
      }
      barrier(CLK_LOCAL_MEM_FENCE);
      if (tid<16){
         this->buffer[tid]  = this->buffer[tid]   this->buffer[(tid   16)];
      }
      barrier(CLK_LOCAL_MEM_FENCE);
      if (tid<8){
         this->buffer[tid]  = this->buffer[tid]   this->buffer[(tid   8)];
      }
      barrier(CLK_LOCAL_MEM_FENCE);
      if (tid<4){
         this->buffer[tid]  = this->buffer[tid]   this->buffer[(tid   4)];
      }
      barrier(CLK_LOCAL_MEM_FENCE);
      if (tid<2){
         this->buffer[tid]  = this->buffer[tid]   this->buffer[(tid   2)];
      }
      barrier(CLK_LOCAL_MEM_FENCE);
      if (tid<1){
         this->buffer[tid]  = this->buffer[tid]   this->buffer[(tid   1)];
      }
      barrier(CLK_LOCAL_MEM_FENCE);
      if (tid==0){
         this->res[get_group_id(0)]  = this->buffer[0];
      }
      return;
   }
}
  

Если вам интересно о странном this , это (к сожалению, необходимый) артефакт aparapi, который я использую для перевода Java в OpenCL.

Мое ядро выдает правильные результаты, и на достаточно мощном оборудовании Nvidia это примерно в 10 раз быстрее, чем последовательная сумма в Java. На Radeon R9 280, однако, это сопоставимо по производительности с простым Java-кодом.

Я профилировал ядро с помощью CodeXL. Это говорит мне, что загрузка MemUnitBusy составляет всего 6%. Почему оно такое низкое?

Комментарии:

1. Я открыл заявку на это и добавил награду здесь: github.com/Syncleus/aparapi/issues/107

Ответ №1:

Оказывается, что OpenCL (напрямую) не виноват, а управление буфером aparapis.

Я опробовал точно такое же ядро без aparapi, и производительность хорошая. Он становится плохим, как только я использую CL_MEM_USE_HOST_PTR , что, к сожалению, является единственным вариантом при использовании aparapi. Похоже, AMD не копирует память хоста на устройство с этой опцией даже после нескольких запусков «прогрева».

Ответ №2:

Возможно, вы захотите рассмотреть возможность перехода к более активному проекту на aparapi.com . Он включает в себя несколько исправлений ошибок и множество дополнительных функций и улучшений производительности по сравнению со старой библиотекой, которую вы связали выше. Он также находится в maven central с примерно дюжиной выпусков. так что его проще использовать. Новый репозиторий Github здесь.