2016-03-05 148 views
1

我的OpenCL程序並不總是在進一步執行主機(C++)代碼之前完成。 OpenCL代碼只能執行到某個點(它隨機是隨機的)。代碼縮短了一些,所以可能會遺漏一些東西。等內核完成OpenCL

cl::Program::Sources sources; 
string code = ResourceLoader::loadFile(filename); 
sources.push_back({ code.c_str(),code.length() }); 

program = cl::Program(OpenCL::context, sources); 

if (program.build({ OpenCL::default_device }) != CL_SUCCESS) 
{ 
    exit(-1); 
} 
queue = CommandQueue(OpenCL::context, OpenCL::default_device); 
kernel = Kernel(program, "main"); 
Buffer b(OpenCL::context, CL_MEM_READ_WRITE, size); 
queue.enqueueWriteBuffer(b, CL_TRUE, 0, size, arg); 
buffers.push_back(b); 
kernel.setArg(0, this->buffers[0]); 

vector<Event> wait{ Event() }; 

版本1:

queue.enqueueNDRangeKernel(kernel, NDRange(), range, NullRange, NULL, &wait[0]); 

版本2:

queue.enqueueNDRangeKernel(kernel, NDRange(), range, NullRange, &wait, NULL); 

wait[0].wait(); 

queue.finish(); 

版本1只是不等待OpenCL程序。第2版​​崩潰的程序(在queue.enqueueNDRangeKernel):

異常在foo.exe的在0x51D99D09(nvopencl.dll)拋出:0000005:訪問衝突讀取位置0x0000002C。

如何讓主機等待GPU在這裏完成?

編輯:queue.enqueueNDRangeKernel返回-1000。雖然它在一個相當小的內核上返回0

回答

1

當內核完成時,版本1表示信號wait[0] - 這是正確的做法。

版本2要求您的clEnqueueNDRangeKernel()等待wait中的事件,然後再啓動內核[顯然無法工作]。

就它自己而言,queue.finish() [或clFinish()]應該足以確保您的內核已經完成。

由於您沒有完成clCreateUserEvent,並且您沒有將它傳遞給其他任何初始化事件,所以第二個變體不起作用。

這是相當糟糕,它崩潰[它應該返回「無效事件」或一些這樣的 - 但大概你正在使用的驅動程序沒有辦法來檢查事件尚未初始化]。我相當肯定與我合作的驅動程序會爲這種情況發出錯誤 - 但我儘量避免出錯...

我不知道-1000來自哪裏 - 它既不是有效的錯誤代碼,也不是來自CL C++包裝的合理的返回值。無論內核是小型還是大型[和/或在短時間內完成]都不應該影響入隊的返回值,因爲所有應該做的就是排隊工作[不能保證它開始直到queue.flush()或執行clFlush]。等待它完成應該發生在其他地方。

我通過原始OpenCL API來完成大部分工作,而不是C++包裝器,這就是爲什麼我指的是他們所做的,而不是C++包裝器。