程序說明:本程序使用兩塊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的編程部分,設計到同步問題,計算中間過程的數據交換問題,對這部分沒有深入的理解,希望各位多多指教。謝謝!