我与OpenCL的初学者,我有困难的明白了什么。 我想提高图像的主机和设备之间的传输。 我做了一个方案,以更好地了解我。
上图:我现在已经| 下图:我想HTD(主机到设备)和DTH(设备到主机)的存储器传输。 K1和K2是内核。
我想过用映射内存,而是先传送(主机到设备)与clSetKernelArg()命令来完成,不是吗? 还是我必须把我的输入图像为子图像,并使用映射来获得输出图像?
谢谢。
编辑:更多信息
K1过程MEM输入图像。 从K1 K2处理输出图像。
所以,我想MemInput转移成数块的K1。 我想读取并保存主机MemOuput由K2处理上。
正如你可能已经看到了,你用从主机转移到设备clEnqueueWriteBuffer
和类似。
具有他们的关键字是“排队”的所有命令有一个特殊的属性:命令是不能直接执行,但是当你跳跳虎他们使用clFinish
, clFlush
, clEnqueueWaitForEvents
,使用clEnqueueWriteBuffer
阻塞模式和多一些。
这意味着所有的动作发生一次,你必须使用事件对象进行同步。 因为一切都(可以)在发生一次,你可以做这样的事情(每个点发生在同一时间):
- 传送数据
- 过程数据A&传输数据乙
- 过程数据B&传输数据C&Retrive数据A”
- 过程数据C&检索数据B”
- 检索数据C”
记住:入列任务没有事件的对象可能导致所有排队元素的同时执行!
为了确保处理数据B不转让B之前发生,你必须检索事件对象clEnqueueWriteBuffer
并提供其作为一个对象来等待到FI clEnqueueNDRangeKernel
cl_event evt;
clEnqueueWriteBuffer(... , bufferB , ... , ... , ... , bufferBdata , NULL , NULL , &evt);
clEnqueueNDRangeKernel(... , kernelB , ... , ... , ... , ... , 1 , &evt, NULL);
取而代之的供应NULL,每条命令可以对某些对象的过程中等待,并生成一个新的事件对象。 倒数第二个参数是一个数组,这样你就可以将事件等待几个事件!
编辑:总结如下
传送数据的评论-什么命令的作用在哪里?
CPU GPU
BufA BufB
array[] = {...}
clCreateBuffer() -----> [ ] //Create (empty) Buffer in GPU memory *
clCreateBuffer() -----> [ ] [ ] //Create (empty) Buffer in GPU memory *
clWriteBuffer() -arr-> [array] [ ] //Copy from CPU to GPU
clCopyBuffer() [array] -> [array] //Copy from GPU to GPU
clReadBuffer() <-arr- [array] [array] //Copy from GPU to CPU
*您可以通过使用提供数据直接初始化缓冲host_ptr
参数。
许多的OpenCL平台不支持乱序指令队列; 大多数供应商说做重叠DMA和计算的方法是使用多个(按顺序)命令队列。 您可以使用事件来确保依赖关系的正确顺序进行。 NVIDIA具有示例代码,显示重叠DMA和计算做这种方式(虽然它是最理想的,它可以比他们说,能更快小幅)。
当你创建你的命令队列,您需要启用乱序执行你的属性。 见:CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, clCreateCommandQueue 。
这将让你设置的任务的小型连锁店,并将其链接到对方。 这是在主机上的所有完成。
主持人伪代码:
for i in taskChainList
enqueueWriteDataFromHost
enqueueKernel(K1)
enqueueKernel(K2)
enqueueReadFromDevice
clfinish
当你排队的任务,把以前的cl_event到每个任务的event_wait_list。 该“enqueueWriteDataFromHost”我有上面就不必等待另一个事件开始。
交替,
cl_event prevWriteEvent;
cl_event newWriteEvent;
for i in taskChainList
enqueueWriteDataFromHost // pass *prevWriteEvent as the event_wait_list, and update with newWriteEvent that the enqueue function produces. Now each Write will wait on the one before it.
enqueueKernel(K1)
enqueueKernel(K2)
enqueueReadFromDevice //The reads shouldn't come back out of order, but they could (if the last block of processing were much faster then the 2nd-last for example)
clfinish
正确的方法(如我做,没有很好地工作)是创建2个命令队列,一个用于I / O,另一个用于处理。 双方必须在同样的背景下。
您可以使用事件来控制两个队列的调度和操作将并行执行(如果他们能)。 即使设备不支持outoforderqueue它确实工作。
例如,你可以排队所有的I / O队列到GPU的100张图像,并得到他们的活动。 然后设置该事件为触发内核。 而DtoH转移是由内核事件触发。 即使你入队所有这一切工作一次,他们将为了与并行I / O处理。