【问题标题】:CUDA allocating array of arraysCUDA 分配数组数组
【发布时间】:2021-12-05 19:39:56
【问题描述】:

我在 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
}

我做错了什么?

【问题讨论】:

  • 重点是所有这些数组都有不同的大小。

标签: memory-management cuda allocation


【解决方案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);
}

【讨论】:

  • 我猜你的意思是 N_ARRAYS 而不是 N 在你的主要功能
【解决方案2】:

我不相信这是支持的。 cudaMalloc() 分配设备内存,但将地址存储在主机上的变量中。在您的 for 循环中,您将在设备内存中传递地址。

根据您要完成的任务,您可能希望在调用当前的 for 循环之前将 data 分配给普通主机 malloc()。或者分配一个大的设备内存块并手动计算偏移量。

查看CUDA Programming Guide 的第 2.4、3.2.1 和 B.2.5 节(底部)以获取更多讨论。具体来说,在第 108 页的底部:

__device____shared____shared__的地址得到的地址 __constant__ 变量只能在设备代码中使用。

【讨论】:

  • 这是正确的。 cudaMalloc 分配的指针必须驻留在主机内存中,并且您正试图将这些指针存储在设备内存中。相反,您应该在主机上创建一个指针数组,然后在最后将其复制到设备,或者按照 Gabriel 的建议计算偏移量。
【解决方案3】:

我认为在第一个循环中应该是&amp;h_array[i] 而不是&amp;d_array[i]

【讨论】:

    【解决方案4】:

    你不能使用

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

    【讨论】:

      【解决方案5】:

      我遇到了同样的问题并设法解决了。

      FabrizioM 的回答对我来说是一个很好的起点,对我帮助很大。但是,当我尝试将代码传输到我的项目时,我遇到了一些问题。使用额外的 cmets 和帖子,我能够编写一个工作示例(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);
      
      
      
      
      }
      

      在内核启动中,我将设备指针转换为数据类型指针(无符号短**)

      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]);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-26
        • 2014-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多