Zum Erlernen von OpenCL habe ich mir eine Vektor-Matrix-Multiplikation
geschrieben, bei der ich mir aber nicht sicher bin, inwieweit die
dahinterstehenden Überlegungen richtig sind.
Prinzipiell verstehe ich Workgroups so, daß mit diesen das Gesamtproblem
in von dem jeweiligen Gerät gleichzeitig ausführbare Häppchen zerlegt
wird.
Deshalb habe ich die elementweise Zeilenvektor/Vektormultiplikation
durch je eine Workgroup ausführen lassen, wobei erst einmal die erste
Einheit der Workgroup den Produktvektor aufsummiert.
Somit wäre die "Global Size" die Größe der Matrix und die "Local Size"
die Anzahl der Zeilenvektoren / Produktvektorgröße.
Kann ich generell (bei mir funktioniert das) den Kernel dann so
parameterisieren:
1 | cl::NDRange globalSize(A.getNumberOfRows()*A.getNumberOfColumns());
|
2 | cl::NDRange localSize(A.getNumberOfColumns());
|
3 | rcpp::KernelFunctor vektorSquareFunc(matrixMultiplicationKernel,queue,globalSize,localSize);
|
4 | vektorSquareFunc(cl::Buffer(A),
|
5 | cl::Buffer(x),
|
6 | cl::Buffer(y),
|
7 | A.getNumberOfRows(),
|
8 | A.getNumberOfColumns(),
|
9 | rcpp::KernelFunctor::createLocalMemoryBuffer<double>(A.getNumberOfColumns()),
|
10 | rcpp::KernelFunctor::createLocalMemoryBuffer<double>(A.getNumberOfColumns()));
|
Den Kernel selbst habe ich so geschrieben, wobei mich momentan der
Verdacht überkommt, daß das "Cachen" des Produktvektors in einen lokalen
Puffer unnötig ist - es sei denn, die physische Arbeitsgruppe wird
wieder rangenommen:
1 | /**
|
2 | * @brief Matrix multiplication kernel.
|
3 | * @param A The matrix as concencated row vectors.
|
4 | * @param x Multiplicant vector (size: number of columns in A)
|
5 | * @param y Result vector A*x (size: number of rows in A)
|
6 | * @param nRows Number of rows in the matrix.
|
7 | * @param nCols Number of columns in the matrix.
|
8 | * @param xbuffer Local memory buffer for the multiplicant vector.
|
9 | */
|
10 |
|
11 |
|
12 |
|
13 | __kernel void matrixMultiplication(__global double *A,__global double *x,__global double *y,unsigned int nRows,unsigned int nCols,__local double *xbuffer,__local double *resultBuffer)
|
14 | {
|
15 | int column=get_local_id(0); // equals the column number
|
16 | int row=get_group_id(0); // fetch the workgroup number - should be the row number
|
17 | int globalID=get_global_id(0);
|
18 |
|
19 | xbuffer[column]=x[column];
|
20 |
|
21 | barrier(CLK_LOCAL_MEM_FENCE);
|
22 |
|
23 | resultBuffer[column]=xbuffer[column]*A[globalID];
|
24 |
|
25 | barrier(CLK_LOCAL_MEM_FENCE);
|
26 |
|
27 | double sum=0;
|
28 |
|
29 | if(column==0)
|
30 | {
|
31 | for(int k=0;k<nCols;k++) sum += resultBuffer[k];
|
32 | y[row]=sum;
|
33 | }
|
34 |
|
35 | }
|