我使用以下两个函数来计算我的代码的不同部分(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)
首先,如果这是用于生产代码,您可能希望能够在第二个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()这样的东西提取到你自己的库和标题中.