2014-07-15 31 views
1

我正在使用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_buf0,然後我在運行的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,我發現令人沮喪的是,錯誤不會一致發生,我不知道爲什麼。

+3

的'CL_INVALID_COMMAND_QUEUE'錯誤通常表示以前執行的內核導致某種​​異常。通常這會像讀或寫內存一樣,不應該是這樣的(例如,超過數組的末尾)。沒有看到你的內核代碼,我們很難說出爲什麼會發生這種情況。 – jprice

+0

這樣做更有意義,是的。在我的情況下,在cl.enqueue_copy(queue,result,result_buf)之前是'amf'內核還是內核? – neXus

+2

如果您正在運行多個內核,則可以在每次調用內核後放置一個'queue.finish()'。你看到的錯誤應該在導致問題的內核之後立即移到'finish()'調用。這應該只是暫時的改變來調試問題 - 每次內核調用後清除隊列都會給你帶來性能上的衝擊。 – jprice

回答

0

在Windows和Linux中,此超時問題可能是固定爲,但顯然不是在Mac中。


的Windows

This answer to a similar question (explaining the symptoms in Windows)將告訴正在發生的事情,以及如何解決它:

這是一個已知的 「功能」 在Windows下(不知道的Linux) - 如果視頻驅動程序停止響應,操作系統將重置它。除此之外,由於OpenCL(和CUDA)是由驅動程序實現的,所以花費太長時間的內核看起來就像是一個凍結的驅動程序。有一個看門狗定時器跟蹤這個(我相信5秒鐘)。

的選項有:

  1. 你需要確保你的內核是不是太費時 (最好的)。
  2. 您可以關閉看門狗定時器:Timeout Detection and Recovery of GPUs
  3. 您可以在沒有連接到顯示器的GPU上運行內核。

我建議你用1

This answer解釋瞭如何真正做到(2)在Windows 7不過對於這些註冊表項的MSDN頁提到,他們不應該受到任何操縱去目標測試或調試以外的應用程序所以它可能不是最好的選擇,但它是一個選項。


的Linux

(從Cuda的發佈說明,但也適用於的OpenCL)

GPU的沒有附加的顯示不受5秒的運行時間限制。出於這個原因,建議CUDA在未連接到X顯示器的GPU上運行。

雖然爲了使用CUDA而不需要運行X,但爲了正確加載NVIDIA內核模塊,X必須在引導後至少初始化一次。即使在X關閉之後,NVIDIA內核模塊仍保持加載狀態,從而允許CUDA繼續運行。


的Mac

蘋果顯然不允許這種看門狗擺弄,因此唯一的選擇似乎是使用第二GPU(沒有連接到它的屏幕)

1

我的建議是避免在內核中出現如此長的循環。工作項目的迭代次數超過10億次,這是一個很長的過程。驅動程序可能會殺死你的內核,因爲它需要花費太多時間來執行。將迭代次數減少到最大量,這不會導致錯誤並查看執行時間。如果需要秒數 - 這太多了。如你所說,減少迭代次數解決了這個問題,這就是我認爲的證據。減少分配操作的次數也會使內核運行得更快,因爲IO操作通常是最慢的。

由於顯而易見的原因,CPU不會遇到這樣的困難。

相關問題