我正在使用pyOpenCL來做一些複雜的計算。 它在CPU上運行良好,但在嘗試在NVIDIA GeForce 9400M(256 MB)上運行時出現錯誤。 我正在使用Mac OS X Lion(10.7.5)在GPU上運行時,如何對同一陣列進行大量分配會導致pyopencl.LogicError?
奇怪的是,這個錯誤並不總是顯示出來。當我的計算使用更大的數字(導致更大的迭代),但只有在GPU上運行時,纔會出現這種情況。
我不寫信給記憶位置我不應該寫信給。通過將代碼作爲單個工作項運行,我排除了可能的問題。
我簡化我的OpenCL代碼儘可能,並從所剩下創造了一些非常簡單的代碼,用引起pyopencl.LogicError
極其怪異的行爲。它由2個嵌套循環組成,其中對result
陣列進行了一些賦值。這個賦值甚至不需要依賴於循環的狀態。 這在GPU上的單個線程(或工作項目,shape = (1,)
)上運行。
__kernel void weirdError(__global unsigned int* result){
unsigned int outer = (1<<30)-1;
for(int i=20; i--;){
unsigned int inner = 0;
while(inner != outer){
result[0] = 1248;
result[1] = 1337;
inner++;
}
outer++;
}
}
奇怪的部分是,刪除結果數組中的任何一個賦值都會消除該錯誤。另外,減小外部的初始值(例如降低到(1<<20)-1
)也會消除該錯誤。在這些情況下,代碼將正常返回,並在相應的緩衝區中提供正確的結果。 在CPU上,它永遠不會引發錯誤。
OpenCL代碼是使用PyOpenCL從Python運行的。
沒有在設置的想象力吧
platform = cl.get_platforms()[0]
device = platform.get_devices(cl.device_type.GPU)[0]
context = cl.Context([device])
program = cl.Program(context, getProgramCode()).build()
queue = cl.CommandQueue(context)
在此Python代碼我設置result_buf
到0
,然後我在運行的OpenCL計算,將在大迭代設置它的值。後來我試圖收集從設備存儲器此值,但是這就是它出了問題:
result = numpy.zeros(2, numpy.uint32)
result_buf = cl.Buffer(context, mem_flags.READ_WRITE | mem_flags.COPY_HOST_PTR, hostbuf=result)
shape = (1,)
program.weirdError(queue, shape, None, result_buf)
cl.enqueue_copy(queue, result, result_buf)
最後一行給我:
pyopencl.LogicError: clEnqueueReadBuffer failed: invalid command queue
這怎麼能重複分配會導致錯誤?
更重要的是:如何避免它?
據我所知,這個問題很可能是與平臺相關的,因而可能難以重現。但這是我唯一可以訪問的機器,所以代碼應該在這臺機器上運行。
免責聲明:我以前從未與OpenCL(或CUDA)合作過。我在GPU不支持OpenCL的機器上編寫代碼。我總是在CPU上測試它。現在,我切換到GPU,我發現令人沮喪的是,錯誤不會一致發生,我不知道爲什麼。
的'CL_INVALID_COMMAND_QUEUE'錯誤通常表示以前執行的內核導致某種異常。通常這會像讀或寫內存一樣,不應該是這樣的(例如,超過數組的末尾)。沒有看到你的內核代碼,我們很難說出爲什麼會發生這種情況。 – jprice
這樣做更有意義,是的。在我的情況下,在cl.enqueue_copy(queue,result,result_buf)之前是'amf'內核還是內核? – neXus
如果您正在運行多個內核,則可以在每次調用內核後放置一個'queue.finish()'。你看到的錯誤應該在導致問題的內核之後立即移到'finish()'調用。這應該只是暫時的改變來調試問題 - 每次內核調用後清除隊列都會給你帶來性能上的衝擊。 – jprice