在使用Thrust时,如何在CUDA中计时内核启动时间?

3
CUDA中的内核启动通常是异步的,这意味着一旦启动了CUDA内核,控制立即返回到CPU(据我所知)。 CPU在GPU忙于数值计算时继续执行一些有用的工作,除非使用cudaThreadsynchronize()cudaMemcpy()强制停止CPU。
现在我刚开始使用Thrust库进行CUDA编程。 Thrust中的函数调用是同步还是异步的?
换句话说,如果我调用thrust::sort(D.begin(),D.end());,其中D是设备向量,那么使用何种方式来测量排序时间才有意义?
        start = clock();//Start

             thrust::sort(D.begin(),D.end());

        diff = ( clock() - start ) / (double)CLOCKS_PER_SEC;
        std::cout << "\nDevice Time taken is: " <<diff<<std::endl;

如果函数调用是异步的,那么对于任何向量diff将为0秒(这对于计时来说是无用的),但如果是同步的,我确实会得到真正的性能时间。

1
我对使用clock来计时推力持怀疑态度,因为它的分辨率很差。在过去,它并没有表现出色。你应该使用CUDA事件API代替。 - Jared Hoberock
1个回答

4

Thrust调用启动内核的操作是异步的,就像底层使用的CUDA API Thrust一样。而复制数据的Thrust调用是同步的,就像底层使用的CUDA API Thrust一样。

因此,您的示例仅测量了内核启动和Thrust主机端设置的开销,而不是操作本身。为了计时,在Thrust内核启动后,您可以调用cudaThreadSynchronizecudaDeviceSynchronize(在CUDA 4.0或更高版本中)来解决这个问题。另外,如果您在内核启动后包括一个后续的复制操作并在那之后记录停止时间,则您的计时将包括设置、执行和复制时间。

在您的示例中,这将看起来像:

   start = clock();//Start 

   thrust::sort(D.begin(),D.end()); 
   cudaThreadSynchronize(); // block until kernel is finished

   diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; 
   std::cout << "\nDevice Time taken is: " <<diff<<std::endl; 

2
这并不完全正确,大多数是异步的,但有些不是。http://groups.google.com/group/thrust-users/browse_thread/thread/8fd88a9987cad036 此外,像reduction这样返回值的thrust调用是阻塞的。http://groups.google.com/group/thrust-users/msg/cd7542285070f893 并且cudaHostSynchronize应该改为cudaDeviceSynchronize。 - jmsu
你难道不需要使用事件来计算设备执行时间吗? - erogol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接