OpenCL カーネルから単一のグローバル値に追加することに関連するバグと戦っています。
次の (単純化しすぎた) 例を考えてみましょう。
__kernel some_kernel(__global unsigned int *ops) {
unsigned int somevalue = ...; // a non-zero value is assigned here
*ops += somevalue;
}
clCreateBuffer
およびを介してゼロとして初期化された引数を渡しますclEnqueueWriteBuffer
。値を追加した後、キューを終了させて読み戻すと、ゼロ以外の値が得られると想定しました。
次に、これは奇妙な競合である可能性があると考えたので、アトミック操作を実行しようとしました。
__kernel some_kernel(__global unsigned int *ops) {
unsigned int somevalue = ...; // a non-zero value is assigned here
atomic_add(ops, somevalue);
}
残念ながら、サイコロはありません。値をホスト ポインターに読み戻した後でも、値はゼロのままです。カーネルの実行でゼロ以外の値があることを既に確認してsomevalue
おり、途方に暮れています。
要求に応じて、メモリを作成するためのコード:
unsigned int *cpu_ops = new unsigned int;
*cpu_ops = 0;
cl_mem_flags flags = CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR;
cl_int error;
cl_mem buffer = clCreateBuffer(context, flags, sizeof(unsigned int), (void*)cpu_ops, &error);
// error code check snipped
error = clEnqueueWriteBuffer(queue, buffer, CL_TRUE, 0, sizeof(unsigned int), (void*)cpu_ops, 0, NULL, NULL);
// error code check snipped
// snip: program setup - it checks out, no errors
cl_kernel some_kernel = clCreateKernel(program, "some_kernel", &error);
// error code check snipped
cl_int error = clSetKernelArg(some_kernel, 0, sizeof(cl_mem), &buffer);
// error code check snipped
//global_work_size and local_work_size set elsewhere
cl_int error = clEnqueueNDRangeKernel(queue, some_kernel, 1, NULL, &global_work_size, &local_work_size, 0, NULL, NULL);
// error code check snipped
clFinish(queue);
cl_int error = clEnqueueReadBuffer(queue, buffer, CL_TRUE, 0, sizeof(unsigned int), (void*)cpu_ops, 0, NULL, NULL);
// error code check snipped
// at this point, cpu_ops still has it's initial value (whatever that value might have been set to)'
エラーが発生しないため、エラー チェック コードをスキップしました。私は実際に、データの送受信、プラットフォームとコンテキストの設定、プログラムのコンパイルなどに一連のカスタム ヘルパー関数を使用しているため、上記は適切なヘルパーの本体で構成され、パラメーターの名前は次のように変更されていますわかる。
これが私の側の間違いまたは理解不足であることはかなり確信していますが、これについての意見がどうしても必要です。