排除长序列内核和读取时的内存注意事项

时间:2013-01-16 04:13:38

标签: 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规范中有相关内容。

谢谢。

2 个答案:

答案 0 :(得分:1)

你的第二个案例是要走的路。

  

在第二个(异步)案例中,我有几个问题:

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个内存区域,释放和分配只应该发生在beggining / end。

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

data -> kernel1 -> data1 -> kernel2 -> data -> kernel3 -> data1
                -> I/O operation    -> I/O operation

为此,只需设置一个强制kernel3仅在第一个I / O完成时启动的条件。你可以用这种方式链接所有事件。

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

  

重要的是,OpenCL如何处理这种情况   所有内存对象的数量超过了可用的总内存数   设备?

分配时

给出错误OUT_OF_RESOURCES或类似错误。

  

内核只需要输入和输出内核   (应该适合内存),但如果有4个或5个这样的缓冲区怎么办?   超过总数,OpenCL如何分配/释放这些内存   幕后的物品?这对读取有何影响?

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

答案 1 :(得分:1)

我的印象很糟糕(抱歉,我要引用规范,但今天无法找到它,所以我降低了我的断言的强度),当你用cl_mem引用排队内核时,它需要保留那些对象,并在内核完成后释放它们。

这可以允许您在引入内核后释放这些对象,而不必等待内核完成运行。这就是异步“clEnqueue”操作与同步操作(即内存释放)协调的方式,并防止运行时和内核使用已释放的内存对象。