私がデータ構造を持っているとしましょう:
struct MyBigData {
float * dataArray;
float * targetArray;
float * nodes;
float * dataDataData;
}
この構造をさまざまな CUDA カーネルに渡せるようにしたいと考えています。引数として複数の配列を渡す必要がないので、構造体を渡すだけで完了できますか? カーネルが C 構造をサポートしていることは知っていますが、C 構造の動的メモリはどうですか?
CUDAカードに構造を作成するためにこれを行うだけのようです:
MyBigData * mbd = (MyBigData *) cudaMalloc( sizeof(MyBigData) );
しかし、構造内の配列の動的メモリはどうでしょうか? 以下の行はコンパイルされますが、実行時エラーが発生します。
mbd->dataArray = (float *) cudaMalloc( 10 * sizeof(float) );
これは、cudaMalloc() が CPU で実行され、mdb->dataArray を読み取ってポインタを新しいメモリ アドレスと等しく設定できないためです。そのため、実行時エラーが発生します。ただし、これはコンパイルして実行しますが、私が望むものではないようです:
MyBigData * mbd = (MyBigData *) malloc( sizeof(myBigData) );
mbd->dataArray = (float *) cudaMalloc( 10 * sizeof(float) );
これは有効ですが、現在 mbd はメイン システム メモリに存在し、浮動小数点ポインタは CUDA デバイスに割り当てられたメモリを指しているためです。そのため、ポインタを MyBigData 構造に渡すだけではなく、構造内の各変数を個別にカーネルに渡す必要があります。きれいではありません。私が欲しいのは:
someKernel<<<1,1>>>(mbd);
いいえ:
someKernel<<<1,1>>>(mbd->dataArray, mbd->targetArray, mbd->nodes, mbd->dataDataData);
だから私は考えていました、cudaMemcpy() はどうですか? 私はこれを考えていました:
MyBigData *d_mbd = cudaMemcpy( (void*) &d_mbd, (void*) mbd, SOMESIZE, CudaHostToDevice);
しかし、SOMESIZE には何を入れますか? sizeof(MyBigData) は使用できません。これには、配列の実際のサイズではなく、浮動小数点ポインターのサイズが含まれるためです。次に、cudaMemcpy() は、複雑なデータ構造のサブオブジェクトを掘り下げるのに十分なほどスマートですか? ないと思います。
では、CUDA カードに動的メモリを含む構造を持つことは不可能ですか? それとも私は何かを逃していますか。簡単な方法は、CUDA カーネルにメモリを割り当てさせることですが、CUDA カーネルから cudaMalloc() を呼び出すことはできません。
考え?
5 月 7 日更新: このコードを書き、コンパイルしましたが、すべての値がゼロであることがわかりました。オブジェクトを正しく作成し、CUDA カーネルで値を適切に入力していると思います。値は単なるスレッド ID です。値を正しく出力していないと思われます。考え?そしてありがとうございました!
MyBigData* generateData(const int size) {
MyBigData *mbd_host, *mbd_cuda;
mbd_host = (MyBigData *) malloc( sizeof(MyBigData) );
cudaMalloc( (void**) &mbd_host->dataArray, size * sizeof(float) );
cudaMalloc( (void**) &mbd_host->targetArray, size * sizeof(float) );
cudaMalloc( (void**) &mbd_host->nodes, size * sizeof(float) );
cudaMalloc( (void**) &mbd_host->dataDataData, size * sizeof(float) );
cudaMalloc( (void**) &mbd_cuda, sizeof(MyBigData) );
cudaMemcpy( mbd_cuda, mbd_host, sizeof(mbd_host), cudaMemcpyHostToDevice );
free(mbd_host);
return mbd_cuda;
}
void printCudaData(MyBigData* mbd_cuda, const int size) {
MyBigData *mbd;
cudaMemcpy( mbd, mbd_cuda, sizeof(mbd_cuda), cudaMemcpyDeviceToHost);
MyBigData *mbd_host = (MyBigData *) malloc( sizeof(MyBigData));
mbd_host->dataArray = (float*) malloc(size * sizeof(float));
mbd_host->targetArray = (float*) malloc(size * sizeof(float));
mbd_host->nodes = (float*) malloc(size * sizeof(float));
mbd_host->dataDataData = (float*) malloc(size * sizeof(float));
cudaMemcpy( mbd_host->dataArray, mbd->dataArray, size * sizeof(float), cudaMemcpyDeviceToHost);
cudaMemcpy( mbd_host->targetArray, mbd->targetArray, size * sizeof(float), cudaMemcpyDeviceToHost);
cudaMemcpy( mbd_host->nodes, mbd->nodes, size * sizeof(float), cudaMemcpyDeviceToHost);
cudaMemcpy( mbd_host->dataDataData, mbd->dataDataData, size * sizeof(float), cudaMemcpyDeviceToHost);
for(int i = 0; i < size; i++) {
printf("data[%i] = %f\n", i, mbd_host->dataArray[i]);
printf("target[%i] = %f\n", i, mbd_host->targetArray[i]);
printf("nodes[%i] = %f\n", i, mbd_host->nodes[i]);
printf("data2[%i] = %f\n", i, mbd_host->dataDataData[i]);
}
free(mbd_host->dataArray);
free(mbd_host->targetArray);
free(mbd_host->nodes);
free(mbd_host->dataDataData);
free(mbd_host);
}
これは私のカーネルとそれを呼び出す関数です:
__global__ void cudaInitData(MyBigData* mbd) {
const int threadID = threadIdx.x;
mbd->dataArray[threadID] = threadID;
mbd->targetArray[threadID] = threadID;
mbd->nodes[threadID] = threadID;
mbd->dataDataData[threadID] = threadID;
}
void initData(MyBigData* mbd, const int size) {
if (mbd == NULL)
mbd = generateData(size);
cudaInitData<<<size,1>>>(mbd);
}
私のmain()
電話:
MyBigData* mbd = NULL;
initData(mbd, 10);
printCudaData(mbd, 10);