CLBufferWrite

Inscrit le tableau au tampon OpenCL et rend la quantité d'éléments inscrits.

uint  CLBufferWrite(
   int          buffer,                    // le handle sur le tampon OpenCL
   const void&  data[],                    // le tableau des valeurs
   uint         buffer_offset=0,           // le décalage dans le tampon OpenCL en octets, par défaut 0
   uint         data_offset=0,             // le décalage dans le tampon dans les éléments, par défaut 0
   uint         data_count=WHOLE_ARRAY     // le nombre des valeurs du tableau pour l'enregistrement, par défaut tout le tableau
   );

Il existe d'autres versions pour l'utilisation de matrices et vecteurs.

Ecrit les valeurs de la matrice dans le buffer et retourne true en cas de succès.

uint  CLBufferWrite(
   int           buffer,                    // handle vers le buffer OpenCL
   uint          buffer_offset,             // décalage dans le buffer OpenCL en octets
   matrix<T>     &mat                       //la matrice des valeurs à écrire dans le buffer
   );

Ecrit les valeurs du vecteur dans le buffer et retourne true en cas de succès.

uint  CLBufferWrite(
   int           buffer,                    // handle vers le buffer OpenCL
   uint          buffer_offset,             // décalage dans le buffer OpenCL en octets
   vector<T>     &vec                       // le vecteur de valeurs à écrire dans le buffer
   );

Paramètres

buffer

[in]  Le handle du tampon OpenCL.

data[]

[in]  le tableau des valeurs, lesquelles il est nécessaire d'inscrire au tampon OpenCL. est transmis selon la référence.

buffer_offset

[in]  le décalage dans le tampon OpenCL en octets, par lequel commence l'inscription. Par défaut l'inscription va dès le début du tampon.

data_offset

[in]  L'index du premier élément du tableau, à partir de lequel les valeurs sont tirées du tableau pour l'inscription au tampon OpenCL. Par défaut on prend les valeurs dès le début du tableau.

data_count

[in]  Le nombre de valeurs, lesquelles il faut inscrire. Toutes les valeurs du tableau par défaut.

mat

[out]  La matrice pour les lire les données du buffer peut être de 3 types : matrix, matrixf ou matrixc.

vec

[out]  Le vecteur pour les lire les données du buffer peut être de 3 types : vector, vectorf ou vectorc.

La valeur rendue

Le nombre d'éléments inscrits, en cas de l'erreur 0 se revient. Pour recevoir l'information sur l'erreur, utilisez la fonction GetLastError().

true si une matrice ou un vecteur est géré avec succès, sinon false.

Note

Pour les tableaux unidimentionnels le numéro de l'élément, par qui commence la lecture des données pour l'inscription au tampon OpenCL, est calculé en prenant en compte le drapeau AS_SERIES.

Le tableau avec la dimension deux et plus est présenté comme unidimentionnel. Dans ce cas data_offset — c'est une quantité d'éléments, qu'il faut manquer dans la représentation, et non le nombre d'éléments dans une première dimension.

Exemple de multiplication d'une matrice avec la méthode MatMul et le calcul en parallèle avec OpenCL

#define M       3000      // le nombre de lignes de la première matrice
#define K       2000      // le nombre de colonnes de la première matrice est égal au nombre de lignes de la seconde
#define N       3000      // le nombre de colonnes de la deuxième matrice
 
//+------------------------------------------------------------------+
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";
//+------------------------------------------------------------------+
//| Fonction de démarrage du programme                               |
//+------------------------------------------------------------------+
void OnStart()
 {
//--- initialise le générateur de nombres aléatoires
  MathSrand((int)TimeCurrent());
//--- remplit les matrices de la taille donnée avec des valeurs aléatoires
  matrixf mat1(MKMatrixRandom) ;    // première matrice
  matrixf mat2(KNMatrixRandom);     // deuxième matrice
 
//--- calcule le produit des matrices avec une méthode naïve
  uint start=GetTickCount();
  matrixf matrix_naive=matrixf::Zeros(MN);// le résultat de la multiplication des 2 matrices est défini ici
  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;   
     
//--- calcule le produit des matrices avec MatMull
  start=GetTickCount();
  matrixf matrix_matmul=mat1.MatMul(mat2);
  uint time_matmul=GetTickCount()-start;     
  
//--- calcule le produit des matrices avec OpenCL
  matrixf matrix_opencl=matrixf::Zeros(MN);
  int cl_ctx;             // handle du contexte
  if((cl_ctx=CLContextCreate(CL_USE_GPU_ONLY))==INVALID_HANDLE)
   {
    Print("OpenCL non trouvé, fin");
    return;
   }
  int cl_prg;             // handle du programme
  int cl_krn;             // handle du noyau
  int cl_mem_in1;         // handle du premier buffer (entrées)
  int cl_mem_in2;         // handle du deuxième buffer (entrées)
  int cl_mem_out;         // handle du troisième buffer (sorties)
//--- crée le programme et le noyau
  cl_prg = CLProgramCreate(cl_ctxclSrc);
  cl_krn = CLKernelCreate(cl_prg"matricesMul");
//--- crée les 3 buffers pour les 3 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);
//--- 3ème matrice - sorties
  cl_mem_out=CLBufferCreate(cl_ctxM*N*sizeof(float), CL_MEM_READ_WRITE);
//--- définit les arguments du noyau
  CLSetKernelArgMem(cl_krn0cl_mem_in1);
  CLSetKernelArgMem(cl_krn1cl_mem_in2);
  CLSetKernelArgMem(cl_krn2cl_mem_out);
//--- écrit les matrices dans le buffer du périphérique
  CLBufferWrite(cl_mem_in10mat1);
  CLBufferWrite(cl_mem_in20mat2);
  CLBufferWrite(cl_mem_out0matrix_opencl);
//--- heure de démarrage de l'exécution du code OpenCL
  start=GetTickCount();
//--- définit les paramètres de la zone de travail de la tâche et exécute le programme OpenCL
  uint  offs[2] = {00};
  uint works[2] = {MN};
  start=GetTickCount();  
  bool ex=CLExecute(cl_krn2offsworks);
//--- calcule le résultat dans la matrice
  if(CLBufferRead(cl_mem_out0matrix_opencl))
    PrintFormat("[%d x %d] matrice lue : "matrix_opencl.Rows(), matrix_opencl.Cols());
   else
      Print("CLBufferRead(cl_mem_out, 0, matrix_opencl a échoué. Erreur ",GetLastError()); 
  uint time_opencl=GetTickCount()-start;   
  Print("Comparaison des temps de calcul de chaque méthode");
  PrintFormat("Produit naïf = %d ms",time_naive);
  PrintFormat("Produit MatMul = %d ms",time_matmul);
  PrintFormat("Produit OpenCl = %d ms",time_opencl);  
//--- libère tous les contextes OpenCL
  CLFreeAll(cl_ctxcl_prgcl_krncl_mem_in1cl_mem_in2cl_mem_out);
 
//--- compare les matrices de résultats obtenues
  Print("Combien y a-t-il d'erreurs de divergence entre les matrices de résultats ?");
  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);
/*
  Résultat :
   
   [3000 x 3000] matrice lue : 
  Comparaison des temps de calcul de chaque méthode
   Produit naïf = 54750 ms
   Produit MatMul  = 4578 ms
   Produit OpenCl  = 922 ms
  Combien y a-t-il d'erreurs de divergence entre les matrices de résultats ?
   matrix_direct.Compare(matrix_matmul,1e-12)=0
   matrix_matmul.Compare(matrix_opencl,1e-12)=0
*/  
 }
//+------------------------------------------------------------------+
//| Remplit la matrice avec des valeurs aléatoires                   |
//+------------------------------------------------------------------+
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.);
     }
   }
 }
//+------------------------------------------------------------------+
//| Libère tous les contextes OpenCL                                 |
//+------------------------------------------------------------------+
void CLFreeAll(int cl_ctxint cl_prgint cl_krn,
               int cl_mem_in1int cl_mem_in2int cl_mem_out)
 {
//--- efface tous les contextes créés par OpenCL en ordre inverse
  CLBufferFree(cl_mem_in1);
  CLBufferFree(cl_mem_in2);
  CLBufferFree(cl_mem_out);
  CLKernelFree(cl_krn);
  CLProgramFree(cl_prg);
  CLContextFree(cl_ctx);
 }