Я использую 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;
}
Ваш вызов 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);
Вы выделяете свои данные как "массив структур", например
class Particle{
public:
float x;
float v;
}
Particle foo[N];
что приведет к объединению проблем из-за чередования данных и по этой причине вы пытаетесь использовать cudaMemcpy2D
. Более удобным решением в плане использования пропускной способности является распределение данных как "структуры массивов", как
class Particle{
public:
float x[N];
float v[N];
}
Particle foo;
Таким образом, вы сможете избежать использования cudaMemcpy2D
и скопировать данные с хоста на устройство с помощью простой cudaMemcpy
.