cudaDeviceSynchronize
関数の呼び出しが本当に必要なのはいつですか。
CUDAのドキュメントから理解する限り、CUDAカーネルは非同期であるため、カーネルを起動するたびにcudaDeviceSynchronize
を呼び出す必要があるようです。ただし、時間測定の前を除いて、cudaDeviceSynchronize
の有無にかかわらず、同じコード(トレーニングニューラルネットワーク)を試しました。同じ結果が得られることがわかりましたが、速度は7〜12倍(マトリックスサイズによって異なります)です。
したがって、問題は、時間測定にcudaDeviceSynchronize
を使用する理由があるかどうかです。
例えば:
cudaMemcpy
を使用してGPUからホストにデータをコピーする前に必要ですか?
のような行列乗算を行う場合
C = A * B
D = C * F
cudaDeviceSynchronize
を両方の間に配置する必要がありますか?
私の実験から、そうではないようです。
cudaDeviceSynchronize
がプログラムをそれほど遅くするのはなぜですか?
CUDAカーネルの起動は非同期ですが、1つのストリームに配置されたすべてのGPU関連タスク(これはデフォルトの動作です)は順番に実行されます。
たとえば、
kernel1<<<X,Y>>>(...); // kernel start execution, CPU continues to next statement
kernel2<<<X,Y>>>(...); // kernel is placed in queue and will start after kernel1 finishes, CPU continues to next statement
cudaMemcpy(...); // CPU blocks until memory is copied, memory copy starts only after kernel2 finishes
したがって、あなたの例では、cudaDeviceSynchronize
は必要ありません。ただし、デバッグの際には、どのカーネルがエラーを引き起こしたか(もしあれば)を検出するのに役立ちます。
cudaDeviceSynchronize
は多少の減速を引き起こす可能性がありますが、7〜12倍は多すぎるようです。時間測定に問題があるか、カーネルが非常に高速で、明示的な同期のオーバーヘッドが実際の計算時間に比べて非常に大きい場合があります。
cudaDeviceSynchronize()
の使用が適切な状況の1つは、複数のcudaStream
sを実行していて、それらに何らかの情報を交換させたい場合です。これの実際のケースは、量子モンテカルロシミュレーションの並列焼戻しです。この場合、すべてのストリームが一連の命令の実行を終了し、相互にメッセージの受け渡しを開始する前に結果を取得するか、ガベージ情報を渡すことになります。このコマンドを使用するとプログラムが非常に遅くなるのは、cudaDeviceSynchronize()
がプログラムを、デバイス上のすべてのストリームで以前に発行されたすべてのコマンドが完了するまで待機してから続行するためです(CUDA Cプログラミングガイドから)。前述のように、カーネルの実行は通常非同期であるため、GPUデバイスがカーネルを実行している間、CPUは待機する代わりに、他のコマンドの処理を続けたり、デバイスにさらに命令を発行したりできます。ただし、この同期コマンドを使用すると、GPUのすべての作業が完了してから他の操作を行うまで、CPUは代わりにアイドル状態になります。この動作は、デバイスコードの非同期実行(1つまたは複数のストリーム)のために一見「ランダム」な時間にセグメンテーション違反が発生する可能性があるため、デバッグ時に役立ちます。 cudaDeviceSynchronize()
は、続行する前にストリームのカーネル/ memcpysが完全であることをプログラムに強制します。これにより、不正アクセスが発生している場所を見つけやすくなります(失敗が表示されるため同期)。
GPUで一部のデータの処理を開始するには、通常、カーネル呼び出しを実行します。そうすると、デバイス(GPU)は、指示されたとおりに実行を開始します。ただし、ホスト上の通常の順次プログラム(CPU)とは異なり、プログラム内の次のコード行は引き続き実行されます。 cudaDeviceSynchronizeは、デバイス(GPU)が開始したすべてのスレッドの実行を完了するまでホスト(CPU)を待機させ、プログラムは通常のシーケンシャルプログラムであるかのように続行します。
小さな単純なプログラムでは、通常、GPUを使用して計算を行うときにcudaDeviceSynchronizeを使用して、結果を要求するCPUと計算を仕上げるGPUの間のタイミングの不一致を回避します。 cudaDeviceSynchronizeを使用すると、プログラムのコーディングが簡単になりますが、1つの大きな欠点があります。GPUが計算を実行している間、CPUは常にアイドル状態です。したがって、高性能コンピューティングでは、GPUが終了するのを待っている間にCPUが計算を行うように努力することがよくあります。