基于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的编程部分,设计到同步问题,计算中间过程的数据交换问题,对这部分没有深入的理解,希望各位多多指教。谢谢!

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