У меня есть шаг Монте-Карло в Cuda, с которым мне нужна помощь. Я уже написал серийный код, и он работает как положено. Допустим, у меня есть 256 частиц, которые хранятся в
vector< vector<double> > *r;
Каждый i в r имеет (x, y) компонент, оба из которых являются двойными. Здесь r — положение частицы.
Теперь в CUDA я должен назначить этот вектор на хосте и отправить его на устройство. Оказавшись в устройстве, эти частицы должны взаимодействовать друг с другом. Предполагается, что каждая нить запускает очистку Монте-Карло. Как мне распределить память, указатели ссылок / разыменования с помощью cudaMalloc, который функционирует для создания глобальных / общих ресурсов, …— Я просто не могу обернуться вокруг этого.
Вот как выглядит выделение памяти на данный момент:
cudaMalloc((void**)&r, (blocks*threads)*sizeof(double));
CUDAErrorCheck();
kernel <<<blocks, threads>>> (&r, randomnums);
cudaDeviceSynchronize();
CUDAErrorCheck();
cudaMemcpy(r, blocks*threads*sizeof(double), cudaMemcpyDeviceToHost);
Код выше на уровне картошки. Я думаю, я не уверен, что делать — даже концептуально. Моя главная проблема заключается в распределении памяти и передаче информации на устройство и с него. & хост. Вектор r должен быть выделен, скопирован с хоста на устройство, что-то сделать с ним на устройстве и скопировать обратно на хост. Любая помощь / «указатели» будет высоко ценится.
Ваш код «уровня картофеля» демонстрирует общее непонимание CUDA, включая, но не ограничиваясь, управление r
данные. Я бы посоветовал вам расширить свои знания о CUDA, воспользовавшись некоторыми доступными образовательными ресурсами, а затем развить понимание хотя бы одного базового кода CUDA, такого как вектор добавить образец. Тогда вы сможете лучше формулировать вопросы и понимать ответы, которые вы получите. Пример:
Это почти никогда не будет иметь смысла:
cudaMalloc((void**)&r, (blocks*threads)*sizeof(double));
CUDAErrorCheck();
kernel <<<blocks, threads>>> (&r, randomnums);
Вы либо не знаете очень простой концепции, что данные должны быть переданы на устройство (через cudaMemcpy
) до того, как он может быть использован ядром графического процессора, или вы не можете быть обеспокоены написанием кода «уровня картошки», который вообще имеет какой-либо смысл — что может означать отсутствие усилий при написании разумного вопроса. Кроме того, независимо от того, что r
есть, проходя &r
Я не думаю, что ядро cuda никогда не имело бы смысла.
Относительно вашего вопроса о том, как двигаться r
назад и вперед:
Первым шагом в решении вашей проблемы будет пересмотр r
позиционировать данные как нечто, что легко может быть использовано ядром графического процессора. В общем, vector
не так уж полезно для обычного кода CUDA и vector< vector< > >
тем более. И если у вас есть плавающие указатели (*r
) тем более. Поэтому сгладьте (скопируйте) ваши данные о положении в один или два динамически распределенных 1-D массива double
:
#define N 1000
...
vector< vector<double> > r(N);
...
double *pos_x_h, *pos_y_h, *pos_x_d, *pos_y_d;
pos_x_h=(double *)malloc(N*sizeof(double));
pos_y_h=(double *)malloc(N*sizeof(double));
for (int i = 0; i<N; i++){
vector<double> temp = r[i];
pos_x_h[i] = temp[0];
pos_y_h[i] = temp[1];}
Теперь вы можете выделить место для данных на устройстве и скопировать данные на устройство:
cudaMalloc(&pos_x_d, N*sizeof(double));
cudaMalloc(&pos_y_d, N*sizeof(double));
cudaMemcpy(pos_x_d, pos_x_h, N*sizeof(double), cudaMemcpyHostToDevice);
cudaMemcpy(pos_y_d, pos_y_h, N*sizeof(double), cudaMemcpyHostToDevice);
Теперь вы можете правильно передать данные о местоположении в ваше ядро:
kernel<<<blocks, threads>>>(pos_x_d, pos_y_d, ...);
Копирование данных обратно после того, как ядро будет примерно
обратный шаг вышеупомянутых шагов. Это поможет вам начать:
cudaMemcpy(pos_x_h, pos_x_d, N*sizeof(double), cudaMemcpyDeviceToHost);
cudaMemcpy(pos_y_h, pos_y_d, N*sizeof(double), cudaMemcpyDeviceToHost);
Есть много способов снять шкуру с кошки, конечно же, приведенное выше является лишь примером. Однако приведенная выше организация данных будет хорошо подходить для стратегии ядра / потока, которая назначает один поток для обработки одного (x,y)
пара позиций.
Других решений пока нет …