CUDADevices同步并执行顺序工作

CUDADevices同步并执行顺序工作,cuda,Cuda,我有一个程序,在使用nvprof分析后,它说大约98%的执行时间用于cudaDeviceSynchronize。在思考如何优化下面的代码时,我被带到这里来尝试并确认我对cudaDeviceSynchronize需求的理解 因此,我的计划的总体布局如下: Copy input array to GPU. program<<<1,1>>>(inputs) Copy outputs back to host. 将输入数组复制到GPU。 程序(输入) 将输出复制回主

我有一个程序,在使用nvprof分析后,它说大约98%的执行时间用于cudaDeviceSynchronize。在思考如何优化下面的代码时,我被带到这里来尝试并确认我对cudaDeviceSynchronize需求的理解

因此,我的计划的总体布局如下:

Copy input array to GPU.
program<<<1,1>>>(inputs)
Copy outputs back to host.
将输入数组复制到GPU。
程序(输入)
将输出复制回主机。
因此,我的程序内核是一个主线程,基本上如下所示:

for (int i = 0; i < 10000; i++)
{
    calcKs(inputs);
    takeStep(inputs);
}
//Calculate k1's
//Calc fluxes for r = 1->(ml-1), then for r = 0, then calc K's
zeroTemps();
calcFlux<<< numBlocks, numThreads >>>(concs, temp2);        //temp2 calculated from concs
cudaDeviceSynchronize();
calcMonomerFlux(temp2, temp1);                              //temp1 calculated from temp2
cudaDeviceSynchronize();
calcK<<< numBlocks, numThreads >>>(k1s, temp2);             //k1s calculated from temp2
cudaDeviceSynchronize(); 
for(int i=0;i<10000;i++)
{
计算(输入);
步骤(输入);
}
calcKs函数是cudaDeviceSynchronize最严重的滥用者之一,如下所示:

for (int i = 0; i < 10000; i++)
{
    calcKs(inputs);
    takeStep(inputs);
}
//Calculate k1's
//Calc fluxes for r = 1->(ml-1), then for r = 0, then calc K's
zeroTemps();
calcFlux<<< numBlocks, numThreads >>>(concs, temp2);        //temp2 calculated from concs
cudaDeviceSynchronize();
calcMonomerFlux(temp2, temp1);                              //temp1 calculated from temp2
cudaDeviceSynchronize();
calcK<<< numBlocks, numThreads >>>(k1s, temp2);             //k1s calculated from temp2
cudaDeviceSynchronize(); 
//计算k1
//r=1->(ml-1)时的计算通量,r=0时的计算通量,然后是计算K
零温度();
calcFlux>(浓度,温度2)//根据concs计算的temp2
cudaDeviceSynchronize();
钙离子通量(temp2,temp1)//temp1由temp2计算得出
cudaDeviceSynchronize();
计算>(k1s,temp2)//k1由temp2计算得出
cudaDeviceSynchronize();
其中,数组temp2、temp1和k1都是根据彼此的结果计算得出的。我的理解是cudaDeviceSynchronize非常重要,因为我需要在计算temp1之前完全计算temp2,对于temp1和k1也是如此

读了这篇文章,我觉得我严重误解了cudaDeviceSynchronize的功能:。我不确定上面的评论与我的情况有多相关,但是,因为我的所有程序都在设备上运行,并且在最终内存复制回主机之前没有CPU-GPU交互,因此我没有得到由memCpy

CUDA活动(内核调用、memcopies等)引起的隐式序列化发布到同一流

当您在应用程序中根本不使用流时,您所做的一切都是在应用程序中进行的

因此,在您的情况下,以下各项之间没有功能上的区别:

calcFlux<<< numBlocks, numThreads >>>(concs, temp2);        //temp2 calculated from concs
cudaDeviceSynchronize();
calcMonomerFlux(temp2, temp1);                              //temp1 calculated from temp2
几乎所有的时间都花在
cudaDeviceSynchronize()
调用中。内核调用是异步的,这意味着它启动内核,然后立即将控制权返回给主机线程,从而允许主机线程继续。因此,主机线程中内核调用的开销可能低至几微秒。但是
cudaDeviceSynchronize()
调用将阻塞主机线程,直到前面的内核调用完成。内核执行的时间越长,主机线程等待
cudaDeviceSynchronize()
调用的时间就越长。因此,几乎所有的主机线程执行时间都花费在这些调用上

对于正确编写的单线程、单(默认)流CUDA代码,
cudaDeviceSynchronize()
在主机线程中几乎不需要。在某些情况下,它可能对某些类型的调试/错误检查很有用,在您有一个正在执行的内核并且希望在应用程序终止之前看到内核的打印输出(
printf
)的情况下,它可能很有用。

CUDA活动(内核调用、memcopies等)向同一流发出

当您在应用程序中根本不使用流时,您所做的一切都是在应用程序中进行的

因此,在您的情况下,以下各项之间没有功能上的区别:

calcFlux<<< numBlocks, numThreads >>>(concs, temp2);        //temp2 calculated from concs
cudaDeviceSynchronize();
calcMonomerFlux(temp2, temp1);                              //temp1 calculated from temp2
几乎所有的时间都花在
cudaDeviceSynchronize()
调用中。内核调用是异步的,这意味着它启动内核,然后立即将控制权返回给主机线程,从而允许主机线程继续。因此,主机线程中内核调用的开销可能低至几微秒。但是
cudaDeviceSynchronize()
调用将阻塞主机线程,直到前面的内核调用完成。内核执行的时间越长,主机线程等待
cudaDeviceSynchronize()
调用的时间就越长。因此,几乎所有的主机线程执行时间都花费在这些调用上


对于正确编写的单线程、单(默认)流CUDA代码,
cudaDeviceSynchronize()
在主机线程中几乎不需要。在某些情况下,对于某些类型的调试/错误检查,它可能很有用,在您有一个正在执行的内核并且希望在应用程序终止之前看到内核的打印输出(
printf
)的情况下,它可能很有用。

值得补充的是
cudaDeviceSynchronize()
在使用CUDA功能(例如统一内存)时,还需要提供一个指向数据的指针。如果要在设备上进行更改后使用托管指针访问主机上的数据,必须首先同步。这一点很好。统一内存是一个例子,零拷贝内存是另一个例子。事情是这样的,我还不够清楚,这些代码都是在GPU上运行的。我将进行编辑以使其更清晰。是的,在这种情况下,
cudaDeviceSynchronize()
调用可能是必要的。值得补充的是,在使用CUDA功能时,也需要
cudaDeviceSynchronize()
,这些功能为您提供一个指向数据的指针,例如统一内存。如果要在设备上进行更改后使用托管指针访问主机上的数据,必须首先同步。这一点很好。统一内存是一个例子,零拷贝内存是另一个例子。事情是这样的,我还不够清楚,这些代码都是在GPU上运行的。我将进行编辑以使其更清晰。是的,在这种情况下,
cudaDeviceSynchronize()
调用可能是必要的。