CLBufferWrite

Записывает массив в буфер OpenCL и возвращает количество записанных элементов.

uint  CLBufferWrite(
   int          buffer,                    // хендл на буфер OpenCL
   const void&  data[],                    // массив значений
   uint         buffer_offset=0,           // смещение в OpenCL буфере в байтах, по умолчанию 0 при работе с массивами
   uint         data_offset=0,             // смещение в массиве в элементах, по умолчанию 0
   uint         data_count=WHOLE_ARRAY     // количество значений из массива для записи, по умолчанию весь массив
   );

Существуют также версии для работы матрицами и векторами.

Записывает значения из матрицы в буфер и возвращает true в случае успеха.

uint  CLBufferWrite(
   int           buffer,                    // хендл на буфер OpenCL
   uint          buffer_offset,             // смещение в OpenCL буфере в байтах
   matrix<T>     &mat                       // матрица значений для записи в буфер
   );

Записывает значения из вектора в буфер и возвращает true в случае успеха.

uint  CLBufferWrite(
   int           buffer,                    // хендл на буфер OpenCL
   uint          buffer_offset,             // смещение в OpenCL буфере в байтах
   vector<T>     &vec                       // вектор значений для записи в буфер
   );

Параметры

buffer

[in]  Хендл буфера OpenCL.

data[]

[in]  Массив значений, которые необходимо записать в буфер OpenCL. Передается по ссылке.

buffer_offset

[in]  Смещение в OpenCL буфере в байтах, с которого начинается запись. По умолчанию запись идет с самого начала буфера.

data_offset

[in]  Индекс первого элемента массива, начиная с которого берутся значения из массива для записи в OpenCL буфер. По умолчанию значения берутся с самого начала массива.

data_count

[in]  Количество значений, которые нужно записать. По умолчанию все значения массива.

mat

[out]  Матрица для чтения данных из буфера может быть любого из трех типиов — matrix, matrixf или matrixc.

vec

[out]  Вектор для чтения данных из буфера может быть любого из трех типиов — vector, vectorf или vectorc.

Возвращаемое значение

Количество записанных элементов, в случае ошибки возвращается 0. Для получения информации об ошибке используйте функцию GetLastError().

true при успешном выполнении при работе с матрицей или вектором, в случае ошибки возвращается false.

Примечание

Для одномерных массивов номер элемента, с которого начинается чтение данных для записи в буфер OpenCL, вычисляется с учётом флага AS_SERIES.

Массив с размерностью два и более представляется как одномерный. В этом случае data_offset – это количество элементов, которое следует пропустить в представлении, а не количество элементов в первой размерности.

Пример умножения матриц с помощью метода MatMul и параллельных вычислений в OpenCL

#define M       3000      // число строк в первой матрице
#define K       2000      // число столбцов в первой матрице равно числу строк во второй 
#define N       3000      // число столбцов во второй матрице
 
//+------------------------------------------------------------------+
const string clSrc=
  "#define N     "+IntegerToString(N)+"                              \r\n"
  "#define K     "+IntegerToString(K)+"                              \r\n"
  "                                                                  \r\n"
  "__kernel void matricesMul( __global float *in1,                   \r\n"
  "                           __global float *in2,                   \r\n"
  "                           __global float *out  )                 \r\n"
  "{                                                                 \r\n"
  "  int m = get_global_id( 0 );                                     \r\n"
  "  int n = get_global_id( 1 );                                     \r\n"
  "  float sum = 0.0;                                                \r\n"
  "  for( int k = 0; k < K; k ++ )                                   \r\n"
  "     sum += in1[ m * K + k ] * in2[ k * N + n ];                  \r\n"
  "  out[ m * N + n ] = sum;                                         \r\n"
  "}                                                                 \r\n";
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
 {
//--- инициализируем генератор случайных чисел
  MathSrand((int)TimeCurrent());
//--- заполним матрицы заданного размера случайными значениями
  matrixf mat1(MKMatrixRandom) ;    // первая матрица
  matrixf mat2(KNMatrixRandom);     // вторая матрица
 
//--- посчитаем произведение матриц наивным способом
  uint start=GetTickCount();
  matrixf matrix_naive=matrixf::Zeros(MN);// сюда запишем результат умножения двух матриц
  for(int m=0m<Mm++)
    for(int k=0k<Kk++)
      for(int n=0n<Nn++)
        matrix_naive[m][n]+=mat1[m][k]*mat2[k][n];
  uint time_naive=GetTickCount()-start;   
     
//--- посчитаем произведение матриц через MatMull
  start=GetTickCount();
  matrixf matrix_matmul=mat1.MatMul(mat2);
  uint time_matmul=GetTickCount()-start;     
  
//--- посчитаем произведение матриц в OpenCL
  matrixf matrix_opencl=matrixf::Zeros(MN);
  int cl_ctx;             // хэндл контекста
  if((cl_ctx=CLContextCreate(CL_USE_GPU_ONLY))==INVALID_HANDLE)
   {
    Print("OpenCL не найдено, выходим");
    return;
   }
  int cl_prg;             // хэндл программы 
  int cl_krn;             // хэндл кернела
  int cl_mem_in1;         // хэндл первого буфера (входного)
  int cl_mem_in2;         // хэндл второго буфера (входного)
  int cl_mem_out;         // хэндл третьего буфера (выходного)
//--- создаем программу и кернел
  cl_prg = CLProgramCreate(cl_ctxclSrc);
  cl_krn = CLKernelCreate(cl_prg"matricesMul");
//--- создаем все три буфера для трех матриц
  cl_mem_in1=CLBufferCreate(cl_ctxM*K*sizeof(float), CL_MEM_READ_WRITE);
  cl_mem_in2=CLBufferCreate(cl_ctxK*N*sizeof(float), CL_MEM_READ_WRITE);
//--- третья матрица - выходная
  cl_mem_out=CLBufferCreate(cl_ctxM*N*sizeof(float), CL_MEM_READ_WRITE);
//--- устанавливаем аргументы кернела
  CLSetKernelArgMem(cl_krn0cl_mem_in1);
  CLSetKernelArgMem(cl_krn1cl_mem_in2);
  CLSetKernelArgMem(cl_krn2cl_mem_out);
//--- пишем матрицы в буферы девайса
  CLBufferWrite(cl_mem_in10mat1);
  CLBufferWrite(cl_mem_in20mat2);
  CLBufferWrite(cl_mem_out0matrix_opencl);
//--- старт времени исполнения кода OpenCL
  start=GetTickCount();
//--- устанавливаем параметры рабочего пространства задачи и исполняем программу OpenCL
  uint  offs[2] = {00};
  uint works[2] = {MN};
  start=GetTickCount();  
  bool ex=CLExecute(cl_krn2offsworks);
//--- считываем результат в матрицу
  if(CLBufferRead(cl_mem_out0matrix_opencl))
    PrintFormat("Прочитана матрица [%d x %d]: "matrix_opencl.Rows(), matrix_opencl.Cols());
   else
      Print("CLBufferRead(cl_mem_out, 0, matrix_opencl failed. Error ",GetLastError()); 
  uint time_opencl=GetTickCount()-start;   
  Print("Сравним время вычислений каждым методом");
  PrintFormat("Naive product time = %d ms",time_naive);
  PrintFormat("MatMul product time = %d ms",time_matmul);
  PrintFormat("OpenCl product time = %d ms",time_opencl);  
//--- освободим все OpenCL контексты
  CLFreeAll(cl_ctxcl_prgcl_krncl_mem_in1cl_mem_in2cl_mem_out);
 
//--- сравним все полученные матрицы результатов между собой 
  Print("Cколько ошибок расхождения между матрицами результатов?");
  ulong errors=matrix_naive.Compare(matrix_matmul,(float)1e-12);
  Print("matrix_direct.Compare(matrix_matmul,1e-12)=",errors);
  errors=matrix_matmul.Compare(matrix_opencl,float(1e-12));
  Print("matrix_matmul.Compare(matrix_opencl,1e-12)=",errors);
/*
   Результат: 
   
   Прочитана матрица [3000 x 3000]: 
   Сравним время вычислений каждым методом
   Naive product time = 54750 ms
   MatMul product time = 4578 ms
   OpenCl product time = 922 ms
   Cколько ошибок расхождения между матрицами результатов?
   matrix_direct.Compare(matrix_matmul,1e-12)=0
   matrix_matmul.Compare(matrix_opencl,1e-12)=0
*/  
 }
//+------------------------------------------------------------------+
//| Заполняет матрицу случайными значениями                          |
//+------------------------------------------------------------------+
void MatrixRandom(matrixfm)
 {
  for(ulong r=0r<m.Rows(); r++)
   {
    for(ulong c=0c<m.Cols(); c++)
     {
      m[r][c]=(float)((MathRand()-16383.5)/32767.);
     }
   }
 }
//+------------------------------------------------------------------+
//| Освободим все OpenCL контексты                                   |
//+------------------------------------------------------------------+
void CLFreeAll(int cl_ctxint cl_prgint cl_krn,
               int cl_mem_in1int cl_mem_in2int cl_mem_out)
 {
//--- удвляем в обратной последовательности все созданные OpenCL контексты
  CLBufferFree(cl_mem_in1);
  CLBufferFree(cl_mem_in2);
  CLBufferFree(cl_mem_out);
  CLKernelFree(cl_krn);
  CLProgramFree(cl_prg);
  CLContextFree(cl_ctx);
 }