对长序列内核和读取进行排队时的内存考虑

  • 本文关键字:排队 内存 内核 读取 opencl
  • 更新时间 :
  • 英文 :


我有一个很长的内核序列,我需要在一些数据上运行,如

data -> kernel1 -> data1 -> kernel2 -> data2 -> kernel3 -> data3 etc.

我还需要将所有中间结果复制回主机,所以这个想法类似于(伪代码):

inputdata = clCreateBuffer(...hostBuffer[0]);
for (int i = 0; i < N; ++i)
{
    // create output buffer
    outputdata = clCreateBuffer(...);
    // run kernel
    kernel = clCreateKernel(...);
    kernel.setArg(0, inputdata);
    kernel.setArg(1, outputdata);
    enqueueNDRangeKernel(kernel);
    // read intermediate result
    enqueueReadBuffer(outputdata, hostBuffer[i]);
    // output of operation becomes input of next
    inputdata = outputdata;
}

有几种方法可以调度这些操作:

    最简单的方法是总是等待上一个队列操作的事件,所以我们在继续下一个内核之前等待一个读操作完成。我可以在不需要缓冲区时立即释放它们。
  • 或者使一切尽可能异步,内核和读队列只等待前一个内核,所以缓冲区读取可以在另一个内核运行时发生。

在第二种(异步)情况下,我有几个问题:

  • 我必须保持引用所有的cl_mem对象在行动的长链和释放它们后,一切都完成?
  • 重要的是,当所有内存对象的总和超过设备上可用的总内存时,OpenCL如何处理这种情况?在任何时候,内核只需要输入和输出内核(应该适合内存),但是如果这些缓冲区中的4或5个超过总数,OpenCL如何在幕后分配/释放这些内存对象?这对读数有什么影响?

如果有人能澄清在这些情况下会发生什么,我会很感激,也许在OpenCL规范中有相关的东西。

谢谢。

你的第二种情况是正确的。

在第二种(异步)情况下,我有几个问题:

Do I have to keep references to all cl_mem objects 
in the long chain of actions and release them after 
everything is complete?

是的。但是,如果所有的数据数组的大小相同,我将只使用2,并在每次迭代中一个接一个地覆盖。然后,您将只需要有2个内存区,并且释放和分配应该只发生在开始/结束。

不要担心数据有坏值,如果您设置了适当的事件,处理将等待I/O完成。即:

data -> kernel1 -> data1 -> kernel2 -> data -> kernel3 -> data1
                -> I/O operation    -> I/O operation
要做到这一点,只需设置一个条件,强制内核3只有在第一个I/O完成时才启动。你可以用这种方式链接所有的事件。

注意:使用两个队列,一个用于I/O,另一个用于处理,将为您带来并行I/O,这是2倍的速度。

重要的是,OpenCL如何处理sum对象上可用的总内存设备?

在分配时给出OUT_OF_RESOURCES或类似错误。

在任何一点,内核只需要输入和输出内核(应该适合内存),但是如果这些缓冲区中有4或5个呢超过总数,OpenCL如何分配/释放这些内存幕后的对象?这对读数有什么影响?

它不会自动执行此操作,除非您已将内存设置为主机PTR。但我不确定OpenCL驱动程序是否会正确处理它。如果我是你,我不会分配超过最大值的。

我的印象是(对不起,我要引用规范,但今天找不到它,所以我降低了我的断言的强度),当你用cl_mem引用队列内核时,它对这些对象进行保留,并在内核完成时释放它们。

这可以允许您在内核队列之后释放这些对象,而不必实际等待内核完成运行。这就是异步"clEnqueue"操作如何与同步操作(即内存释放)协调,并防止运行时和内核使用释放的内存对象。

最新更新