我使用以下两个函数来计算我的代码的不同部分(cudaMemcpyHtoD,内核执行,cudaMemcpyDtoH)(包括同一GPU上的multi-gpus,并发内核,内核的顺序执行等)。据我所知,这些函数会记录事件之间经过的时间,但我想在代码的生命周期中插入事件可能会导致开销和不准确。我想听听批评意见,改善这些功能的一般建议以及对他们的警告。
//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;
}
用法:
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) );
答案 0 :(得分: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;
};
注意我没有包含cudaSetDevice() - 在我看来应该留给使用这个类的代码,以使其更灵活。用户必须确保在调用启动和停止时同一设备处于活动状态。
PS:NVIDIA并不打算将CUTIL作为生产代码的依赖 - 它仅仅是为了方便我们的示例而使用,并没有像CUDA库和编译器本身那样经过严格测试或优化。我建议你把像cutilSafeCall()这样的东西提取到你自己的库和标题中。