2012-07-19 14 views
2

在Nvidia GPU上,當我撥打clEnqueueNDRange時,程序會在繼續之前等待它完成。更確切地說,我打電話給它的等效C++綁定,CommandQueue::enqueueNDRange,但這不應該有所作爲。這隻發生在Nvidia硬件(3 Tesla M2090s)上;在我們配備AMD GPU的辦公室工作站上,呼叫不受阻礙,並立即返回。我沒有本地的Nvidia硬件來測試 - 我們曾經這樣做過,而且我也記得類似的行爲,但它有點朦朧。clEnqueueNDRange在Nvidia硬件上阻塞? (也是多GPU)

這使得難以在多個GPU之間傳播工作。我已經嘗試在新的C++ 11規範中使用std::async/std::finish來啓動一個新線程,以便每次調用enqueueNDRange,但這似乎並不奏效 - 監控nvidia-smi中的GPU使用情況,我可以看到GPU 0上的內存使用量上升,然後它做了一些工作,然後GPU 0上的內存下降,GPU 1上的內存上升,一個做一些工作等等。我的gcc版本是4.7.0。

這裏是我是如何開始的內核,其中增量所需的全球工作的尺寸由設備的數量劃分,四捨五入到所需的地方工作的大小最接近的倍數:

std::vector<cl::CommandQueue> queues; 
/* Population of queues happens somewhere 
cl::NDrange offset, increment, local; 
std::vector<std::future<cl_int>> enqueueReturns; 
int numDevices = queues.size(); 

/* Calculation of increment (local is gotten from the function parameters)*/ 

//Distribute the job among each of the devices in the context 
for(int i = 0; i < numDevices; i++) 
{ 
    //Update the offset for the current device 
    offset = cl::NDRange(i*increment[0], i*increment[1], i*increment[2]); 

    //Start a new thread for each call to enqueueNDRangeKernel 
    enqueueReturns.push_back(std::async(
        std::launch::async, 
        &cl::CommandQueue::enqueueNDRangeKernel, 
        &queues[i], 
        kernels[kernel], 
        offset, 
        increment, 
        local, 
        (const std::vector<cl::Event>*)NULL, 
        (cl::Event*)NULL)); 
    //Without those last two casts, the program won't even compile 
} 
//Wait for all threads to join before returning 
for(int i = 0; i < numDevices; i++) 
{ 
    execError = enqueueReturns[i].get(); 

    if(execError != CL_SUCCESS) 
     std::cerr << "Informative error omitted due to length" << std::endl 
} 

的內核肯定應該在對std::async的調用中運行,因爲我可以創建一個虛擬函數,在GDB上設置一個斷點並在調用std::async時進入它。但是,如果我爲enqueueNDRangeKernel創建一個包裝函數,請在此處運行它,然後在運行後放入一個打印語句,我可以看到在打印之間需要一些時間。

P.S.由於黑客等原因,Nvidia開發區已經關閉,所以我無法在那裏發佈問題。

編輯:忘了提 - 那我傳遞給內核作爲argment(和一個我提到,上面,這似乎讓GPU之間傳遞)被聲明爲使用CL_MEM_COPY_HOST_PTR的緩衝區。我一直在使用CL_READ_WRITE_BUFFER,效果相同。

回答

2

我給Nvidia們發了封電子郵件,實際上得到了相當公平的答覆。有一個在Nvidia的SDK,顯示了樣本,每個設備需要創建單獨的:

  • 隊列 - 所以,你可以代表每個設備和排隊的訂單給它
  • 緩衝區 - 一個緩衝每個陣列都需要傳遞給設備,否則設備將繞過一個緩衝區,等待它變爲可用並有效地將所有內容序列化。
  • kernel - 我認爲這是可選的,但它使得指定參數變得更容易。

此外,你必須爲獨立線程中的每個隊列調用EnqueueNDRangeKernel。這不在SDK示例中,但Nvidia傢伙確認這些通話被阻止。

做完所有這些之後,我在多個GPU上實現了併發。但是,仍然存在一些問題。 On to the next question...

0

是的,你是對的。 AFAIK - nvidia的實現有一個同步的「clEnqueueNDRange」。我在使用我的圖書館(梵天)時也注意到了這一點。我不知道是否有解決方法或防止這種方法,除了使用不同的實現(並因此設備)。

+0

那麼,這是否意味着clEnqueueNDRange只能在任何給定的上下文中一次調用一次?這似乎是這種情況,正如我對'std :: async'的實驗所暗示的那樣。 編輯:或者,而不是一次調用一次,一次執行一個。 – Chaosed0 2012-07-19 14:19:07

+0

從我的實驗來看,是的。每當我想要做更復雜的事時,我都會使用AMD(或Intel)實現。但是,您可以創建兩個上下文,每個上下文都有一個設備,對嗎? – Ani 2012-07-19 14:20:50

+0

井dangit。我的設置的問題是我需要此代碼在多GPU設置上運行,並且我已經訪問的兩個GPU羣集都有Nvidia卡。如果沒有解決方法,那麼我有點死在水裏。在論壇不通的情況下向Nvidia的支持發送電子郵件是否值得? arghedit:是的,我想我可以嘗試單獨的上下文。 – Chaosed0 2012-07-19 14:22:10

相關問題