Как создать 2d-массив в cuda

Для практики я работаю над созданием простой программы инициализации матрицы на cuda. Я сделал небольшую последовательную версию для справки в качестве отправной точки. Он просто создает массив размером n на m и заполняет его числами типа double. Я читал другие сообщения и документацию, но я очень запутался, и я надеялся, что кто-то сможет объяснить мне, как инициализировать 2d-массив в cuda аналогичным образом размером n на m, как я сделал ниже. Я также был бы признателен за понимание того, как заполнить эту матрицу 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;
}

Возможный дубликат Как использовать 2D-массивы в CUDA?

Swordfish 28.11.2018 07:23
double (*arr)[m] = malloc(n * sizeof *arr); - Я не думаю, что это работает так, как вы думаете. А почему все переменные глобальные ??
Swordfish 28.11.2018 07:27

Деталь; В C arr в double (*arr)[m] - это не 2D-массив, а указатель на массив m двойников. double arr[n][m] - это 2D-массив.

chux - Reinstate Monica 28.11.2018 07:27

@chux pssst ... указатель на массив из m двойников.

Swordfish 28.11.2018 07:29

Чтобы создать указатель на 2D-массив, код C может использовать double (*arr)[n][m] = malloc(sizeof *arr);

chux - Reinstate Monica 28.11.2018 07:31

Я могу изменить переменные, чтобы они были локальными, если вы предпочитаете, это будет иметь больше смысла.

the_martian 28.11.2018 07:32

@chux спасибо, тогда я обновлю соответственно

the_martian 28.11.2018 07:32

Cuda не моя сила. Удачи

chux - Reinstate Monica 28.11.2018 07:36

@Swordfish На второй мысли, возможно, OP действительно хочет double (*arr)[m] = malloc(n * sizeof *arr);, даже если это не правильный 2D-массив. Хммм уже поздно.

chux - Reinstate Monica 28.11.2018 07:38

хорошо @chux еще раз спасибо за вашу предыдущую помощь

the_martian 28.11.2018 07:38
это может представлять интерес
Robert Crovella 28.11.2018 15:03
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
11
86
1

Ответы 1

Вы можете моделировать 2D-массив в 1D, сохраняя данные строка за строкой. Итак, этот 2D-массив: [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 жалуется, что многие другие ответы на этот вопрос уже на Переполнение стека, по-видимому, слишком сложны для понимания из-за ограниченного объяснения. Ваш ответ страдает той же проблемой

talonmies 28.11.2018 16:23

Другие вопросы по теме