Заставить Куранда генерировать различные случайные числа из равномерного распределения


Я пытаюсь использовать библиотеку CURAND для генерации случайных чисел, которые полностью независимы друг от друга от 0 до 100. Поэтому я даю время как семя каждому потоку и указываю " id = threadIdx.x + blockDim.x * blockIdx.x " как последовательность и смещение . Затем, получив случайное число в виде float, я умножаю его на 100 и принимаю его целочисленное значение.

Теперь проблема, с которой я сталкиваюсь, заключается в том, что он получает одно и то же случайное число для потока [0,0] и [0,1], независимо от того, сколько их раз я запускаю код, который равен 11. Я не могу понять, что я делаю не так. Пожалуйста помочь.

Я вставляю свой код ниже:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include<curand_kernel.h>
#include "util/cuPrintf.cu"
#include<time.h>

#define NE WA*HA //Total number of random numbers 
#define WA 2   // Matrix A width
#define HA 2   // Matrix A height
#define SAMPLE 100 //Sample number
#define BLOCK_SIZE 2 //Block size

__global__ void setup_kernel ( curandState * state, unsigned long seed )
{
int id = threadIdx.x  + blockIdx.x + blockDim.x;
curand_init ( seed, id , id, &state[id] );
}

__global__ void generate( curandState* globalState, float* randomMatrix )
{
int ind = threadIdx.x + blockIdx.x * blockDim.x;
if(ind < NE){
    curandState localState = globalState[ind];
    float stopId = curand_uniform(&localState) * SAMPLE;
    cuPrintf("Float random value is : %f",stopId);
    int stop = stopId ;
    cuPrintf("Random number %dn",stop);
    for(int i = 0; i < SAMPLE; i++){
            if(i == stop){
                    float random = curand_normal( &localState );
                    cuPrintf("Random Value %ft",random);
                    randomMatrix[ind] = random;
                    break;
            }
    }
    globalState[ind] = localState;
}
}

/////////////////////////////////////////////////////////
// Program main
/////////////////////////////////////////////////////////

int main(int argc, char** argv)
{

// 1. allocate host memory for matrix A
unsigned int size_A = WA * HA;
unsigned int mem_size_A = sizeof(float) * size_A;
float* h_A = (float* ) malloc(mem_size_A);
time_t t;

// 2. allocate device memory
float* d_A;
cudaMalloc((void**) &d_A, mem_size_A);

// 3. create random states    
curandState* devStates;
cudaMalloc ( &devStates, size_A*sizeof( curandState ) );

// 4. setup seeds
int n_blocks = size_A/BLOCK_SIZE;
time(&t);
printf("nTime is : %un",(unsigned long) t);
setup_kernel <<< n_blocks, BLOCK_SIZE >>> ( devStates, (unsigned long) t );
// 4. generate random numbers
cudaPrintfInit();
generate <<< n_blocks, BLOCK_SIZE >>> ( devStates,d_A );
cudaPrintfDisplay(stdout, true);
cudaPrintfEnd();
// 5. copy result from device to host
cudaMemcpy(h_A, d_A, mem_size_A, cudaMemcpyDeviceToHost);


// 6. print out the results
printf("nnMatrix A (Results)n");
for(int i = 0; i < size_A; i++)
{
   printf("%f ", h_A[i]);
   if(((i + 1) % WA) == 0)
      printf("n");
}
printf("n");

// 7. clean up memory
free(h_A);
cudaFree(d_A);

}

Вывод, который я получаю:

Время: 1347857063 [0, 0]: поплавок случайной величины является : 11.675105[0, 0]: случайных чисел 11 [0, 0]: случайный 0.358356 значение[0, 1]: поплавок случайной величины является : 11.675105[0, 1]: случайных чисел 11 [0, 1]: случайный 0.358356 значение [1, 0]: поплавок случайная величина : 63.840496[1, 0]: случайных чисел 63 [1, 0]: случайное значение 0.696459 [1, 1]: плавающее случайное значение: 44.712799[1, 1]: случайное число 44 [1, 1]: Случайное Значение 0.735049

1 3

1 ответ:

Здесь есть несколько неправильных вещей, я обращаюсь к первым здесь, чтобы вы начали:

Общие пункты

  • пожалуйста, проверьте возвращаемые значения всех вызовов CUDA API, смотрите здесь для получения дополнительной информации.
  • пожалуйста, запустите cuda-memcheck, чтобы проверить наличие очевидных вещей, таких как доступ вне границ.

Конкретные пункты

  • при выделении пространства для состояния RNG, вы должны иметь пространство для одного состояния на поток (не один на поток). матричный элемент, как у вас сейчас).
  • ваш расчет идентификатора потока в setup_kernel() неверен, должен быть threadIdx.x + blockIdx.x * blockDim.x (*вместо+).
  • вы используете идентификатор потока в качестве порядкового номера, а также смещение, вы должны просто установить смещение в ноль, как описано в руководстве cuRAND:

Для получения максимально качественного параллельного псевдослучайного числа, каждое эксперименту должно быть присвоено уникальное семя. В рамках эксперимента, каждый поток вычислений должен быть присваивается уникальный порядковый число.

Наконец, вы запускаете два потока на блок, это невероятно неэффективно. Для получения дополнительной информации ознакомьтесь с руководством по программированию CUDA C в разделе "максимальное использование", но вы должны стремиться запустить несколько потоков по 32 на блок (например, 128, 256) и большое количество блоков (например, десятки тысяч). Если ваша проблема невелика, то рассмотрите возможность запуска нескольких проблем одновременно (либо пакетной в одном запуске ядра, либо как ядра в разных потоках, чтобы получить параллельное выполнение).