1. ホーム
  2. クーダ

[解決済み】CUDAランタイムAPIを使用してエラーをチェックする標準的な方法は何ですか?

2022-04-01 19:55:34

質問

CUDAの質問に対する回答やコメントに目を通し、また CUDAタグウィキ APIを呼び出すたびに、その戻り値がエラーでないかをチェックすることがよく提案されていますね。APIドキュメントには、以下のような関数があります。 cudaGetLastError , cudaPeekAtLastError および cudaGetErrorString しかし、多くの余分なコードを必要とせずに、確実にエラーをキャッチして報告するために、これらを組み合わせる最良の方法は何でしょうか?

どのように解決するのですか?

実行時APIコードのエラーをチェックするには、おそらく以下のようなアサート形式のハンドラ関数とラッパーマクロを定義するのが最も良い方法です。

#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
   if (code != cudaSuccess) 
   {
      fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
      if (abort) exit(code);
   }
}

そして、それぞれの API 呼び出しを gpuErrchk マクロで、ラップした API 呼び出しの戻り値のステータスを処理する、といった具合です。

gpuErrchk( cudaMalloc(&a_d, size*sizeof(int)) );

呼び出しにエラーがある場合、エラーを説明するテキストメッセージと、エラーが発生したコード内のファイルと行が、次のように出力されます。 stderr で、アプリケーションは終了します。考えられるのは gpuAssert を呼び出すのではなく、例外を発生させるようにします。 exit() が必要な場合、より洗練されたアプリケーションで使用することができます。

関連する2つ目の質問は、標準的なランタイムAPIコールのようにマクロ呼び出しで直接ラップできない、カーネル起動時のエラーをチェックする方法です。カーネルの場合、次のようなものです。

kernel<<<1,1>>>(a);
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaDeviceSynchronize() );

は、まず起動引数が無効かどうかをチェックし、次にカーネルが停止して実行エラーをチェックするまでホストを強制的に待機させます。このように後続のブロック型APIコールがあれば、同期を省くことができる。

kernel<<<1,1>>>(a_d);
gpuErrchk( cudaPeekAtLastError() );
gpuErrchk( cudaMemcpy(a_h, a_d, size * sizeof(int), cudaMemcpyDeviceToHost) );

この場合 cudaMemcpy の呼び出しは、カーネル実行中に発生したエラーまたはメモリコピー自体から発生したエラーのいずれかを返すことができます。これは初心者には分かりにくいので、デバッグ時にカーネル起動後に明示的な同期を行うことで、どこで問題が起きているのかを理解しやすくすることをお勧めします。

を使用する場合は注意が必要です。 CUDA動的並列処理 デバイスカーネルでのCUDAランタイムAPIの使用、およびデバイスカーネルの起動後に、非常に類似した方法を適用することができますし、そうする必要があります。

#include <assert.h>
#define cdpErrchk(ans) { cdpAssert((ans), __FILE__, __LINE__); }
__device__ void cdpAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
   if (code != cudaSuccess)
   {
      printf("GPU kernel assert: %s %s %d\n", cudaGetErrorString(code), file, line);
      if (abort) assert(0);
   }
}