如何正确初始化此 C++ for openCL 内核的输入/输出参数?
Posted
技术标签:
【中文标题】如何正确初始化此 C++ for openCL 内核的输入/输出参数?【英文标题】:How do I properly initialise the input/output arguments for this C++ for openCL kernel? 【发布时间】:2021-12-23 03:09:50 【问题描述】:这是我第一次编写 OpenCL 计算单元,所以我从小处着手;这是我的基本测试内核:
kernel void test_kernel(global float* in, global float* out)
int thread_id = get_global_id(0);
printf("%d", thread_id);
out[thread_id] = in[thread_id] + thread_id;
下面是尝试为参数构造缓冲区并运行它的 c++ 代码:
...
...
cl::Kernel kernel(program, "test_kernel", &cl_error);
if (cl_error != 0)
std::cout << "Error - cl::Kernel - " << getErrorString(cl_error) << std::endl;
return 1;
cl::CommandQueue command_queue(context, device);
cl::vector<float> input_vector 0.1f, 0.2f, 0.3f, 0.4f, 0.5f ;
cl::vector<float> output_vector 0.0f, 0.0f, 0.0f, 0.0f, 0.0f ;
cl::Buffer input_buffer(std::begin(input_vector), std::end(input_vector), true);
cl::Buffer output_buffer(std::begin(output_vector), std::end(output_vector), false);
cl::EnqueueArgs enqueue_args(command_queue, cl::NDRange(5));
cl::KernelFunctor<cl::Buffer, cl::Buffer> functor(kernel);
functor(enqueue_args, input_buffer, output_buffer);
for (const auto& value : output_vector)
std::cout << value << ", ";
我希望在运行内核后打印输出向量缓冲区的结果,这应该等于input[n] + n
,但是我只得到了填充输出向量的初始0
s。我已经尝试了很多事情,但到目前为止还没有成功,所以为了清楚起见,我将其缩小了。内核确实构建了,运行它时没有任何错误,只是没有得到我希望的结果。我也看不到任何打印语句输出。
关于进一步的上下文,我的硬件最高支持 openCL 1.2,在 macOS 上运行,并且我已经定义了 openCL 定义以声明我正在使用 openCL 1.2。
谁能看到我在设置代码中做错了什么?
【问题讨论】:
我在使用其他库的计算和图形着色器方面有中等经验,但同样,在为 openCL 处理 C++ 之前熟悉常规 openCL 是否可取?也许我错了,但是用于 openCL 的 C++ 的文档更有限,而没有 【参考方案1】:您的test_kernel
看起来不错。
但在 C++ 方面,您缺少一些东西:
-
在设备上下文中创建缓冲区,以便 OpenCL 知道它应该在哪个设备的内存上分配内存:
const int N = 5;
cl::Buffer input_buffer(context, CL_MEM_READ_WRITE, N*sizeof(float));
cl::Buffer output_buffer(context, CL_MEM_READ_WRITE, N*sizeof(float));
您必须将Buffer
对象链接到Kernel
参数。否则,OpenCL 不知道内存中的哪些缓冲区对应test_kernel
的哪些参数。
kernel.setArg(0, input_buffer);
kernel.setArg(1, output_buffer);
在执行内核之前,需要将input_vector
从CPU内存复制到GPU内存中的input_buffer
:
command_queue.enqueueWriteBuffer(input_buffer, true, 0, N*sizeof(float), (void*)input_vector);
注意:GPU 内存中的output_buffer
保持未初始化,并且可能包含随机值。由于您的test_kernel
将每个条目写入output_buffer
并且不读取output_buffer
的任何条目,因此此处不需要command_queue.enqueueWriteBuffer(output_buffer, ...)
。
执行kernel
:
const int local = 1; // GPU warp size is 32, so this should be 32 or a multiple of 32 to get full performance. For the test with N=5, I have set it to 1.
const int global = ((N+local-1)/local)*local;
cl::NDRange range_local = cl::NDRange(local);
cl::NDRange range_global = cl::NDRange(global);
command_queue.enqueueNDRangeKernel(kernel, cl::NullRange, range_global, range_local);
command_queue.finish();
将 output_buffer
从 GPU 内存复制回 CPU 内存中的 output_vector
:
command_queue.enqueueReadBuffer(output_buffer, true, 0, N*sizeof(float), (void*)output_vector);
注意:enqueueReadBuffer
中的true
使其成为阻塞命令,表示在此行之后队列自动清空,数据传输完成;您不需要在此处添加额外的command_queue.finish();
。
更新的数据现在位于output_vector
的 CPU 内存中,可以在 CPU 上进一步处理或在控制台中打印。
【讨论】:
迟到的回复、圣诞节和分心之类的……但效果很好!非常感谢您的帮助以上是关于如何正确初始化此 C++ for openCL 内核的输入/输出参数?的主要内容,如果未能解决你的问题,请参考以下文章