在 OpenCL 1.2 中的内核之间传递变量/内核之间的通信
Passing variables between kernels in OpenCL 1.2 / Communication between kernels
我对 OpenCL 比较陌生。我正在使用 OpenCL 1.2 C++ 包装器。假设我遇到以下问题:我在主机上声明了三个整数值 a、b 和 c
int a = 1;
int b = 2;
int c = 3;
int help;
int d;
d 是我的结果,help 是一个帮助变量。
我想计算 d = (a + b)*c。为此,我现在有两个内核,分别称为 'add' 和 'multiply'。
目前,我正在按照以下方式执行此操作(请不要被我面向指针的编程方式所混淆):首先,我创建缓冲区
bufferA = new cl::Buffer(*context, CL_MEM_READ_ONLY, buffer_length);
cl::Buffer bufferB = new cl::Buffer(*context, CL_MEM_READ_ONLY, buffer_length);
bufferC = new cl::Buffer(*context, CL_MEM_READ_ONLY, buffer_length);
bufferHelp = new cl::Buffer(*context, CL_MEM_READ_WRITE, buffer_length);
bufferD = new cl::Buffer(*context, CL_MEM_WRITE_ONLY, buffer_length);
然后,我为添加内核设置内核参数
add->setArg(0, *bufferA);
add->setArg(1, *bufferB);
add->setArg(2, *bufferHelp);
以及乘法内核
multiply->setArg(0, *bufferC);
multiply->setArg(1, *bufferHelp);
multiply->setArg(2, *bufferD);
然后我将我的数据加入队列
queueAdd->enqueueWriteBuffer(*bufferA, CL_TRUE, 0, datasize, &a);
queueAdd->enqueueWriteBuffer(*bufferB, CL_TRUE, 0, datasize, &b);
queueAdd->enqueueNDRangeKernel(*add, cl::NullRange, global[0], local[0]);
queueAdd->enqueueReadBuffer(*bufferHelp, CL_TRUE, 0, datasize, &help);
和乘法
queueMult->enqueueWriteBuffer(*bufferC, CL_TRUE, 0, datasize, &c);
queueMult->enqueueWriteBuffer(*bufferHelp, CL_TRUE, 0, datasize, &help);
queueMult->enqueueNDRangeKernel(*multiply, cl::NullRange, global[0], local[0]);
queueMult->enqueueReadBuffer(*bufferD, CL_TRUE, 0, datasize, &d);
这很好用。但是,我不想将 help 的值复制回主机,然后再复制回设备。为此,我想到了3种可能:
- 设备端帮助的全局变量。这样做,两个内核都可以随时访问 help 的值。
- 内核添加在运行时调用内核乘法。然后我们将 c 的值插入加法内核,并在加法完成后立即将 help 和 c 传递给乘法内核。
- 只需将帮助的值传递给乘法内核即可。我在这里搜索的是类似于 OpenCL 2.0 可用的管道对象。有人知道 OpenCL 1.2 的类似内容吗?
如果有人能提出最流畅的方法来解决我的问题,我将不胜感激!
提前致谢!
不需要读写bufferHelp
。只需将其留在设备内存中即可。您提出的解决方案的数量 1)
已经是 cl::Buffers
,设备内存中的全局变量。
这等同于您的代码并会产生相同的结果:
queueAdd->enqueueWriteBuffer(*bufferA, CL_FALSE, 0, datasize, &a);
queueAdd->enqueueWriteBuffer(*bufferB, CL_FALSE, 0, datasize, &b);
queueAdd->enqueueNDRangeKernel(*add, cl::NullRange, global[0], local[0]);
//queueAdd->enqueueReadBuffer(*bufferHelp, CL_FALSE, 0, datasize, &help);
queueMult->enqueueWriteBuffer(*bufferC, CL_FALSE, 0, datasize, &c);
//queueMult->enqueueWriteBuffer(*bufferHelp, CL_FALSE, 0, datasize, &help);
queueMult->enqueueNDRangeKernel(*multiply, cl::NullRange, global[0], local[0]);
queueMult->enqueueReadBuffer(*bufferD, CL_TRUE, 0, datasize, &d);
注意:我还更改了阻塞写入调用,这将提供更好的速度,因为缓冲区 C 的副本和内核 "add" 的执行可以并行化。
我对 OpenCL 比较陌生。我正在使用 OpenCL 1.2 C++ 包装器。假设我遇到以下问题:我在主机上声明了三个整数值 a、b 和 c
int a = 1;
int b = 2;
int c = 3;
int help;
int d;
d 是我的结果,help 是一个帮助变量。
我想计算 d = (a + b)*c。为此,我现在有两个内核,分别称为 'add' 和 'multiply'。
目前,我正在按照以下方式执行此操作(请不要被我面向指针的编程方式所混淆):首先,我创建缓冲区
bufferA = new cl::Buffer(*context, CL_MEM_READ_ONLY, buffer_length);
cl::Buffer bufferB = new cl::Buffer(*context, CL_MEM_READ_ONLY, buffer_length);
bufferC = new cl::Buffer(*context, CL_MEM_READ_ONLY, buffer_length);
bufferHelp = new cl::Buffer(*context, CL_MEM_READ_WRITE, buffer_length);
bufferD = new cl::Buffer(*context, CL_MEM_WRITE_ONLY, buffer_length);
然后,我为添加内核设置内核参数
add->setArg(0, *bufferA);
add->setArg(1, *bufferB);
add->setArg(2, *bufferHelp);
以及乘法内核
multiply->setArg(0, *bufferC);
multiply->setArg(1, *bufferHelp);
multiply->setArg(2, *bufferD);
然后我将我的数据加入队列
queueAdd->enqueueWriteBuffer(*bufferA, CL_TRUE, 0, datasize, &a);
queueAdd->enqueueWriteBuffer(*bufferB, CL_TRUE, 0, datasize, &b);
queueAdd->enqueueNDRangeKernel(*add, cl::NullRange, global[0], local[0]);
queueAdd->enqueueReadBuffer(*bufferHelp, CL_TRUE, 0, datasize, &help);
和乘法
queueMult->enqueueWriteBuffer(*bufferC, CL_TRUE, 0, datasize, &c);
queueMult->enqueueWriteBuffer(*bufferHelp, CL_TRUE, 0, datasize, &help);
queueMult->enqueueNDRangeKernel(*multiply, cl::NullRange, global[0], local[0]);
queueMult->enqueueReadBuffer(*bufferD, CL_TRUE, 0, datasize, &d);
这很好用。但是,我不想将 help 的值复制回主机,然后再复制回设备。为此,我想到了3种可能:
- 设备端帮助的全局变量。这样做,两个内核都可以随时访问 help 的值。
- 内核添加在运行时调用内核乘法。然后我们将 c 的值插入加法内核,并在加法完成后立即将 help 和 c 传递给乘法内核。
- 只需将帮助的值传递给乘法内核即可。我在这里搜索的是类似于 OpenCL 2.0 可用的管道对象。有人知道 OpenCL 1.2 的类似内容吗?
如果有人能提出最流畅的方法来解决我的问题,我将不胜感激!
提前致谢!
不需要读写bufferHelp
。只需将其留在设备内存中即可。您提出的解决方案的数量 1)
已经是 cl::Buffers
,设备内存中的全局变量。
这等同于您的代码并会产生相同的结果:
queueAdd->enqueueWriteBuffer(*bufferA, CL_FALSE, 0, datasize, &a);
queueAdd->enqueueWriteBuffer(*bufferB, CL_FALSE, 0, datasize, &b);
queueAdd->enqueueNDRangeKernel(*add, cl::NullRange, global[0], local[0]);
//queueAdd->enqueueReadBuffer(*bufferHelp, CL_FALSE, 0, datasize, &help);
queueMult->enqueueWriteBuffer(*bufferC, CL_FALSE, 0, datasize, &c);
//queueMult->enqueueWriteBuffer(*bufferHelp, CL_FALSE, 0, datasize, &help);
queueMult->enqueueNDRangeKernel(*multiply, cl::NullRange, global[0], local[0]);
queueMult->enqueueReadBuffer(*bufferD, CL_TRUE, 0, datasize, &d);
注意:我还更改了阻塞写入调用,这将提供更好的速度,因为缓冲区 C 的副本和内核 "add" 的执行可以并行化。