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