0

私がデータ構造を持っているとしましょう:

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);
4

1 に答える 1

2

第二に、cudaMemcpy() は複雑なデータ構造のサブオブジェクトを掘り下げるのに十分スマートですか? ないと思います。

そうです、cudaMemcpy()再帰的なコピーを作成しません。目的を達成するには、次のようにする必要があります。

// Create mbd on host
MyBigData *mbd_host, *mbd;
mbd_host = (MyBigData *) malloc( sizeof(myBigData) );
// Fill it with pointers to device arrays
cudaMalloc( &mbd_host->dataArray, 10 * sizeof(float) );
// etc for other structure fields
// Create mbd on device
cudaMalloc( &mbd, sizeof(MyBigData) );
// Copy structure, filled with device addresses, to device memory
cudaMemcpy( mbd, mbd_host, sizeof(mbd), cudaMemcpyHostToDevice );
// Voila!

ところで、 MyBigData 構造体を__global__ではなく__constant__、デバイスのメモリに保存することをお勧めします ( allocating の代わりに定数を宣言し、last の代わりに使用する必要mbdがあります) 。cudaMalloccudaMemcpyToSymbolcudaMemcpy

于 2012-05-05T07:21:34.980 に答える