同時実行が期待される CUDA カーネルでシリアライゼーションの問題に遭遇しました。カーネルの実行を追跡するためのマーカーとして cudaEvents を使用しています。
複数のストリームを持つ同時実行カーネルでの私の実験では、それぞれのストリームでイベントを使用すると、同時実行カーネルがシリアル化されることがわかりました。
以下のコードは、この問題を示しています。以下にリストされている同時カーネル実行機能を持つ 2 つの異なるデバイスでこれをテストしました。
- Tesla C2070、ドライバー バージョン 4.10、ランタイム バージョン 4.10、CUDA 機能 2.0
- Tesla M2090、ドライバー バージョン 4.10、ランタイム バージョン 4.10、CUDA 機能 2.0
USE_EVENTS マクロを変更することにより、イベントを使用してプログラムを実行したり、イベントを使用せずにプログラムを実行したりできます。同時実行とシリアル実行による違いを確認できます。
#include<cuda.h>
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#define CUDA_SAFE_CALL( call) do { \
cudaError_t err = call; \
if( cudaSuccess != err) { \
fprintf(stderr, "Cuda error in call at file '%s' in line %i : %s.\n", \
__FILE__, __LINE__, cudaGetErrorString( err) ); \
exit(-1); \
} } while (0)
// Device code
__global__ void VecAdd(uint64_t len)
{
volatile int a;
for(uint64_t n = 0 ; n < len ; n ++)
a++;
return ;
}
#define USE_EVENTS
int
main(int argc, char *argv[])
{
cudaStream_t stream[2];
for(int i = 0 ; i < 2 ; i++)
CUDA_SAFE_CALL(cudaStreamCreate(&stream[i]));
#ifdef USE_EVENTS
cudaEvent_t e[4];
CUDA_SAFE_CALL(cudaEventCreate(&e[0]));
CUDA_SAFE_CALL(cudaEventCreate(&e[1]));
CUDA_SAFE_CALL(cudaEventRecord(e[0],stream[0]));
#endif
VecAdd<<<1, 32, 0, stream[0]>>>(0xfffffff);
#ifdef USE_EVENTS
CUDA_SAFE_CALL(cudaEventRecord(e[1],stream[0]));
#endif
#ifdef USE_EVENTS
CUDA_SAFE_CALL(cudaEventCreate(&e[2]));
CUDA_SAFE_CALL(cudaEventCreate(&e[3]));
CUDA_SAFE_CALL(cudaEventRecord(e[2],stream[1]));
#endif
VecAdd<<<1, 32, 0, stream[1]>>>(0xfffffff);
#ifdef USE_EVENTS
CUDA_SAFE_CALL(cudaEventRecord(e[3],stream[1]));
#endif
CUDA_SAFE_CALL(cudaDeviceSynchronize());
for(int i = 0 ; i < 2 ; i++)
CUDA_SAFE_CALL(cudaStreamDestroy(stream[i]));
return 0;
}
これが発生する理由と、このシリアライゼーションを回避する方法についての提案は役に立ちます。