使用事件计时CUDA应用程序

Say*_*yan 4 cuda timer

我使用以下两个函数来计算我的代码的不同部分(cudaMemcpyHtoD,内核执行,cudaMemcpyDtoH)(其中包括多个gpus,同一GPU上的并发内核,内核的顺序执行等).据我所知,这些函数会记录事件之间经过的时间,但我想在代码的生命周期中插入事件可能会导致开销和不准确.我想听听批评意见,改善这些功能的一般建议以及对它们的警告.

//Create event and start recording
cudaEvent_t *start_event(int device, cudaEvent_t *events, cudaStream_t streamid=0)
{
        cutilSafeCall( cudaSetDevice(device) );
        cutilSafeCall( cudaEventCreate(&events[0]) );
        cutilSafeCall( cudaEventCreate(&events[1]) );
        cudaEventRecord(events[0], streamid);

    return events;
 }

 //Return elapsed time and destroy events
 float end_event(int device, cudaEvent_t *events, cudaStream_t streamid=0)
 {

        float elapsed = 0.0;
        cutilSafeCall( cudaSetDevice(device) );
        cutilSafeCall( cudaEventRecord(events[1], streamid) );
        cutilSafeCall( cudaEventSynchronize(events[1]) );
        cutilSafeCall( cudaEventElapsedTime(&elapsed, events[0], events[1]) );

        cutilSafeCall( cudaEventDestroy( events[0] ) );
        cutilSafeCall( cudaEventDestroy( events[1] ) );

        return elapsed;
 }
Run Code Online (Sandbox Code Playgroud)

用法:

cudaEvent_t *events;
cudaEvent_t event[2]; //0 for start and 1 for end
...
events = start_event( cuda_device, event, 0 );
<Code to time>
printf("Time taken for the above code... - %f secs\n\n", (end_event(cuda_device, events, 0) / 1000) );
Run Code Online (Sandbox Code Playgroud)

har*_*ism 9

首先,如果这是用于生产代码,您可能希望能够在第二个cudaEventRecord和cudaEventSynchronize()之间执行某些操作.否则,这可能会降低您的应用与GPU和CPU工作重叠的能力.

接下来,我将事件创建和破坏与事件记录分开.我不确定费用,但总的来说你可能不想经常调用cudaEventCreate和cudaEventDestroy.

我要做的是创建一个这样的类

class EventTimer {
public:
  EventTimer() : mStarted(false), mStopped(false) {
    cudaEventCreate(&mStart);
    cudaEventCreate(&mStop);
  }
  ~EventTimer() {
    cudaEventDestroy(mStart);
    cudaEventDestroy(mStop);
  }
  void start(cudaStream_t s = 0) { cudaEventRecord(mStart, s); 
                                   mStarted = true; mStopped = false; }
  void stop(cudaStream_t s = 0)  { assert(mStarted);
                                   cudaEventRecord(mStop, s); 
                                   mStarted = false; mStopped = true; }
  float elapsed() {
    assert(mStopped);
    if (!mStopped) return 0; 
    cudaEventSynchronize(mStop);
    float elapsed = 0;
    cudaEventElapsedTime(&elapsed, mStart, mStop);
    return elapsed;
  }

private:
  bool mStarted, mStopped;
  cudaEvent_t mStart, mStop;
};
Run Code Online (Sandbox Code Playgroud)

注意我没有包含cudaSetDevice() - 在我看来应该留给使用这个类的代码,以使其更灵活.用户必须确保在调用启动和停止时同一设备处于活动状态.

PS:NVIDIA并不打算将CUTIL作为生产代码的依赖 - 它仅仅是为了方便我们的示例而使用,并没有像CUDA库和编译器本身那样经过严格的测试或优化.我建议你把像cutilSafeCall()这样的东西提取到你自己的库和标题中.