我尝试测量CUDA内核函数花费的时间。我同时测量它的CPU和GPU时序。但是两者之间却有很大的不同。
当我使用NVIDIA分析器对其进行分析时,内核大约需要6毫秒,这正是我想要的。但是,当我在内核调用周围使用gettimeofday()来获取CPU计时时,该度量为15ms。我那里也没有任何memcpy电话。内核在单独的流中运行。并且类似的内核正在并发流中运行。
示例代码:
gettimeofday(start);
cudaEventRecord(startGPU);
Kernel <<<abc, xyz,stream>>>();
cudaDeviceSynchronize();
cudaEventRecord(stopGPU);
printf("Elapsed GPU time = ");
gettimeofday(stop);
printf("Elapsed CPU time = ");
我得到上面代码的结果:
经过的GPU时间= 6毫秒 经过的CPU时间= 15毫秒
这很奇怪,因为仅存在内核执行行。但是,内核参数是指针。记忆副本是否要占用额外的时间?但是我也没有在配置文件中的任何地方找到内存副本。任何线索将不胜感激。
答案 0 :(得分:3)
基本上,您所测量的CPU时间就是它花费的时间
另外,请注意,您的CPU时间测量方法不仅会测量您的进程/线程所花费的处理时间,而且还会计算总的系统时间(这可能包括您在使用过程中其他进程/线程所花费的处理时间)。进程/线程甚至不一定在运行)。我必须承认,即使如此,您报告的CPU时间仍然比我通常期望的要大得多。但是我不确定上面是否确实有整个代码。实际上,考虑到printf()
并没有真正打印出任何内容,我对此表示怀疑。因此,可能还有一些我们不知道的其他因素,您仍需要考虑这些因素以充分说明您的时间安排。
无论如何,很可能您进行的两次测量都没有实际测量您真正想要测量的东西。如果您对运行内核所需的时间感兴趣,请使用CUDA事件。但是,如果先同步然后才记录结束事件,则开始事件和结束事件之间的时间将是内核执行开始,等待内核执行完成的CPU之间的时间,以及之后可能花费的时间。记录下第二个事件,然后让那个事件进入GPU,这样您就可以在什么时候询问GPU。想一想标记之类的事件,这些事件标记了发送到GPU的命令流中的特定点。您最有可能实际上想写这个:
cudaEventRecord(startGPU, stream); // mark start of kernel execution
Kernel<<<abc, xyz, stream>>>();
cudaEventRecord(stopGPU, stream); // mark end of kernel execution
cudaEventSynchronize(stopGPU); // wait for results to be available
,然后使用cudaEventElapsedTime()
获取两个事件之间的时间。
还请注意,gettimeofday()
是not necessarily的一种获得高分辨率时序的可靠方法。在C ++中,您可以使用std::steady_clock
或std::high_resolution_clock
(仅在无法避免的情况下我才求助于后者,因为不能保证其稳定;请确保时钟稳定周期实际上足以满足您要测量的条件。
答案 1 :(得分:-1)
调试完相同的问题后,我发现cuda通常在第一次启动内核之前需要时间,如论坛中所述:https://devtalk.nvidia.com/default/topic/1042733/extremely-slow-cuda-api-calls-/?offset=3。
内核之前的cuda运行时API具有6ms的cudaMalloc和14ms的cudaLaunch,这是造成额外延迟的原因。但是,随后的内核可以正常工作。 cudaLaunch耗时通常以毫秒为单位,因此,如果超出该时间,则肯定需要修复。
注意::如果您在while(1)循环(仅运行一次)中运行任何cuda内核,则必须在循环外进行分配。否则,您将最终像这样延迟。