Как скопировать переменные из массива пользовательских классов на хосте в массив с плавающей точкой на устройстве в CUDA

0

Я использую CUDA. У меня есть следующий класс на хосте:

class Particle{
     public:
     float x;
     float v;
     // several other variables
}

Тогда у меня есть вектор частиц

vector <Particle> p_all(512);

На GPU я хочу работать с массивом всех x (взятых из всех частиц) и вы хотите скопировать данные из массива Particles в массив float на устройстве. У меня есть подозрение, что cudaMemcpy можно использовать, и я попробовал следующий код, но он дает неверную ошибку основного тона.

cudaMalloc( (void**) &pos_dev, sizeof(float)*512);
cudaMemcpy2D( (void*) &pos_dev, sizeof(float), (void*)&p_all[0].x, sizeof(Particle), sizeof(Particle), 512*sizeof(float), cudaMemcpyHostToDevice);

Неужели это возможно? Конечно, решение для резервного копирования состоит в создании массива x с использованием цикла for, а затем его копирования на устройство. Но я ищу более эффективное решение.

Благодарю.

ПОЛНЫЙ КОДЕКС НИЖЕ.

#include <cuda_runtime.h>
#include <iostream>
#include <vector>
using namespace std;

// This will output the proper error string when calling cudaGetLastError
void getLastCudaError(string s=""){
    string errMessage = s;
    cudaError_t err = cudaGetLastError();
    if( err != cudaSuccess){
        cerr << __FILE__ << "(" << __LINE__ << ") : Last Cuda Error - " << errMessage 
             << " (" << int(err) << "): " << cudaGetErrorString(err) << ".\n";
        exit(-1);
    }
}

class Particle{
    public:
    float x;
    float v;
    int a;
    char c;
    short b;

    Particle(){
        a=1988; c='a'; v=5.56; x=1810; b=1.66;
    }
};

template <class T>
void printVec(vector <T> &v, string name = "v"){
    cout << name << " = ";
    for (int i=0; i<v.size(); ++i) cout << v[i] << " " ;
    cout << '\n';
}

int main(){

    const int N = 512;
    vector <float> pos(N,5);

    vector <Particle> p_all(N);

    float * pos_dev;
    float * vel_dev;

    cudaMalloc( (void**) &pos_dev, sizeof(float)*N);

    printVec(pos, "pos");

    cudaMemcpy2D( (void*) &pos_dev, sizeof(float), (void*)&(p_all[0].x), sizeof(Particle), sizeof(float), N, cudaMemcpyHostToDevice);
    getLastCudaError("HtoD");

    cudaMemcpy( (void*) &pos[0], (void*)&pos_dev, N*sizeof(float), cudaMemcpyDeviceToHost);
    getLastCudaError("DtoH");

    printVec(pos, "pos_new");

    return 0;

}
Теги:
arrays
cuda

2 ответа

0
Лучший ответ

Ваш вызов cudaMemcpy2D настроен неправильно. Проверьте документацию.

попробуйте это вместо этого:

cudaMemcpy2D( (void*) pos_dev, sizeof(float), (void*)&(p_all[0].x), sizeof(Particle), sizeof(float), 512, cudaMemcpyHostToDevice);

Было необходимо изменить несколько параметров, но ошибка недопустимого тангажа возникла из-за того, что запрошенная ширина передачи в байтах (у вас была sizeof(Particle)) была шире, чем шаг назначения (sizeof(float), что правильно)

EDIT: кроме того, хотя вы не спрашивали об этом, окончательная операция cudaMemcpy в коде, который вы сейчас опубликовали, также неверна. Следующие изменения должны помочь:

cudaMemcpy( (void*) &(pos[0]), (void*)pos_dev, N*sizeof(float), cudaMemcpyDeviceToHost);
  • 0
    Я попробовал ваше решение, но оно все равно выдает ошибку «неверный аргумент». Я проверил документацию, но я не совсем понимаю. Я добавил полный код к своему сообщению на случай, если вы захотите скомпилировать. - Спасибо.
  • 0
    Ох, теперь я понимаю документацию. Но ошибка все еще сохраняется. - Спасибо.
Показать ещё 3 комментария
0

Вы выделяете свои данные как "массив структур", например

class Particle{
    public:
        float x;
        float v;
}

Particle foo[N];

что приведет к объединению проблем из-за чередования данных и по этой причине вы пытаетесь использовать cudaMemcpy2D. Более удобным решением в плане использования пропускной способности является распределение данных как "структуры массивов", как

class Particle{
    public:
        float x[N];
        float v[N];
}

Particle foo;

Таким образом, вы сможете избежать использования cudaMemcpy2D и скопировать данные с хоста на устройство с помощью простой cudaMemcpy.

  • 0
    Я думал об этом, но включение массивов в класс Particle отрицательно сказывается на цели создания такого класса. Мой старый код действительно имел отдельные массивы для всех переменных-членов, но с ним становится все труднее обращаться, так как код становится все более сложным. - Спасибо.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню