何时真正需要调用cudaDeviceSynchronize
函数?
据我从CUDA文档中了解,CUDA内核是异步的,因此我们应该在每次内核启动后调用cudaDeviceSynchronize
。但是,除了时间测量之前的一个,我尝试使用和不使用任何cudaDeviceSynchronize
的相同代码(训练神经网络)。我发现我得到了相同的结果,但速度在7-12x之间(取决于矩阵大小)。
所以,问题是是否有任何理由使用cudaDeviceSynchronize
时间测量。
例如:
在使用cudaMemcpy
将数据从GPU复制回主机之前是否需要?
如果我进行矩阵乘法,如
C = A * B
D = C * F
我应该将cudaDeviceSynchronize
放在两者之间吗?
从我的实验看来我没有。
cudaDeviceSynchronize
为什么这么慢地使程序变慢?
答案 0 :(得分:51)
虽然CUDA内核启动是异步的,但是所有与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 memory is copied, memory copy starts only after kernel2 finishes
因此,在您的示例中,不需要cudaDeviceSynchronize
。但是,调试可能有助于检测哪个内核导致错误(如果有的话)。
cudaDeviceSynchronize
可能会导致一些放缓,但7-12倍似乎太多了。可能存在时间测量方面的问题,或者内核可能非常快,并且显式同步的开销相对于实际计算时间而言是巨大的。
答案 1 :(得分:15)
使用cudaDeviceSynchronize()
的一种情况是,当您运行多个cudaStream
时,您希望让它们交换一些信息。实际情况就是量子蒙特卡罗模拟中的平行回火。在这种情况下,我们希望确保每个流已经完成运行一些指令并在开始向对方传递消息之前得到一些结果,或者我们最终会传递垃圾信息。使用此命令的原因使程序运行速度变慢,cudaDeviceSynchronize()
强制程序在继续之前等待设备上所有流中所有先前发出的命令完成(来自CUDA C编程指南)。正如您所说,内核执行通常是异步的,因此当GPU设备执行您的内核时,CPU可以继续处理其他一些命令,向设备发出更多指令等,而不是等待。但是,当您使用此同步命令时,CPU将被强制为空闲,直到完成所有GPU工作,然后再执行任何其他操作。调试时此行为很有用,因为由于设备代码的异步执行(无论是在一个流还是多个流中),您可能会在看似“随机”的时间内发生段错误。 cudaDeviceSynchronize()
将强制程序确保流的内核/ memcpys在继续之前完成,这样可以更容易地找出非法访问的发生位置(因为在同步过程中会出现故障) )。
答案 2 :(得分:4)
当您希望GPU开始处理某些数据时,通常会进行内核调用。 当你这样做时,你的设备(GPU)将开始做你告诉它做的任何事情。但是,与主机(CPU)上的正常顺序程序不同,将继续执行程序中的下一行代码。 cudaDeviceSynchronize使主机(CPU)等到设备(GPU)完成所有已启动的线程的执行,因此您的程序将继续,就像它是正常的顺序程序一样。
在小型简单程序中,当您使用GPU进行计算时,通常会使用cudaDeviceSynchronize,以避免请求结果的CPU与GPU完成计算之间的时序不匹配。使用cudaDeviceSynchronize可以更轻松地编写程序代码,但有一个主要缺点:CPU一直处于空闲状态,而GPU则进行计算。因此,在高性能计算中,您经常努力让CPU在等待GPU完成时进行计算。