C ++ OpenCL: что происходит с суббуфером, когда буфер выходит из области видимости? - PullRequest
2 голосов
/ 21 мая 2019

Я не смог найти четкого источника о том, как освобождение памяти обрабатывается оболочкой 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;

Освобождается ли выделенная память устройства, оставляя буферизацию, указывающую на недопустимый адрес памяти, или программа ожидает, пока подпрограмма также будет уничтожена?

1 Ответ

2 голосов
/ 21 мая 2019

Оболочки C ++ для OpenCL используют подсчет ссылок, предоставляемый собственным API OpenCL (см. clRetainMemObject и clReleaseMemObject для отслеживания каждого буфера). Возможно, было бы правильно думать о них, как о том, что они реализованы примерно так:

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 неявно указывает на вызов retain для объекта , создающего буфер), поэтому он будет быть также подсчитанным по ссылке и оставаться действительным до тех пор, пока остается владелец объекта, удерживая ссылку и на исходный буферный объект.

Этот код может помочь:

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, стр. 156

Таким образом, в предположении, что C ++ OpenCL Wrapper реализован правильно, тогда можно с уверенностью сказать, что подпуфер сохранится после того, как вы удалили владельца для исходного объекта буфера, потому что оригинал будет удален с помощью команды retain / Освободить семантику и, таким образом, поддерживать до тех пор, пока не будет удален суббуфер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...