【问题标题】:How do you create a 2d array in cuda你如何在 cuda 中创建一个二维数组
【发布时间】:2019-04-29 23:39:52
【问题描述】:

为了练习,我正在 cuda 中制作一个简单的矩阵初始化程序。我做了一个小的顺序版本作为起点供参考。它只是创建一个 n x m 数组并用双精度数填充它。我一直在阅读其他帖子和文档,但我很困惑,我希望有人可以向我解释如何以 n x m 大小的类似方式初始化 cuda 中的二维数组,如下所示。如果有人愿意解释,我也将不胜感激有关如何填充该 cuda 矩阵的见解。

再次嗨,关于它可能是重复的,我应该详细说明。链接的帖子并没有真正解释任何东西,它只是示例代码,它是我之前查看但不理解的帖子之一,因为它没有解释。谢谢你。

顺序版本:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <assert.h>

int n,m, i, j;
double count;

void update(int n, int m, double arr[][m]){
  for(i=0; i<n; i++){
    for(j=0; j<m; j++){
      count++;
      arr[i][j] = count;
    }
  }
}


int main(int argc, char * argv[]) {
  assert(argc==3);
  n = atoi(argv[2]);
  m = atoi(argv[1]);

  double (*arr)[n][m] = malloc(sizeof *arr);
  update(n,m,arr);
  return 0;
}

【问题讨论】:

  • double (*arr)[m] = malloc(n * sizeof *arr); – 我不认为这和你想的一样。为什么所有变量都是全局变量??
  • 详细信息;在 C 中,double (*arr)[m] 中的arr 不是二维数组,而是pointer to an array m of doublesdouble arr[n][m] 是一个二维数组。
  • @chux pssst ... 指向 m 个双精度数组的指针。
  • 要创建一个指向二维数组的指针,C 代码可以使用double (*arr)[n][m] = malloc(sizeof *arr);
  • @Swordfish 第二个想法,也许 OP 确实想要double (*arr)[m] = malloc(n * sizeof *arr);,即使它不是一个合适的二维数组。嗯,来晚了。

标签: c cuda


【解决方案1】:

您可以在一维中模拟二维数组,逐行保存数据。所以二维数组: [a,b][c,d] 变为 [a,b,c,d]。为简单起见,您可以编写一个提供此类功能的包装类。

这是这个想法的演示(不是 100% 防灾,但可以工作)

#pragma once
#include <iostream>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"

typedef int TYPE;

// NOTE: copy consturctor and = operator need to be overloaded as well
template<class T>
struct Matrix
{
    Matrix(int r, int c) : rows(r), cols(c) {
        data = new T[r*c];
    }
    ~Matrix() {
        // As we allocated memory it needs to be freed upon destruction
        delete[] data;
        data = nullptr;
    }
    int rows, cols;
    T* data;
    T* operator[](int row) {
        // Returns pointer to "ROW", further call to [] on result will retrieve item at column in this row
        return data + (row*cols);
    }
};

// Simple cuda kernel 
__global__ void add(TYPE *a, TYPE *b, TYPE *c, int rows, int cols) {
    // Get element row and col
    int row = blockIdx.y * blockDim.y + threadIdx.y;
    int col = blockIdx.x * blockDim.x + threadIdx.x;
    // If kernel block/grid is not sized perfectly make sure not to step outside data bounds
    if(row < rows && col < cols)
    {
        int idx = row*cols + col;
        c[idx] = a[idx] + b[idx];
    }
}

int main() {
    // m3 = m1 + m2 using cuda
    int rows = 5, cols = 5, total = rows * cols;
    Matrix<TYPE> m1{ rows,cols }, m2{ rows,cols }, m3{ rows,cols };

    // Initialization as 1D array
    for(int i = 0; i < total; i++)  {
        m1.data[i] = i;
    }

    // Or initialization as 2D array
    for(int r = 0; r < rows; r++)
        for(int c = 0; c < cols; c++)
            m2[r][c] = r*cols + c + 100;

    for(int i = 0; i < total; i++)  std::cout << m1.data[i] << ", ";
    std::cout << "\n";

    for(int r = 0; r < rows; r++) {
        for(int c = 0; c < cols; c++) 
            std::cout << m2[r][c] << ", ";
        std::cout << "\n";
    }

    // CUDA part
    TYPE *d_m1, *d_m2, *d_m3;

    // Allocation
    cudaMalloc((void **) &d_m1, total * sizeof(TYPE));
    cudaMalloc((void **) &d_m2, total * sizeof(TYPE));
    cudaMalloc((void **) &d_m3, total * sizeof(TYPE));

    // Copy m1 and m2 to GPU
    cudaMemcpy(d_m1, m1.data, total * sizeof(TYPE), cudaMemcpyHostToDevice);
    cudaMemcpy(d_m2, m2.data, total * sizeof(TYPE), cudaMemcpyHostToDevice);

    // Oversized on purpose to show row/col guard on add kernel
    dim3 grid(5, 5);
    dim3 block(5, 5);
    add <<< grid, block >>> (d_m1, d_m2, d_m3, rows, cols);

    // Copy result to m3
    cudaMemcpy(m3.data, d_m3, total * sizeof(TYPE), cudaMemcpyDeviceToHost);

    cudaFree(d_m1);
    cudaFree(d_m2);
    cudaFree(d_m3);

    for(int r = 0; r < rows; r++) {
        for(int c = 0; c < cols; c++)
            std::cout << m3[r][c] << ", ";
        std::cout << "\n";
    }

    system("pause");
    return 0;
}

【讨论】:

  • 我不明白麻烦地编写一个包装类而不是在主机和设备上都使用它的逻辑。此外,OP 抱怨说,由于解释有限,Stack Overflow 上已经对这个问题的许多其他答案显然难以理解。您的答案也存在同样的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-13
  • 1970-01-01
  • 2011-04-11
  • 1970-01-01
  • 2011-01-26
  • 2016-04-23
  • 2020-08-02
相关资源
最近更新 更多