如何正确初始化此 C++ for openCL 内核的 input/output 参数?
How do I properly initialise the input/output arguments for this C++ for openCL kernel?
这是我第一次编写 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 上 运行ning,并且我已经定义了 openCL 定义以声明我正在专门使用 openCL 1.2。
谁能看出我在设置代码中做错了什么?
你的 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));
- 您必须 link
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 内存复制回 output_vector
在 CPU 内存中:
command_queue.enqueueReadBuffer(output_buffer, true, 0, N*sizeof(float), (void*)output_vector);
注意:enqueueReadBuffer
中的true
是一个阻塞命令,意思是这行之后队列自动清空,数据传输完成;这里不需要额外的 command_queue.finish();
。
- 更新后的数据现在在
output_vector
的 CPU 内存中,可以在 CPU 上进一步处理或在控制台中打印。
这是我第一次编写 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 上 运行ning,并且我已经定义了 openCL 定义以声明我正在专门使用 openCL 1.2。
谁能看出我在设置代码中做错了什么?
你的 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));
- 您必须 link
Buffer
对象到Kernel
参数。否则,OpenCL 不知道内存中的哪些缓冲区对应于test_kernel
的哪些参数。kernel.setArg(0, input_buffer); kernel.setArg(1, output_buffer);
- 在执行内核之前,您需要将
input_vector
从 CPU 内存复制到 GPU 内存中的input_buffer
:
注意:GPU 内存中的command_queue.enqueueWriteBuffer(input_buffer, true, 0, N*sizeof(float), (void*)input_vector);
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 内存复制回output_vector
在 CPU 内存中:
注意:command_queue.enqueueReadBuffer(output_buffer, true, 0, N*sizeof(float), (void*)output_vector);
enqueueReadBuffer
中的true
是一个阻塞命令,意思是这行之后队列自动清空,数据传输完成;这里不需要额外的command_queue.finish();
。 - 更新后的数据现在在
output_vector
的 CPU 内存中,可以在 CPU 上进一步处理或在控制台中打印。