基於CUDA的多GPU編程中計算同步問題請教與探討

程序說明:本程序使用兩塊GPU進行並行計算,程序的核心計算分配四個kenel function進行計算,每個kernel都需要上一個kernel的輸出數據作爲該kernel的輸入數據。但是在中間計算過程中,需要將兩塊GPU的計算結果輸出到主機,主機對這個兩個結果進行加和,然後再傳遞給兩塊GPU繼續進行計算(此步驟也可以將0號GPU的計算結果傳遞給1號GPU,由1號GPU完成兩個中間結果的運算,然後將計算結果傳遞給0號GPU,後續兩塊GPU再繼續後續的運算)。

簡要程序code:

void function(int numGpus, TGPUPara* gpupara)   //TGPUPara 是自己定義的在多GPU中運算的參數
{
    for(int i = 0; i < 12; i++)
    {
        for(int g = 0; g < numGpus; g++)
        {
            CHECK(cudaSetDevice(i));
            dim3 Block(192);
            dim3 Grid_A((ThreadNumA + Block.x - 1) / Block.x);
            dim3 Grid_B((ThreadNumB + Block.x - 1) / Block.x);
            CHECK(cudaMemsetAsync(d_updataData, 0, SIZEV, gpuPara[i].stream));

            for(int j = i; j < 264; j += 12)
            {
                CHECK(cudaMemsetAsync(d_dataA, 0, SIZEL, gpuPara[i].stream));
                CHECK(cudaMemsetAsync(d_dataB, 0, SIZEL, gpuPara[i].stream));

                kernelA<<<Block, Grid_A, 0, gpuPara[i].stream>>>(gpuPara[i].d_dataA, paraA, gpuPara[i].d_dataB);
                kernelB<<<Block, Grid_B, 0, gpuPara[i].stream>>>(gpuPara[i].d_dataB, gpuPara[i].d_dataC);
                kernelC<<<Block, Grid_B, 0, gpuPara[i].stream>>>(gpuPara[i].d_dataC, gpuPara[i].d_dataD);
                kernelA<<<Block, Grid_B, 0, gpuPara[i].stream>>>(gpuPara[i].d_dataD, paraB, gpuPara[i].d_dataE);
            }
            kernelD<<<Block, Grid_A, 0, gpuPara[i].stream>>>(i, gpuPara[i].d_dataE, gpuPara[i].d_dataA);
            CHECK(cudaGetLastError());

            //-----------------------------------------------------------------------------------------------------------------------
            //兩塊GPU將中間數據傳遞給主機
            CHECK(cudaDeviceSynchronize());
            CHECK(cudaMemcpyAsync(gpuPara[i].d_dataA, gpuPara[i].h_dataA, N * sizeof(float), cudaMemcpyDeviceToHost, gpuPara[i].stream));    //使用哪個
            for(int k = 0; k < N; k++)
            {
                gpuPara[i].h_data[k] +=  gpuPara[i].h_dataA[k];
            }

            CHECK(cudaDeviceSynchronize());
            CHECK(cudaMemcpyAsync(gpuPara[i].h_data, gpuPara[i].d_dataA, N * sizeof(float), cudaMemcpyHostToDevice, gpuPara[i].stream));
            //-----------------------------------------------------------------------------------------------------------------------
            //中間數據由0號GPU傳遞給1號GPU
            CHECK(cudaDeviceSynchronize());
            cudaSetDevice(1);
            CHECK(cudaMemcpyAsync(gpuPara[1].d_data, gpuPara[0].d_dataA, N * sizeof(float), cudaMemcpyDeviceToDevice, gpuPara[0].stream));
            kernelE<<<Block, Grid_B, 0, gpuPara[1].stream>>>(gpuPara[1].d_data, gpuPara[1].d_dataA);
            CHECK(cudaMemcpyAsync(gpuPara[0].d_dataA, gpuPara[1].d_dataA, N * sizeof(float), cudaMemcpyDeviceToDevice, gpuPara[0].stream));
            //-----------------------------------------------------------------------------------------------------------------------
        }
    }

    return;
}

問題說明:因爲幾個kernel的時間都是在for(int g = 0; g < numGpus; g++);  當每塊GPU計算完kernelD function時,如果在此使用cudaDeviceSynchronize();同步函數,會不會直接阻塞該循環,導致0 號GPU計算完成後 1 號GPU纔可以進行計算。這樣就達不到使用多塊GPU計算的目的了;但是如果不使用同步,程序的邏輯就不對了。     ?????

使用cudaDeviceSynchronize();正確嗎,或者是使用cudaStreamSynchronize();

在傳遞數據方面使用cudaMemcpyAsync(); 還是使用cudaMemcpy();

因爲在這一步的核心計算方面數據在0 號GPU和1號GPU之間的傳遞都只發生在一片GPU上,是不是應該通過cudaSetDevice(); 設定數據是由哪塊GPU進行傳遞,由哪塊GPU進行計算;

 

這是小編第一次接觸多GPU的編程部分,設計到同步問題,計算中間過程的數據交換問題,對這部分沒有深入的理解,希望各位多多指教。謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章