C ++ OpenCL:当缓冲区超出范围时,子缓冲区会发生什么?

时间:2019-05-21 19:32:00

标签: c++ opencl

关于OpenCL的C ++包装程序如何处理内存释放,我还找不到清晰的信息;任何指向此类引用的指针都将很棒。

我现在的特殊问题是,如果缓冲区超出了相应子缓冲区的范围,会发生什么?说,在这种情况下:

cl::Buffer *buf=new cl::Buffer;
*buf=cl::Buffer(context, CL_MEM_READ_WRITE, 1000);
cl_buffer_region reg={20, 50};
cl::Buffer sub=buf->createSubBuffer(CL_MEM_READ_WRITE, CL_BUFFER_CREATE_TYPE_REGION, &reg);
delete buf;

分配的设备内存是否被释放,而buf指向无效的内存地址,还是程序等待sub也被销毁?

1 个答案:

答案 0 :(得分:2)

用于OpenCL的C ++包装器使用由本地OpenCL API提供的引用计数(请参阅clRetainMemObjectclReleaseMemObject作为参考)来跟踪每个缓冲区。将它们视为已实现的这样的东西可能是准确的:

class cl::Buffer {
    cl_mem buffer;
public:
    Buffer(/*...*/) { buffer = clCreateBuffer(/*...*/);} //Implicit Retain
    Buffer(Buffer const& o) {buffer = o.buffer; clRetainMemObject(buffer);}
    ~Buffer() {clReleaseMemObject(buffer);}

    /*...*/
};

这对于子缓冲区也成立:它们使用与主缓冲区相同的内部引用计数机制({clCreateSubBuffer被声明为implicitly call retain on the object产生缓冲区),因此它将被引用计数为很好,只要拥有的对象仍然存在,并且保持对原始缓冲区对象的引用,它就仍然有效。

此代码可能会有所帮助:

cl::Buffer do_stuff() {
    cl::Buffer buffer{context, CL_MEM_READ_WRITE, 1000};
    std::cout << "Ref Count: " << buffer.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
    //Should print "Ref Count: 1" to console

    cl::Buffer copy = buffer; //retain
    std::cout << "Ref Count: " << buffer.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
    //Should print "Ref Count: 2"
    std::cout << "Ref Count: " << copy.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
    //Should print "Ref Count: 2"

    cl_buffer_region reg={20, 50};
    cl::Buffer sub = buffer.createSubBuffer(CL_MEM_READ_WRITE, CL_BUFFER_CREATE_TYPE_REGION, &reg); //retain
    std::cout << "Ref Count: " << buffer.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
    //Should print "Ref Count: 3"
    std::cout << "Ref Count: " << sub.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
    //I believe it prints "Ref Count: 1", but if it inherits the main buffer's reference count,
    //then it'll print "Ref Count: 3" instead. Not sure what the actual specification is

    return sub;
    //release buffer
    //release copy
}

void outer_code() {
    cl::Buffer subBuffer = do_stuff();
    //Should print "Ref Count: 1", "Ref Count: 2", "Ref Count: 2", "Ref Count: 3", "Ref Count: 1", in order
    std::cout << "Ref Count: " << subBuffer.getInfo<CL_MEM_REFERENCE_COUNT>() << std::endl;
    //Should print "Ref Count: 1"

    //End of scope: release subBuffer
}

我们还可以确认,使用保留/释放语义,直到子缓冲区也被删除之前,原始缓冲区将不会被删除,因为规范这样说:

  

memobj参考计数变为零并且命令排队等待在   使用memobj的命令队列已完成,存储对象被删除。 如果memobj是一个缓冲区对象,则在删除与memobj关联的所有子缓冲区对象之前,无法删除memobj使用此功能来释放不是由引用获得的引用。创建对象或调用clRetainMemObject会导致未定义的行为

     

clReleaseMemObject ,OpenCL 2.0规范,pg. 156

因此,在正确实现C ++ OpenCL包装器的假设下,可以肯定地说,在删除原始缓冲区对象的所有者之后,子缓冲区将继续存在,因为将使用keep /删除原始缓冲区释放语义,并一直保持到删除子缓冲区为止。