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

C++ OpenCL: what happens to a subbuffer when a buffer goes out of scope?

本文关键字:缓冲区 什么情况 范围 OpenCL C++      更新时间:2023-10-16

我一直找不到关于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 也被销毁?

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声明在生成缓冲区的对象上隐式调用 keep),因此它也将被引用计数,并且只要拥有对象仍然存在,并且保持对原始缓冲区对象的引用。

此代码可能会有所帮助:

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,OpenCL2.0 规范,第 156 页

因此,假设 C++ OpenCL 包装器已正确实现,那么可以肯定地说,在您删除原始缓冲区对象的所有者后,子缓冲区将保留,因为将使用保留/释放语义删除原始缓冲区,从而一直保持到子缓冲区被删除。

相关文章: