簡體   English   中英

同步多個Cuda流

[英]Synchronising multiple Cuda streams

對於我目前正在開發的應用程序,我希望有一個長內核(即,相對於其他內核需要很長時間才能完成的內核)與一系列同時運行的較短內核同時執行。 然而,更復雜的是,四個較短的內核在完成后需要進行同步,以便執行另一個短內核,該內核收集並處理其他短內核的數據輸出。

以下是我的想法的示意圖,編號的綠色條代表不同的內核:

我想到的原理圖。

為了實現這一點,我編寫了類似於以下內容的代碼:

// definitions of kernels 1-6

class Calc
{
    Calc()
    {
        // ...
        cudaStream_t stream[5];
        for(int i=0; i<5; i++) cudaStreamCreate(&stream[i]);
        // ...
    }

    ~Calc()
    {
        // ...
        for(int i=0; i<5; i++) cudaStreamDestroy(stream[i]);
        // ...
    }

    void compute()
    {
        kernel1<<<32, 32, 0, stream[0]>>>(...);
        for(int i=0; i<20; i++) // this 20 is a constant throughout the program
        {
            kernel2<<<1, 32, 0, stream[1]>>>(...);
            kernel3<<<1, 32, 0, stream[2]>>>(...);
            kernel4<<<1, 32, 0, stream[3]>>>(...);
            kernel5<<<1, 32, 0, stream[4]>>>(...);
            // ?? synchronisation ??
            kernel6<<<1, 32, 0, stream[1]>>>(...);
        }
    }
}

int main()
{
    // preparation

    Calc C;

    // run compute-heavy function as many times as needed
    for(int i=0; i<100; i++)
    {
        C.compute();
    }

    // ...

    return 0;
}

注意:塊,線程和共享內存的數量只是任意數。

現在,我將如何在每次迭代中正確同步內核2-5? 首先,我不知道哪個內核需要花費最長的時間才能完成,因為這可能取決於用戶輸入。 此外,我已經嘗試過使用cudaDeviceSynchronize()cudaStreamSynchronize() ,但是那些超過總執行時間的三倍。

Cuda事件可能是要走的路嗎? 如果是這樣,我該如何應用它們? 如果沒有,那么這樣做的正確方法是什么?

非常感謝你。

首先需要提出兩條評論。

  1. 啟動小內核(一個塊)通常不是從GPU中獲得良好性能的方法。 同樣,每個塊具有少量線程的內核(32)通常會施加占用限制,這將阻止GPU的完全性能。 啟動多個並發內核並不能減輕這種第二個考慮因素。 我不會在這里花費更多的時間,因為你已經說過這些數字是隨意的(但請看下面的下一條評論)。

  2. 目睹實際的內核並發很難。 我們需要內核具有相對較長的執行時間,但對GPU資源的需求相對較低。 <<<32,32>>>內核可能會填充您正在運行的GPU,從而阻止並發內核的塊運行能力。

您的問題似乎歸結為“如何在kernel2-5完成之前阻止kernel6啟動。

可以為此使用事件。 基本上,你會記錄一個事件到每個流的kernel2-5啟動后,你會放一個cudaStreamWaitEvent電話,一個對4個事件, 之前推出的kernel6

像這樣:

        kernel2<<<1, 32, 0, stream[1]>>>(...);
        cudaEventRecord(event1, stream[1]);
        kernel3<<<1, 32, 0, stream[2]>>>(...);
        cudaEventRecord(event2, stream[2]);
        kernel4<<<1, 32, 0, stream[3]>>>(...);
        cudaEventRecord(event3, stream[3]);
        kernel5<<<1, 32, 0, stream[4]>>>(...);
        cudaEventRecord(event4, stream[4]);
        // ?? synchronisation ??
        cudaStreamWaitEvent(stream[1], event1);
        cudaStreamWaitEvent(stream[1], event2);
        cudaStreamWaitEvent(stream[1], event3);
        cudaStreamWaitEvent(stream[1], event4);
        kernel6<<<1, 32, 0, stream[1]>>>(...);

請注意,以上所有調用都是異步的 它們都不需要花費超過幾微秒來處理,並且它們都不會阻止CPU線程繼續運行,這與使用cudaDeviceSynchronize()cudaStreamSynchronize() ,后者通常阻塞CPU線程。

因此,您可能需要在上述序列之后進行某種同步(例如cudaStreamSynchronize(stream[1]); )在循環中執行,否則所有這些的異步性質將會變得毛茸茸( ,基於你的原理圖,似乎你可能不希望迭代i + 1的kernel2-5開始直到迭代i的內核6完成?)注意我已經省略了事件創建和其他可能的樣板,我假設您可以解決這個問題或參考任何使用事件的示例代碼,或參考文檔。

即使你實現了所有這些基礎設施,你見證(或不見)實際內核並發的能力將由你的內核本身決定, 而不是我在這個答案中建議的任何東西。 所以,如果你回來說“我做了那個,但我的內核並沒有同時運行”這實際上是一個與你所提出的問題不同的問題,在這里,我會把你的初學者推薦給我的評論#2。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM