CLBufferWrite

Escribe un array en el búfer OpenCL y devuelve el número de elementos escritos.

uint  CLBufferWrite(
   int          buffer,                    // manejador para el búfer OpenCL
   const void&  data[],                    // array de valores
   uint         buffer_offset=0,           // offset en el búfer OpenCL en bytes, por defecto es 0
   uint         data_offset=0,             // offset dentro del array en elementos, por defecto es 0
   uint         data_count=WHOLE_ARRAY     // número de valores del array para la escritura, por defecto es el array entero
   );

Asimismo, existe una versión para trabajar con matrices y vectores.

Escribe los valores de una matriz en un búfer y retorna true en caso de éxito.

uint  CLBufferWrite(
   int           buffer,                    // manejador al búfer OpenCL
   uint          buffer_offset,             // desplazamiento en el búfer OpenCL en bytes
   matrix<T>     &mat                       // matriz de valores para anotar en el búfer
   );

Escribe los valores de un vector en un búfer y retorna true en caso de éxito.

uint  CLBufferWrite(
   int           buffer,                    // manejador al búfer OpenCL
   uint          buffer_offset,             // desplazamiento en el búfer OpenCL en bytes
   vector<T>     &vec                       // vector de valores para anotar en el búfer
   );

Parámetros

buffer

[in]  Manejador del búfer OpenCL.

data[]

[in]  Array de valores que hay que escribir en el búfer OpenCL. Se pasa por referencia.

buffer_offset

[in]  Desplazamiento (offset) en el búfer OpenCL en bytes, a partir del cual se empieza la escritura. Por defecto, la escritura se hace desde el principio del búfer.

data_offset

[in]  Índice del primer elemento del array a partir del cual se cogen los valores desde el array para la escritura en el búfer OpenCL. Por defecto, los valores se cogen desde el principio del array.

data_count

[in]  Número de valores que hay que escribir. Por defecto, todos los valores del array.

mat

[out]  La matriz para leer los datos del búfer puede ser de cualquiera de los tres tipos – matrix, matrixf o matrixc.

vec

[out]  El vector para leer los datos del búfer puede ser de cualquiera de los tres tipos – vector, vectorf o vectorc.

Valor devuelto

Número de valores que se han escrito. En caso del error, devuelve 0. Para obtener la información sobre el error, utilice la función GetLastError().

true en caso de ejecución exitosa al trabajar con una matriz o vector; en caso de error, se retornará false.

Nota

Para los arrays unidimensionales, el número del elemento a partir del que se empieza la lectura de dato para su escritura en el búfer OpenCL, se calcula teniendo en cuenta la bandera AS_SERIES.

Un array con dos o más dimensiones se representa como unidimensional. En este caso data_offset es el número de elementos que hay que saltar en la representación, y no el número de elementos en la primera dimensión.

Ejemplo de multiplicación de matrices usando el método MatMul y cálculos paralelos en OpenCL

#define M       3000      // número de líneas en la primera matriz
#define K       2000      // el número de columnas en la primera matriz es igual a número de líneas en la segunda 
#define N       3000      // número de columnas en la segunda matriz
 
//+------------------------------------------------------------------+
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()
 {
//--- inicializamos el generador de números aleatorios
  MathSrand((int)TimeCurrent());
//--- rellenamos la matriz del tamaño indicado con valores aleatorios
  matrixf mat1(MKMatrixRandom) ;    // primera matriz
  matrixf mat2(KNMatrixRandom);     // segunda matriz
 
//--- calculamos el producto de las matrices de forma ingenua
  uint start=GetTickCount();
  matrixf matrix_naive=matrixf::Zeros(MN);// aquí anotamos el resultado de la multiplicación de las dos matrices
  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;   
     
//--- calculamos el producto de las matrices usando MatMull
  start=GetTickCount();
  matrixf matrix_matmul=mat1.MatMul(mat2);
  uint time_matmul=GetTickCount()-start;     
  
//--- calculamos el producto de las matrices en OpenCL
  matrixf matrix_opencl=matrixf::Zeros(MN);
  int cl_ctx;             // manejador de contexto
  if((cl_ctx=CLContextCreate(CL_USE_GPU_ONLY))==INVALID_HANDLE)
   {
    Print("OpenCL no ha sido encontrado, salimos");
    return;
   }
  int cl_prg;             // manejador del programa 
  int cl_krn;             // manejador del kernel
  int cl_mem_in1;         // manejador del primer búfer (de entrada)
  int cl_mem_in2;         // manejador del segundo búfer (de entrada)
  int cl_mem_out;         // manejador del tercer búfer (de entrada)
//--- creamos el programa y el kernel
  cl_prg = CLProgramCreate(cl_ctxclSrc);
  cl_krn = CLKernelCreate(cl_prg"matricesMul");
//--- creamos los tres búferes para las tres matrices
  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);
//--- la tercera matriz es de salida
  cl_mem_out=CLBufferCreate(cl_ctxM*N*sizeof(float), CL_MEM_READ_WRITE);
//--- establecemos los argumentos del kernel
  CLSetKernelArgMem(cl_krn0cl_mem_in1);
  CLSetKernelArgMem(cl_krn1cl_mem_in2);
  CLSetKernelArgMem(cl_krn2cl_mem_out);
//--- escribimos las matrices en los búferes del dispositivo
  CLBufferWrite(cl_mem_in10mat1);
  CLBufferWrite(cl_mem_in20mat2);
  CLBufferWrite(cl_mem_out0matrix_opencl);
//--- iniciando el tiempo de ejecución del código de OpenCL
  start=GetTickCount();
//--- establecemos los parámetros del espacio de trabajo de la tarea y ejecutamos el programa de OpenCL
  uint  offs[2] = {00};
  uint works[2] = {MN};
  start=GetTickCount();  
  bool ex=CLExecute(cl_krn2offsworks);
//--- calculamos el resultado en la matriz
  if(CLBufferRead(cl_mem_out0matrix_opencl))
    PrintFormat("Leída la matriz [%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("Comparamos el tiempo de cálculo con cada método");
  PrintFormat("Naive product time = %d ms",time_naive);
  PrintFormat("MatMul product time = %d ms",time_matmul);
  PrintFormat("OpenCl product time = %d ms",time_opencl);  
//--- liberamos todos los contextos de OpenCL
  CLFreeAll(cl_ctxcl_prgcl_krncl_mem_in1cl_mem_in2cl_mem_out);
 
//--- comparamos entre sí todas las matrices de resultados obtenidas
  Print("¿Cuántos errores de divergencia hay entre las matrices de resultados?");
  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);
/*
  Resultado:
   
   Leída la matriz [3000 x 3000]: 
   Comparamos el tiempo de cálculo con cada método
   Naive product time = 54750 ms
   MatMul product time = 4578 ms
   OpenCl product time = 922 ms
   ¿Cuántos errores de divergencia hay entre las matrices de resultados?
   matrix_direct.Compare(matrix_matmul,1e-12)=0
   matrix_matmul.Compare(matrix_opencl,1e-12)=0
*/  
 }
//+------------------------------------------------------------------+
//| Rellena la matriz con valores aleatorios                         |
//+------------------------------------------------------------------+
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.);
     }
   }
 }
//+------------------------------------------------------------------+
//| Liberamos todos los contextos de OpenCL                          |
//+------------------------------------------------------------------+
void CLFreeAll(int cl_ctxint cl_prgint cl_krn,
               int cl_mem_in1int cl_mem_in2int cl_mem_out)
 {
//--- eliminamos en una secuencia inversa todos los contextos de OpenCL creados
  CLBufferFree(cl_mem_in1);
  CLBufferFree(cl_mem_in2);
  CLBufferFree(cl_mem_out);
  CLKernelFree(cl_krn);
  CLProgramFree(cl_prg);
  CLContextFree(cl_ctx);
 }