2016-04-05 4 views
0

Ich möchte eine Sub-Matrix-Multiplikation machen. Sagen Ich habe eine Funktion:OpenCL Wie ändert man die Speicheradresse von cl_mem?

void MatMul(cl_mem A, cl_mem B, cl_mem C, int M, int K, int N) 

wobei A M * K, B ist K * N ist, C M * N, und A, B, C sind alle Zeilenhaupt 1 dimensionales Array von dem Host-Speicher übergeben float *h_A, *h_B, *hC mit der folgenden Funktion:

void ocl_push_array(cl_mem d_x, float *h_x, int n){ 
    size_t data_size = sizeof(float)*n; 
    err = clEnqueueWriteBuffer(queue, d_x, CL_TRUE, 0, data_size, h_x, 0, NULL, NULL); 
} 

ich möchte fragen,:

wenn ich Untermatrixmultiplikation tun wollen, sagen Slicing A Zeile:

// cl_mem A, B, C; 
    for(int x=0; x<M; x+=16) 
    { 
     cl_mem A_sub = (cl_mem)((float *)A+x*K); 
     cl_mem C_sub = (cl_mem)((float *)C+x*N); 
     if((M-x+1)>=16) 
      MatMul(A_sub, B, C_sub, 16, K, N); 
     else 
      MatMul(A_sub, B, C_sub, M-x+1, K, N); 
    } 

Ist es der richtige Code um diesen Vorgang zu tun? Ich habe einen Laufzeitfehler sagt: "CL_INVALID_MEM_OBJECT" (-38), wenn er dem OpenCL-Kernel Argumente (clSetKernelArg) zuweist.

Der Grund, warum ich diese Operation durchführen möchte, ist, dass die Matrixmultiplikation falsche Antworten erhalten hat, wenn meine Eingabematrix A und B groß wird.

Mein OpenCL-Kernel ist:

#define BLOCK_SIZE 16 

#define AS(i, j) As[j + i * BLOCK_SIZE] 
#define BS(i, j) Bs[j + i * BLOCK_SIZE] 

__kernel void 
matrixMul(__global float* A, __global float* B, __global float* C, 
    __local float* As, __local float* Bs, int uiWA, int uiWB) 
{ 
    int bx = get_group_id(0); 
    int by = get_group_id(1); 
    int tx = get_local_id(0); 
    int ty = get_local_id(1); 
    int aBegin = uiWA * BLOCK_SIZE * by; 
    int aEnd = aBegin + uiWA - 1; 
    int aStep = BLOCK_SIZE; 
    int bBegin = BLOCK_SIZE * bx; 
    int bStep = BLOCK_SIZE * uiWB; 
    float Csub = 0.0f; 
    for (int a = aBegin, b = bBegin; a <= aEnd; a += aStep, b += bStep) { 
     AS(ty, tx) = A[a + uiWA * ty + tx]; 
     BS(ty, tx) = B[b + uiWB * ty + tx]; 
     barrier(CLK_LOCAL_MEM_FENCE); 
     #pragma unroll 
     for (int k = 0; k < BLOCK_SIZE; ++k) 
     Csub += AS(ty, k) * BS(k, tx); 
      barrier(CLK_LOCAL_MEM_FENCE); 
     } 
     C[get_global_id(1) * get_global_size(0) + get_global_id(0)] = Csub; 
    } 

und die Größe ist:

#define BLOCK_SIZE 16 

size_t localWorkSize[] = {BLOCK_SIZE, BLOCK_SIZE}; 
size_t globalWorkSize[] = {shrRoundUp(BLOCK_SIZE, N), shrRoundUp(BLOCK_SIZE, M)}; 

size_t shrRoundUp(int group_size, int global_size) 
{ 
    int r = global_size % group_size; 
    if(r == 0) 
    { 
     return global_size; 
    } else 
    { 
     return global_size + group_size - r; 
    } 
} 

der Code von Nvidia OpenCL Matrixmultiplikation Probe angenommen wird. Meine GPU ist: Intel (R) HD Graphics 4600.

Vielen Dank!

Antwort

0

Ich glaube nicht, dies zu tun: Statt nur einen Datenzeiger

cl_mem A_sub = (cl_mem)((float *)A+x*K); 

Da cl_mem ein Objekt in OpenCL ist, die Struktur tatsächlich eine komplexe Daten. Es verwaltet Informationen wie Datenzeiger auf den tatsächlichen Speicher, Verweis auf das Objekt, Speichereigenschaften und so weiter. Verschiedene Laufzeiten können sogar unterschiedliche Implementierungen des cl_mem-Objekts haben. Deshalb haben Sie die CL_INVALID_MEM_OBJECT Fehlermeldung erhalten.

Was Sie tun können, um Daten für die Untermatrix erhalten wollte, ist eine der folgenden:

  1. definieren zwei neue cl_mem Objekte und einen separaten Kernel die Kopie zu tun verwenden.

  2. Verwenden Sie die clEnqueueCopyBuffer-Funktion, um die Daten auf dem Host Code-Domäne zu kopieren.

  3. Verwendung CL_MEM_ALLOC_HOST_PTR auf Speicherpuffer, und verwenden Sie dann clEnqueueMapBuffer den GPU-Speicher Karte Speicherzeiger Host und dann durch die Verwendung der zugeordneten Host-Speicher Zeiger, den Speicherinhalt ändern, wenn Sie unmap den Zeiger zu beenden, zurückzukehren der GPU-Speicher in die Speicherdomäne des Geräts.