OpenCL中的重叠传输和设备计算

OpenCL中的重叠传输和设备计算,opencl,gpgpu,Opencl,Gpgpu,我是OpenCL的初学者,我很难理解一些东西。 我想改进主机和设备之间的图像传输。 我制定了一个计划来更好地了解我 上图:我现在拥有的;下图:我想要的 HtD(主机到设备)和DtH(设备到主机)是内存传输。 K1和K2是内核 我考虑过使用映射内存,但是第一次传输(主机到设备)是通过clSetKernelArg()命令完成的,不是吗? 或者我必须将输入图像剪切成子图像,然后使用映射来获得输出图像吗 谢谢 编辑:更多信息 K1处理mem输入图像。 K2处理来自K1的输出图像 所以,我想把MemIn

我是OpenCL的初学者,我很难理解一些东西。 我想改进主机和设备之间的图像传输。 我制定了一个计划来更好地了解我

上图:我现在拥有的;下图:我想要的 HtD(主机到设备)和DtH(设备到主机)是内存传输。 K1和K2是内核

我考虑过使用映射内存,但是第一次传输(主机到设备)是通过clSetKernelArg()命令完成的,不是吗? 或者我必须将输入图像剪切成子图像,然后使用映射来获得输出图像吗

谢谢

编辑:更多信息

K1处理mem输入图像。 K2处理来自K1的输出图像

所以,我想把MemInput转换成K1的几个部分。
我想读取K2处理的备忘录并将其保存在主机上。

正如您可能已经看到的,您可以使用
clEnqueueWriteBuffer
和类似工具从主机到设备进行传输

所有包含关键字“enqueue”的命令都有一个特殊属性:这些命令不是直接执行的,而是在阻塞模式下使用
clFinish
clFlush
clEnqueueWaitForEvents
、使用
clEnqueueWriteBuffer
等进行跳转时执行的

这意味着所有操作一次发生,您必须使用事件对象同步它。由于一切(可能)同时发生,您可以这样做(每一点同时发生):

  • 传输数据A
  • 过程数据A和传输数据B
  • 过程数据B和传输数据C以及检索数据A'
  • 过程数据C和检索数据B'
  • 检索数据C'
  • 请记住:在没有事件对象的情况下将任务排队可能会导致同时执行所有排队元素

    为了确保进程数据B在传输B之前不会发生,您必须从
    clEnqueueWriteBuffer
    中检索事件对象,并将其作为对象提供给f.i.
    ClenqueEndRangeKernel

    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 CPU GPU BufA BufB 数组[]={…} clCreateBuffer()------>[]//在GPU内存中创建(空)缓冲区* clCreateBuffer()------>[][]//在GPU内存中创建(空)缓冲区* clWriteBuffer()-arr->[array][//从CPU复制到GPU clCopyBuffer()[array]->[array]//从GPU复制到GPU
    clReadBuffer()创建命令队列时,需要在属性中启用无序执行。请参阅:CL_队列_OUT_OF u ORDER_EXEC_MODE_ENABLE

    这将允许您设置较小的任务链,并将它们相互链接。这一切都是在主机上完成的

    主机伪代码:

    for i in taskChainList
      enqueueWriteDataFromHost
      enqueueKernel(K1)
      enqueueKernel(K2)
      enqueueReadFromDevice
    clfinish
    
    在对任务排队时,将上一个cl_事件放入每个任务的事件等待列表中。我上面的“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
    

    许多OpenCL平台不支持无序命令队列;大多数供应商说,进行重叠DMA和计算的方式是使用多个(按顺序)命令队列。您可以使用事件来确保以正确的顺序完成依赖关系。NVIDIA的示例代码显示了重叠DMA并以这种方式进行计算(虽然这是次优的;它可以比他们所说的稍快一点)。

    正确的方法(正如我所做的,并且工作得很好)是创建两个命令队列,一个用于I/O,另一个用于处理。两者必须在相同的上下文中

    您可以使用事件来控制两个队列的调度,操作将并行执行(如果可以的话)。即使设备不支持outoforderqueue,它也确实可以工作

    例如,您可以将I/O队列中的所有100个映像排队到GPU并获取它们的事件。然后将此事件设置为内核的触发器。DtoH传输由内核事件触发。
    即使您一次将所有这些作业排队,它们也将以并行I/O的顺序进行处理。

    Ok。但我的问题是缓冲区的传输(在我的例子中是2D图像)。例如:在我的主机上,我有一个表示100个元素的数组的缓冲区。但是我想在设备上一次发送10个元素,一旦完成,我同意,我会同步启动我的内核。我希望避免在开始时完全传输缓冲区(请参见方案)。我刚才作为点编写的两个参数可以接收大小数组,一个设置范围,另一个设置要复制的区域的偏移量。我还没有医生,但我想这正是你想要的!;)这样:
    size\u t origin[]={0,0,0},region[]={2,2,1};clEnqueueWriteImage(队列、图像、CL_FALSE、原点、区域、0、0、yourHostData、事件到等待、新事件)
    现在更改原点并再次调用。通过这种方式,您可以传输缓冲区的子集。确保您也适当地偏移指向
    yourHostData
    的指针。(注意:原点和偏移量必须是三维的。
    区域[2]
    必须是
    1
    对于2D imageStack,Exchange会通知我此处看不到的注释。我尝试从收件箱中解释预览;)如果要将数据从主机传输到设备,或从主机传输到设备,您可以使用
    clenqueuwrite…
    clenqueuered…
    。如果要将数据从设备内传输到设备内的另一个位置,请使用
    clenqueecopy…
    抱歉,我不完全理解这一点。我的工作流程:-#-将图像从HDD读取到[integer | char]-数组-#-在GPU上创建缓冲区-#-将数组传输到缓冲区(I