yohhoyの日記

技術的メモをしていきたい日記

CUDA同期メモリ転送関数 != 同期動作

CUDAメモリ転送系関数の Async サフィックス有無*1と、実際の同期(synchronous)/非同期(asynchronous)動作は1:1対応しない。Asyncサフィックス無しメモリ転送関数でも、実際には非同期動作となる可能性がある

API synchronization behavior
The API provides memcpy/memset functions in both synchronous and asynchronous forms, the latter having an "Async" suffix. This is a misnomer as each function may exhibit synchronous or asynchronous behavior depending on the arguments passed to the function.

https://docs.nvidia.com/cuda/cuda-runtime-api/api-sync-behavior.html

シングルスレッド処理のホストかつ単一デバイス利用という単純構成では、特に意識しなくとも問題にはならない(たぶん)。一方、ホスト側がマルチスレッド処理であったり、複数GPU間でのデバイス間メモリ転送を行う場合には、非同期動作には十分留意する必要がある。罠すぎる(#^ω^)

後者環境では、CUDAストリーム(cudaStream_tCUstream)とAsyncサフィックス付き関数を組み合わせ、明示的な同期関数(cudaStreamSynchronizecuStreamSynchronize)呼び出しによってメモリ転送完了を待機する。*2

Memcpy
In the reference documentation, each memcpy function is categorized as synchronous or asynchronous, corresponding to the definitions below.

Synchronous

  1. All transfers involving Unified Memory regions are fully synchronous with respect to the host.
  2. For transfers from pageable host memory to device memory, a stream sync is performed before the copy is initiated. The function will return once the pageable buffer has been copied to the staging memory for DMA transfer to device memory, but the DMA to final destination may not have completed.
  3. For transfers from pinned host memory to device memory, the function is synchronous with respect to the host.
  4. For transfers from device to either pageable or pinned host memory, the function returns only once the copy has completed.
  5. For transfers from device memory to device memory, no host-side synchronization is performed.
  6. For transfers from any host memory to any host memory, the function is fully synchronous with respect to the host.

Asynchronous

  1. For transfers from device memory to pageable host memory, the function will return only once the copy has completed.
  2. For transfers from any host memory to any host memory, the function is fully synchronous with respect to the host.
  3. For all other transfers, the function is fully asynchronous. If pageable memory must first be staged to pinned memory, this will be handled asynchronously with a worker thread.
https://docs.nvidia.com/cuda/cuda-runtime-api/api-sync-behavior.html

関連URL

*1:例:CUDA Runtime API の cudaMemcpy と cudaMemcpyAsync、CUDA Driver API の cuMemcpy と cuMemcpyAsync など。

*2:厳密には、転送元/先メモリ区分に応じて同期/非同期動作が決定する。現実的には細かいルールを覚えて慎重にコーデイングするより、最初からCUDAストリーム×Asyncサフィックス付き関数を使うのがベターと思う。