2014-05-02 79 views
4

我正在寫一個基於CUDA的程序,需要定期從GPU轉移一組項目到主機內存之間的統一存儲。爲了使進程保持異步,我希望使用cuda的UMA在主機內存中有一個內存緩衝區和標誌(因此GPU和CPU都可以訪問它)。 GPU將確保標誌清晰,將其項目添加到緩衝區並設置標誌。 CPU等待該標誌被設置,將其從緩衝區中複製出來並清除該標誌。據我所知,這不會產生任何競爭條件,因爲它會迫使GPU和CPU輪流,總是讀寫相對的標誌。Cuda的GPU和主機

到目前爲止,我還沒有能夠得到這個工作,因爲那裏似乎是某種形式的競爭條件。我想出了也有類似的問題,一個簡單的例子:

#include <stdio.h> 

__global__ 
void uva_counting_test(int n, int *h_i); 

int main() { 
    int *h_i; 
    int n; 

    cudaMallocHost(&h_i, sizeof(int)); 

    *h_i = 0; 
    n = 2; 

    uva_counting_test<<<1, 1>>>(n, h_i); 

    //even numbers 
    for(int i = 1; i <= n; ++i) { 
     //wait for a change to odd from gpu 
     while(*h_i == (2*(i - 1))); 

     printf("host h_i: %d\n", *h_i); 
     *h_i = 2*i; 
    } 

    return 0; 
} 

__global__ 
void uva_counting_test(int n, int *h_i) { 
    //odd numbers 
    for(int i = 0; i < n; ++i) { 
     //wait for a change to even from host 
     while(*h_i == (2*(i - 1) + 1)); 

     *h_i = 2*i + 1; 
    } 
} 

對於我來說,這種情況下總是從CPU(host h_i: 1)第一個print語句後掛起。真正不尋常的事情(這可能是一個線索)是我可以在cuda-gdb中使用它。如果我在cuda-gdb中運行它,它將像以前一樣掛起。如果我按ctrl + C,它會將我帶到內核中的while()循環行。從那裏,令人驚訝的是,我可以告訴它繼續下去,它會結束。對於n> 2,它將在每個內核之後再次凍結在內核的while()循環中,但我可以繼續使用Ctrl + C繼續前進,並繼續。

如果有一個更好的方式來完成我想要做的,這也將是有益的。

+1

代碼中的任何內容都不保證緩存一致性。沒有某種記憶柵欄,這種方法是行不通的。而是考慮每次啓動一個內核,與統一內存訪問相比,這相當便宜。 –

+0

您的示例代碼不起作用,因爲在內核執行期間不能保證PCI-e總線上的內存一致性。這個遊戲的基本規則是不要嘗試和設計任何類型的執行模型,這些執行模式除了GPU和主機設備之間明確的主機驅動程序級別同步以外。 – talonmies

+1

您未使用[Unified Memory。](http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#um-unified-memory-programming-hd)。您正在使用零拷貝主機內存。如果你只是想看看有效的計數測試,看看[這裏](http://stackoverflow.com/questions/20345702/how-can-i-check-the-progress-of-matrix-multiplication/20381924 #20381924)。除了關於您的方法的所有其他評論之外,*今天的*統一內存實現並不旨在爲主機和當前正在執行的內核提供對內存區域的同時連貫訪問。 –

回答

4

你所描述生產者 - 消費者模型,其中GPU正在產生一些數據,從時間到時間的CPU會消耗數據。

實現這個最簡單的方法是讓CPU成爲主。 CPU在GPU上啓動一個內核,當它準備好準備好使用數據時(例如在您的示例中爲while循環),它與GPU同步,從GPU複製數據,再次啓動內核以生成更多數據,並執行與它所複製的數據有關的任何操作。這可以讓GPU在CPU處理之前的批處理時填充固定大小的緩衝區(因爲有兩個副本,一個在GPU上,另一個在CPU上)。

,可以在由雙緩衝中的數據,這意味着可以通過乒乓保持GPU忙產生數據的時間的100%緩衝液之間作爲你的其他複製到CPU加以改進。假設複製速度比製作速度快,但如果不是這樣,那麼您將使複製帶寬飽和,這也是很好的。

這些都不是你實際描述的。你所要求的是讓GPU掌握數據。由於您需要仔細管理您的緩衝區大小,因此我需要謹慎對待,因此您需要仔細考慮計時和通信問題。在你研究這個方向之前,你應該閱讀關於內存隔離,原子操作和volatile的內容。

+0

我喜歡你的答案,並試圖在成功時自己實現生產者 - 消費者模型(第2段)。我想知道你能否給出一個例子,或者指出一個例子,說明如何在第3段中描述雙緩衝。謝謝。 – goryh

2

我會嘗試添加

__threadfence_system(); 

*h_i = 2*i + 1; 

here瞭解詳情。沒有它,修改完全可能會永久保留在GPU緩存中。然而,你最好聽聽其他答案:爲了改進它的多線程/塊,你必須處理其他「問題」,以獲得類似的方案可靠工作。如Tom建議(+1),最好使用雙緩衝。流可以幫助你制定很多這樣的計劃,你可以找到here