何时调用cudaDeviceSynchronize?
什么时候调用到cudaDeviceSynchronize
函数真的需要?
据我所知,从CUDA文档中,CUDA内核是asynchronous的,所以在每次内核启动后,我们应该调用cudaDeviceSynchronize
。 但是,我已经尝试了使用和不使用cudaDeviceSynchronize
的相同的代码(训练neural network),除了时间测量之前的一个。 我发现我得到了相同的结果,但加速度在7-12倍之间(取决于matrix大小)。
所以,问题是如果有任何理由使用cudaDeviceSynchronize
分开计时。
例如:
-
使用
cudaMemcpy
将数据从GPU复制回主机之前是否需要? -
如果我做像matrix乘法
C = A * B D = C * F
我应该把cudaDeviceSynchronize
之间的cudaDeviceSynchronize
?
从我的实验看来,我没有。
为什么cudaDeviceSynchronize
太慢了呢?
虽然CUDA内核启动是asynchronous的,但所有与GPU相关的任务(默认行为)都是按顺序执行的。
所以,例如,
kernel1<<<X,Y>>>(...); // kernel start execution, CPU continues to next statement kernel2<<<X,Y>>>(...); // kernel is placed in queue and will start after kernel1 finishes, CPU continues to next statement cudaMemcpy(...); // CPU blocks until ememory is copied, memory copy starts only after kernel2 finishes
所以在你的例子中,不需要cudaDeviceSynchronize
。 但是,debugging可能会发现哪个内核导致错误(如果有)。
cudaDeviceSynchronize
可能会导致一些放缓,但7-12x似乎太多了。 可能在时间测量上存在一些问题,或者可能是内核真的很快,并且显式同步的开销相对于实际计算时间是巨大的。
一种情况是使用cudaDeviceSynchronize()
是合适的,当你有几个cudaStream
运行,你想让他们交换一些信息。 一个真实的例子是在量子蒙特卡洛模拟中的平行回火。 在这种情况下,我们希望确保每个stream都已经完成了一些指令的运行,并在开始向对方传递消息之前得到了一些结果,否则我们最终会传递垃圾信息。 使用这个命令的原因是程序cudaDeviceSynchronize()
了, cudaDeviceSynchronize()
强制程序在继续之前(从CUDA C编程指南)等待设备上所有stream中的所有先前发出的命令完成。 正如你所说的,内核执行通常是asynchronous的,所以当GPU设备执行你的内核时,CPU可以继续执行一些其他的命令,向设备发出更多的指令等,而不是等待。 但是,当你使用这个同步命令时,CPU必须空闲,直到所有GPU工作完成,然后再做其他事情。 这种行为在debugging时很有用,因为由于设备代码的asynchronous执行(无论是在一个stream还是多个stream中),您可能会在看似“随机”的时间发生段错误。 cudaDeviceSynchronize()
将强制程序在继续之前确保stream的内核/ memcpys已完成,这可以更容易地找出非法访问发生的位置(因为在同步过程中会出现故障)。
当您希望GPU开始处理某些数据时,通常会进行内核调用。 当你这样做的时候,你的设备(GPU)会开始做你所说的任何事情。 但是,与主机上的正常顺序程序不同(CPU)将继续执行程序中的下一行代码。 cudaDeviceSynchronize使主机(CPU)等待设备(GPU)完成执行所有已经启动的线程,因此程序将继续,就像它是一个正常的顺序程序一样。
在小型的简单程序中,当使用GPU进行计算时,通常会使用cudaDeviceSynchronize,以避免请求结果的CPU与GPU完成计算之间的时序不匹配。 使用cudaDeviceSynchronize可以使你的程序编写起来更加容易,但是有一个主要的缺点:在GPU进行计算时,CPU一直处于空闲状态。 因此,在高性能计算中,您经常努力让您的CPU在等待GPU完成时进行计算。