5

CUDAで配列の配列を割り当てるのに問題があります。

void ** data;
cudaMalloc(&data, sizeof(void**)*N); // allocates without problems
for(int i = 0; i < N; i++) {
    cudaMalloc(data + i, getSize(i) * sizeof(void*)); // seg fault is thrown
}

私は何を間違えましたか?

4

5 に答える 5

11

ポインタをホストメモリに割り当ててから、各配列にデバイスメモリを割り当て、そのポインタをホストメモリに保存する必要があります。次に、ポインタを格納するためのメモリをデバイスに割り当て、ホスト メモリをデバイス メモリにコピーします。1 つの例は 1000 語の価値があります。

__global__ void multi_array_kernel( int N, void** arrays ){
    // stuff
}


int main(){

    const int N_ARRAYS = 20;
    void *h_array = malloc(sizeof(void*) * N_ARRAYS);
    for(int i = 0; i < N_ARRAYS; i++){
        cudaMalloc(&h_array[i], i * sizeof(void*));
        //TODO: check error
    }
    void *d_array = cudaMalloc(sizeof(void*) * N_ARRAYS);

    // Copy to device Memory
    cudaMemcpy(d_array, h_array, sizeof(void*) * N_ARRAYS, cudaMemcpyHostToDevice);

    multi_array_kernel<1,1>(N_ARRAYS, d_array);
    cudaThreadSynchronize();

    for(int i = 0; i < N_ARRAYS; i++){
        cudaFree(h_array[i]); //host not device memory
        //TODO: check error
    }
    cudaFree(d_array);
    free(h_array);
}
于 2009-12-11T10:56:54.173 に答える
4

これがサポートされているとは思えません。 cudaMalloc()デバイスメモリを割り当てますが、ホスト上の変数にアドレスを格納します。for ループでは、デバイス メモリ内のアドレスを渡しています。

達成しようとしていることに応じて、現在使用している for ループを呼び出す前にdata、通常のホストで割り当てたい場合があります。malloc()または、デバイス メモリの 1 つの大きなブロックを割り当て、オフセットを手動で計算します。

詳細については、 CUDA プログラミング ガイドのセクション 2.4、3.2.1、および B.2.5 (下部) を参照してください。具体的には、108ページの下部に:

__device____shared__または 変数のアドレスを取得することによって得られるアドレスは、__constant__デバイス コードでのみ使用できます。

于 2009-12-03T00:08:25.180 に答える
2

&h_array[i]最初のループではそうではないと思います&d_array[i]

于 2010-10-11T05:36:36.967 に答える
2

あなたは使用できません

cudaMalloc(&h_array[i], i * sizeof(void*));

として宣言された配列void *

定義されたデータ型を使用する

CUdeviceptr *h_array = malloc(sizeof(CUdeviceptr *) * N);

また

int *h_array = malloc(sizeof(int *) * N);

そしてそれをキャストしますvoid *

cudaMalloc((void *)&h_array[i], i * sizeof(void*));
于 2011-07-04T22:53:21.900 に答える
1

私は同じ問題を抱えていて、なんとか解決しました。

FabrizioM の回答は、私にとって良い出発点であり、大いに役立ちました。それにもかかわらず、コードをプロジェクトに転送しようとしたときに、いくつかの問題が発生しました。追加のコメントと投稿を使用して、実際の例 (VS2012、CUDA7.5) を作成できました。したがって、私は自分のコードを追加の回答として投稿し、他の人の開始点として投稿します。

命名を理解するには: 複数のカメラからキャプチャされた入力として OpenCV cv::Mat のベクトルを使用しており、これらの画像をカーネルで処理しています。

     void TransferCameraImageToCuda(const std::vector<cv::Mat*>* Images)
{

     int NumberCams     = Images->size();
     int imageSize      = Images->at(0)->cols*Images->at(0)->rows;

     CUdeviceptr*           CamArraysAdressOnDevice_H;
     CUdeviceptr*           CamArraysAdressOnDevice_D;


         //allocate memory on host to store the device-address of each array
         CamArraysAdressOnDevice_H = new CUdeviceptr[NumberCams];

         // allocate memory on the device and store the arrays on the device 
         for (int i = 0; i < NumberCams; i++){
             cudaMalloc((void**)&(CamArraysAdressOnDevice_H[i]), imageSize * sizeof(unsigned short));
             cudaMemcpy((void*)CamArraysAdressOnDevice_H[i], Images->at(i)->data, imageSize * sizeof(unsigned short), cudaMemcpyHostToDevice);
         }

         // allocate memory on the device to store the device-adresses of the arrays
         cudaMalloc((void**)&CamArraysAdressOnDevice_D, sizeof(CUdeviceptr*)* NumberCams);

         // Copy the adress of each device array to the device
         cudaMemcpy(CamArraysAdressOnDevice_D, CamArraysAdressOnDevice_H, sizeof(CUdeviceptr*)* NumberCams, cudaMemcpyHostToDevice);




}

カーネルの起動時に、デバイス ポインターをデータ型ポインター (unsigned short**) にキャストしています。

DummyKernel<<<gridDim,blockDim>>>(NumberCams, (unsigned short**) CamArraysAdressOnDevice_D)

カーネル定義は次のとおりです。

__global__ void DummyKernel(int NumberImages, unsigned short** CamImages)
{
    int someIndex = 3458;
    printf("Value Image 0 : %d \n", CamImages[0][someIndex]);
    printf("Value Image 1 : %d \n", CamImages[1][someIndex]);
    printf("Value Image 2 : %d \n", CamImages[2][someIndex]);
}
于 2016-08-24T11:25:15.023 に答える