【问题标题】:cudaMallocManaged for 2D and 3D arraycudaMallocManaged 用于 2D 和 3D 阵列
【发布时间】:2018-12-20 03:07:37
【问题描述】:

如果想要将阵列从主机复制到设备,请执行 cudamalloccudaMemcpy。但是为了减少麻烦,只需做 cudaMallocManaged 没有前两件事,生活从未如此简单。 代码看起来像这样(或多或少)

__global__ void convert(float kelvin[], float celsius[])  //can pass 
arrays in kernel
{
     int i = blockIdx.x * blockDim.x + threadIdx.x;
  if (i<N)
    kelvin[i]=celsius[i]+273.15;
}

int main()
{
    float *celsius =(float *)malloc(N*sizeof(float));
    float *kelvin =(float *)malloc(N*sizeof(float));
    cudaMallocManaged(&celsius, N*sizeof(float));
    cudaMallocManaged(&kelvin, N*sizeof(float));

// init celsius here

dim3 blocksPerGrid(1,1,1); //use only one block
dim3 threadsPerBlock(N,1,1); //use N threads in the block
convert<<<blocksPerGrid, threadsPerBlock>>>(kelvin,celsius);
cudaDeviceSynchronize();

//Doing stuff with the output here

return 0;
}

前面的例子对我来说似乎很清楚。 但是,怎么办 cudaMallocManaged 用于 2D 和 3D 数组?我一直在努力

__global__ void MatAdd(float A[N][N], float B[N][N], float C[N][N])
{
int i = blockIdx.x * blockDim.x + threadIdx.x;
int j = blockIdx.y * blockDim.y + threadIdx.y;
if (i < N && j < N)
C[i][j] = A[i][j] + B[i][j];
}

int main()
{   // I thonk, 2D arrays can be passed as pointer to pointers
    float **A = (float **)malloc(N*N*sizeof(float));
    float **B = (float **)malloc(N*N*sizeof(float));
    float **C = (float **)malloc(N*N*sizeof(float));
    cudaMallocManaged(&A, N*N*sizeof(float));
    cudaMallocManaged(&B, N*N*sizeof(float));
    cudaMallocManaged(&C, N*N*sizeof(float));


A[N][N]={{1,0,0},{0,1,0},{0,0,1}};
B[N][N]={{1,0,0},{0,1,0},{0,0,1}};
dim3 threadsPerBlock(16, 16);
dim3 numBlocks(N / threadsPerBlock.x, N / threadsPerBlock.y);
MatAdd<<<numBlocks, threadsPerBlock>>>(A, B, C);
//outputs and all

}

但是,它显示以下错误

matrix_add.cu(22): error: too many initializer values

matrix_add.cu(25): error: argument of type "float **" is incompatible with parameter of type "float (*)[3]"

非常感谢您的帮助。

【问题讨论】:

  • “二维数组”不能作为指针传递。为什么所有东西都分配了两次?
  • @talonmies ,因为我已经在 CPU 中分配了内存,所以我也必须在 cuda 设备中分配它。这里 cudaMallocManaged 在 GPU 中分配相同的内存。至少我是这么认为的
  • 你想错了。 malloc 调用是不必要且不正确的,就像代码中的其他所有内容一样。我建议您重新阅读上一个问题的答案中的所有内容,因为您显然不明白那里告诉您的内容。

标签: cuda


【解决方案1】:

您在尝试中犯了很多错误,以至于编写一个工作版本比在您的问题中列出代码中的所有单个问题要快。因此,这是您尝试做的工作的工作版本:

#include <algorithm>
#include <iostream>

const int N = 3;

__global__ void MatAdd(float A[][N], float B[][N], float C[][N])
{
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    int j = blockIdx.y * blockDim.y + threadIdx.y;
    if (i < N && j < N)
        C[i][j] = A[i][j] + B[i][j];
}

int main()
{
    float* A; cudaMallocManaged(&A, N*N*sizeof(float));
    float* B; cudaMallocManaged(&B, N*N*sizeof(float));
    float* C; cudaMallocManaged(&C, N*N*sizeof(float));

    const float A_vals[N][N]={{1,0,0},{0,1,0},{0,0,1}};
    const float B_vals[N][N]={{1,0,0},{0,1,0},{0,0,1}};
    float (*C_vals)[N] = reinterpret_cast<float (*)[N]>(C);

    std::copy(&A_vals[0][0], &A_vals[0][0] + N*N, A);
    std::copy(&B_vals[0][0], &B_vals[0][0] + N*N, B);

    dim3 threadsPerBlock(16, 16);
    dim3 numBlocks(1, 1);
    MatAdd<<<numBlocks, threadsPerBlock>>>( reinterpret_cast<float (*)[N]>(A),
                                            reinterpret_cast<float (*)[N]>(B),
                                            C_vals );

    cudaDeviceSynchronize();

    for(int i=0; i<N; i++) {
        for(int j=0; j<N; j++) {
            std::cout << C_vals[i][j] << "  ";
        }
        std::cout << std::endl;
    }

    return 0;
}

一些重点:

  1. 托管内存分配取代了标准的主机内存分配,并生成可在主机和设备上直接访问的内存。
  2. 当按值作为参数传递给函数时,所有数组都会衰减为指针。这种衰减不是递归的。有关详细信息,请参阅here
  3. 您可以(并且需要)强制转换,以便在运行时动态分配的线性内存上使用[][] 访问语法(这适用于mallocnew 或任何CUDA 主机内存分配API . 详情请见here)。
  4. 数组的初始化语法和赋值语法不可互换。

我只能建议你彻底研究它,直到你了解它是如何工作的。

【讨论】:

  • 先生,感谢您对这个问题的详细回答。当谈到程序的内存分配部分时,我肯定没有太多的知识。我是物理专业的学生和 python 程序员,所以我的路径不会与内存元素交叉。今年夏天,我为我的模拟项目选择了 CUDA,并在此过程中犯了一些巨大的错误。然而,总有一条学习曲线。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-23
  • 1970-01-01
相关资源
最近更新 更多