CUDA カーネルのタイミングを計るとき、カーネルは実行中に CPU プログラムの実行をブロックしないため、以下は機能しません。
start timer
kernel<<<g,b>>>();
end timer
CUDA カーネルのタイミングを (うまく) 計る 3 つの基本的な方法を見てきました。
(1) 2 つの CUDA eventRecords。
float responseTime; //result will be in milliseconds
cudaEvent_t start; cudaEventCreate(&start); cudaEventRecord(start); cudaEventSynchronize(start);
cudaEvent_t stop; cudaEventCreate(&stop);
kernel<<<g,b>>>();
cudaEventRecord(stop); cudaEventSynchronize(stop);
cudaEventElapsedTime(&responseTime, start, stop); //responseTime = elapsed time
(2) 1 つの CUDA eventRecord。
float start = read_timer(); //helper function on CPU, in milliseconds
cudaEvent_t stop; cudaEventCreate(&stop);
kernel<<<g,b>>>();
cudaEventRecord(stop); cudaEventSynchronize(stop);
float responseTime = read_timer() - start;
(3) eventRecord の代わりに deviceSynchronize。(おそらく、単一のストリームでプログラミングを使用する場合にのみ役立ちます。)
float start = read_timer(); //helper function on CPU, in milliseconds
kernel<<<g,b>>>();
cudaDeviceSynchronize();
float responseTime = read_timer() - start;
これら 3 つの戦略が同じタイミング結果を生成することを実験的に確認しました。
質問:
- これらの戦略のトレードオフは何ですか? ここに隠された詳細はありますか?
- 複数のストリームで多くのカーネルのタイミングを計ること以外に、2 つのイベント レコードと
cudaEventElapsedTime()
関数を使用する利点はありますか?
おそらく想像力を働かせて、何read_timer()
が機能するかを理解できるでしょう。それにもかかわらず、実装例を提供することは害にはなりません:
double read_timer(){
struct timeval start;
gettimeofday( &start, NULL ); //you need to include <sys/time.h>
return (double)((start.tv_sec) + 1.0e-6 * (start.tv_usec))*1000; //milliseconds
}