0

openclカーネルにアトミック関数を実装しようとしています。私が作成している複数のスレッドは、単一のメモリ位置を並行して書き込もうとしています。その特定のコード行でシリアル実行を実行してもらいたい。私はこれまでアトミック関数を使用したことがありません。

多くのブログやフォーラムで同様の問題を見つけました。1つの解決策を試しています。つまり、セマフォをロックおよびロック解除するための2つの異なる関数「取得」と「解放」を使用しています。必要なopencl拡張機能を含めましたが、これらはすべて私のデバイス(NVIDIA GeForce GTX 630M)で確実にサポートされています。

私のカーネル実行構成:

global_item_size = 8;
ret = clEnqueueNDRangeKernel(command_queue2, kernel2, 1, NULL, &global_item_size2, &local_item_size2, 0, NULL, NULL);

これが私のコードです:reducer.cl

#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable
#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable
#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable
#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable

typedef struct data
{
  double dattr[10];
  int d_id;
  int bestCent;
}Data;

typedef struct cent
{
  double cattr[5];
  int c_id;
}Cent;

__global void acquire(__global int* mutex)
{
    int occupied;
    do {
        occupied = atom_xchg(mutex, 1);
    } while (occupied>0);
}

__global void release(__global int* mutex)
{
    atom_xchg(mutex, 0); //the previous value, which is returned, is ignored
}

__kernel void reducer(__global int *keyMobj, __global int *valueMobj,__global Data *dataMobj,__global Cent *centMobj,__global int *countMobj,__global double *sumMobj, __global int *mutex)
{
  __local double sum[2][2];
  __local int cnt[2];

  int i = get_global_id(0);
  int n,j;

  if(i<2)
    cnt[i] = countMobj[i];
  barrier(CLK_GLOBAL_MEM_FENCE);

  n = keyMobj[i];
  for(j=0; j<2; j++)
  {
     barrier(CLK_GLOBAL_MEM_FENCE);
          acquire(mutex);
             sum[n][j] += dataMobj[i].dattr[j];
      release(mutex);
  }

  if(i<2)
  {
    for(j=0; j<2; j++)
    {
       sum[i][j] = sum[i][j]/countMobj[i];
       centMobj[i].cattr[j] = sum[i][j];
    }
  }
}

残念ながら、解決策は私にはうまくいかないようです。centMobjをホストメモリに読み戻すときは、

ret = clEnqueueReadBuffer(command_queue2, centMobj, CL_TRUE, 0, (sizeof(Cent) * 2),  centNode, 0, NULL, NULL);
ret = clEnqueueReadBuffer(command_queue2, sumMobj, CL_TRUE, 0, (sizeof(double) * 2 * 2), sum, 0, NULL, NULL);

centMobjとsumMobjの両方でエラーコード=-5(CL_OUT_OF_RESOURCES)のエラーが発生します。

アトミック関数コードに問題があるか、ホストメモリへのデータの読み取りに問題があるかどうかがわかりません。アトミック関数を誤って使用している場合は、正しくしてください。前もって感謝します。

4

1 に答える 1

1

OpenCL では、ワークアイテム間の同期はワークグループ内でのみ実行できます。異なるワーク グループ間でワークアイテムを同期しようとするコードは、非常に特殊な (および実装/デバイスに依存する) ケースでは機能する可能性がありますが、一般的なケースでは失敗します。

解決策は、アトミックを使用して同じメモリ位置へのアクセスをシリアル化する (ただし、作業項目をブロックしない) か、コードを別の方法で再設計することです。

于 2013-02-05T07:16:09.187 に答える