1

コードの 2 つのスニペットについて考えてみましょう。

Snippet1

cudaStream_t stream1, stream2 ;
cudaStreamCreate(&stream1);
cudaStreamCreate(&stream2);
cudaMemcpyAsync( dst, src, size, dir, stream1 );
kernel<<<grid, block, 0, stream2>>>(...);



Snippet2
cudaStreamCreate(&stream1);
cudaStreamCreate(&stream2);
cudaMemcpy( dst, src, size, dir, stream1 );
kernel<<<grid, block, 0, stream2>>>(...);

両方のスニペットで memcpy 呼び出しを発行しています (snippet1 非同期および snippet2 同期)

コマンドは 2 つの異なるストリームに対して発行されているため、私の理解では、両方のケースで重複する可能性があります。

しかし、Snippet2 では cudaMemcpy 呼び出しが同期的 (つまりブロッキング) であるため、cudaMemcpy とカーネル呼び出しが次々に実行されるという逆説的な結論に至ります。

結論として正しいのはどれか。

よりコンパクトに言い換えると、ストリームに cudaMemcpy 呼び出しを発行すると、「コード全体」がブロックされますか、それとも発行先のストリームがブロックされるだけですか?

4

2 に答える 2

3

同期呼び出しは、操作が完了するまで制御を CPU に戻さないため、memcpy が完了するまで、2 番目のスニペットはカーネル起動の送信を開始しません。

あなたのcudaMemcpy()呼び出しは間違っているようです。「Async」で終わらない memcpy のバリアントにストリーム パラメータを指定することはできないと思います。書かれているように、コンパイラはコードを受け入れ、ストリームを memcpy 方向として受け取る可能性があります。

于 2012-08-16T21:15:25.380 に答える
1

ArcheaSoftware は部分的に正しいです。実際、同期呼び出しは、操作が完了するまで制御を CPU に返しません。cudaMemcpyその意味で、カーネルの起動は、呼び出しが返された後にのみ発生します。cudaMemcpyただし、バッファーの種類によっては、呼び出しによって転送されたデータをカーネルが使用できる場合と使用できない場合があります。以下にいくつかの例を示します。

例 1:

cudaMallocHost(&src, size);
cudaMalloc(&dst, size);
cudaMemcpy(dst, src, size, cudaMemcpyHostToDevice);
kernel<<<grid, block, 0, stream2>>>(...);

この場合、カーネルは からsrcにコピーされたデータを使用できますdst

例 2:

src = malloc(size);
cudaMalloc(&dst, size);
cudaMemcpy(dst, src, size, cudaMemcpyHostToDevice);
kernel<<<grid, block, 0, stream2>>>(...);

この場合、cudaMemcpyデータが実際にデバイスに転送される前に戻る可能性があります。

cudaMemcpy登録されていないホスト バッファー (バッファーなど)からの呼び出しは、呼び出しが戻る前に、データがソース バッファーから、おそらく中間ステージング バッファーにコピーされるmallocことのみを保証します。これは驚くべき動作ですが、NVIDIA CUDA ドキュメントではそのように定義されています。参照: https://docs.nvidia.com/cuda/cuda-runtime-api/api-sync-behavior.html#api-sync-behavior

一般に、このような動作のため、登録されていないホスト バッファーの使用は避けることをお勧めします。

于 2020-04-07T09:39:04.780 に答える