4

cudaMallocメモリ割り当ては、GPU で最も時間のかかる操作の 1 つであるため、次のコードを使用して 1 回呼び出して 2 つの配列を割り当てたいと考えました。

int numElements = 50000;
size_t size = numElements * sizeof(float);

//declarations-initializations
float *d_M = NULL;
err = cudaMalloc((void **)&d_M, 2*size);
//error checking

// Allocate the device input vector A
float *d_A = d_M;


// Allocate the device input vector B
float *d_B = d_M + size;

err = cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice);
//error checking

err = cudaMemcpy(d_B, h_B, size, cudaMemcpyHostToDevice);
//error checking

元のコードは、cuda ツールキットの vectorAdd.cu という名前のサンプル フォルダー内にあるため、h_A、h_B が適切に開始され、変更を加えなくてもコードが機能すると想定できます。
その結果、2 番目の cudaMemcpy が無効な引数というメッセージでエラーを返しました。

デバイスメモリの動作が異なるため、操作「d_M +サイズ」は誰かが期待するものを返さないようですが、方法はわかりません。

私のアプローチ (cudaMalloc を 1 回呼び出して 2 つの配列にメモリを割り当てる) を機能させることは可能ですか? これが良いアプローチであるかどうかについてのコメント/回答も大歓迎です。

更新Robertdreamcrash
の回答が示唆したように、バイト数であるサイズではなく、要素数(numElements)をポインターd_Mに追加する必要がありました。参考までに、目に見えるスピードアップはありませんでした。

4

1 に答える 1

4

交換するしかない

float *d_B = d_M + size;

float *d_B = d_M + numElements;

これはポインター演算です。float の配列がある場合は、 を実行R = [1.0,1.2,3.3,3.4]して最初の位置を出力できますprintf("%f",*R);。そしてセカンドポジション?あなたはprintf("%f\n",*(++R));こうするだけですr[0] + 1。あなたがしていたように、あなたはしませんr[0] + sizeof(float)。これを行うと、以降r[0] + sizeof(float)の位置にある要素にアクセスします。r[4]size(float) = 4

宣言すると、コンパイラはがメモリに継続的に割り当てられるとfloat *d_B = d_M + numElements;想定し、各要素のサイズは. したがって、距離をバイト単位で指定する必要はなく、要素単位でコンパイラが計算します。このアプローチは、バイト単位よりも要素単位でポインター演算を表現する方が直感的であるため、より人間に優しいものです。さらに、特定の型のバイト数が基礎となるアーキテクチャに基づいて変更された場合、コンパイラがそれを処理するため、移植性も高くなります。したがって、固定バイトサイズを想定しているため、コードが壊れることはありません。d_bfloat


「その結果、2 番目の cudaMemcpy がメッセージの無効な引数でエラーを返した」とあなたは言いました:

このエラーに対応する番号を出力すると、それが出力され11CUDA APIを確認すると、このエラーが以下に対応していることを確認できます。

cudaErrorInvalidValue

これは、API 呼び出しに渡された 1 つ以上のパラメーターが許容範囲内にないことを示しています。

あなたの例では、フロート*d_B = d_M + size;が範囲外になっていることを意味します。

100000フロート用のスペースを割り当てd_a、0 から 50000 まで開始しますが、コードによると50000 * 4 = 200000 d_bから開始しますnumElements * sizeof(float);

于 2012-12-03T15:36:04.363 に答える