2016-04-05 20 views
0

私は部分行列乗算をしたいと思います。 I機能を持っていると言う:OpenCLどのようにcl_memのメモリアドレスを変更するには?

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

AはM * K、BはK * Nである場合、CはM * Nであり、そしてA、B、Cは、ホストメモリfloat *h_A, *h_B, *hCによって渡されるすべての行の主要な1次元アレイであります以下の機能を持つ:

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); 
} 

私が聞きたい

私は、サブ行列の乗算を行いたい場合は

、スライスAは、行で言う:それは、この操作を行うには正しいコード

// 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); 
    } 

ですか?私は実行時エラーがあると言う:"CL_INVALID_MEM_OBJECT" (-38) OpenCLカーネル(clSetKernelArg)に引数を割り当てるとき。

私がこの操作をしたい理由は、入力行列AとBが大きくなったときに、行列乗算に間違った答えがあることです。

#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; 
    } 

とサイズは次のとおり:

マイOpenCLのカーネルがある

#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; 
    } 
} 

コードはNvidiaのOpenCLの行列乗算試料から採用されています。私のGPUは:インテル(R)HDグラフィックス4600.

ありがとう!

答えて

0

私はあなたがこれを行うことができるとは思わない:

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

cl_memが実際に複雑なデータ構造だけではなくデータポインタであるOpenCLの中のオブジェクト、ですので。実際のメモリへのデータポインタ、オブジェクトへの参照、メモリプロパティなどの情報を保持します。実行時間が異なると、cl_memオブジェクトの実装が異なる場合があります。そのためCL_INVALID_MEM_OBJECTエラーメッセージが表示されます。あなたは、サブ行列のデータを望んでいた得るために何ができるか

は、以下のいずれかです。

  1. は、2つの新しいcl_memオブジェクトを定義し、 にコピー作業を行うために別のカーネルを使用します。

  2. ホストでデータをコピーするために、clEnqueueCopyBuffer関数を使用してください コードドメイン。

  3. メモリバッファに使用CL_MEM_ALLOC_HOST_PTR、その後、メモリポインタをホストする がclEnqueueMapBuffer GPUのメモリをマップ使用し、 は、あなたが終了したときに返すためにポインタマップ解除、マップされたホストメモリに ポインタを使用してメモリの内容を変更しますGPUメモリ をデバイスメモリドメインに転送します。

関連する問題