CUDA портирование структуры с внутренней случайной функцией - PullRequest
3 голосов
/ 02 февраля 2012

Мне нужно перенести на графический процессор структуру, которая широко использует случайные числа.Все может быть перенесено без особых проблем, но функция генератора случайных чисел - это единственное, что она вызывается во всех функциях этого класса.Хотя я мог просто переопределить его как функцию внутреннего устройства самого класса.Ниже я привожу игрушечную модель того, что мне нужно (учтите, что класс, с которым я работаю, более сложный).Мне также нужно, чтобы при каждом вызове функции «rand» выдавалось другое случайное число (даже в одном и том же объекте).Здесь игрушечная модель, однако она дает неправильные результаты.Может ли кто-нибудь помочь мне исправить это, пожалуйста?

#include <cuda.h>
#include <iostream>
#include <curand_kernel.h>
using namespace std;

struct test{

float value;

curandState B;

void __device__ rand(){value=curand_uniform(&B);}
void __device__ foo(){rand();}
};

__global__ void setup_kernel(curandState *state)
{
const int id=blockIdx.x;
curand_init(id, id, 0, &state[id]);
}

__global__ void fill_mat(struct test *anobj, curandState *state)
{
 const int Idx=blockIdx.x;
 curandState localState = state[Idx];
 anobj[Idx].B=localState;
 anobj[Idx].foo();
}

int main()
{
int num=10;
curandState *devStates;
cudaMalloc(  (void **)&devStates, num*sizeof(curandState) );

struct test *results = (struct test*)malloc(num*sizeof(struct test));
struct test *to_device;
cudaMalloc ( (void **)&to_device, num*sizeof(to_device));

setup_kernel<<<num, 1>>>(devStates);

fill_mat<<<num,1>>>(to_device, devStates);

cudaMemcpy(results,to_device,num*sizeof(struct test),cudaMemcpyDeviceToHost);

for(int i=0;i<num;i++)
 cout<<results[i].value<<endl; 
return 0;
}

1 Ответ

3 голосов
/ 05 февраля 2012

Спасибо за отличный (и полный) пример. После постройки я обнаружил две проблемы.

Когда вы используете cudaMalloc to_device, вы хотите выделить num * sizeof (struct test) байтов.

Я предполагаю, что вы, возможно, захотите вызывать fill_mat более одного раза, или у вас могут быть другие ядра, и вы хотите, чтобы они каждый раз получали разные числа. Если это так, в конце fill_mat (или других ядер, которые делают копию curandState), вам нужно скопировать ваше локальное состояние обратно в curandState. Это потому, что curand продвигает состояние каждый раз, когда вы генерируете число.

Наконец (и это не обязательно ошибка). Я вижу, что вы используете идентификатор потока в качестве начального числа и последовательности в вызове curand_init. Это нормально, но существует некоторый (крайне маловероятный) риск того, что алгоритм скремблирования семян curand окажет вам влияние на часть последовательности, которая перекрывается с последовательностью какого-либо другого потока. curand_init использует скремблированную версию начального числа для генерации начального состояния, а затем применяет пропуск в 2 67 раз. Обычно цель состоит в том, чтобы все потоки использовали одно и то же начальное число, чтобы гарантировать, что каждый поток находится на расстоянии 2 * 67 от предыдущего в последовательности.

Паулс.

...