Actual source code: curand.c

  1: #include <petsc/private/deviceimpl.h>
  2: #include <petsc/private/randomimpl.h>
  3: #include <petscdevice_cuda.h>

  5: typedef struct {
  6:   curandGenerator_t gen;
  7: } PetscRandom_CURAND;

  9: static PetscErrorCode PetscRandomSeed_CURAND(PetscRandom r)
 10: {
 11:   PetscRandom_CURAND *curand = (PetscRandom_CURAND *)r->data;

 13:   PetscFunctionBegin;
 14:   PetscCallCURAND(curandSetPseudoRandomGeneratorSeed(curand->gen, r->seed));
 15:   PetscFunctionReturn(PETSC_SUCCESS);
 16: }

 18: PETSC_INTERN PetscErrorCode PetscRandomCurandScale_Private(PetscRandom, size_t, PetscReal *, PetscBool, cudaStream_t);

 20: static PetscErrorCode PetscRandomGetValuesReal_CURAND(PetscRandom r, PetscInt n, PetscReal *val)
 21: {
 22:   PetscRandom_CURAND *curand = (PetscRandom_CURAND *)r->data;
 23:   size_t              nn     = n < 0 ? (size_t)(-2 * n) : (size_t)n; /* handle complex case */
 24:   PetscDeviceContext  dctx;
 25:   cudaStream_t       *stream;

 27:   PetscFunctionBegin;
 28:   PetscCall(PetscDeviceContextGetCurrentContextAssertType_Internal(&dctx, PETSC_DEVICE_CUDA));
 29:   PetscCall(PetscDeviceContextGetStreamHandle(dctx, (void **)&stream));
 30:   PetscCallCURAND(curandSetStream(curand->gen, *stream));
 31: #if PetscDefined(USE_REAL_SINGLE)
 32:   PetscCallCURAND(curandGenerateUniform(curand->gen, val, nn));
 33: #else
 34:   PetscCallCURAND(curandGenerateUniformDouble(curand->gen, val, nn));
 35: #endif
 36:   if (r->iset) PetscCall(PetscRandomCurandScale_Private(r, nn, val, (PetscBool)(n < 0), *stream));
 37:   PetscCall(PetscDeviceContextSynchronizeIfWithBarrier_Internal(dctx));
 38:   PetscFunctionReturn(PETSC_SUCCESS);
 39: }

 41: static PetscErrorCode PetscRandomGetValues_CURAND(PetscRandom r, PetscInt n, PetscScalar *val)
 42: {
 43:   PetscFunctionBegin;
 44: #if PetscDefined(USE_COMPLEX)
 45:   /* pass negative size to flag complex scaling (if needed) */
 46:   PetscCall(PetscRandomGetValuesReal_CURAND(r, -n, (PetscReal *)val));
 47: #else
 48:   PetscCall(PetscRandomGetValuesReal_CURAND(r, n, val));
 49: #endif
 50:   PetscFunctionReturn(PETSC_SUCCESS);
 51: }

 53: static PetscErrorCode PetscRandomDestroy_CURAND(PetscRandom r)
 54: {
 55:   PetscRandom_CURAND *curand = (PetscRandom_CURAND *)r->data;

 57:   PetscFunctionBegin;
 58:   PetscCallCURAND(curandDestroyGenerator(curand->gen));
 59:   PetscCall(PetscFree(r->data));
 60:   PetscFunctionReturn(PETSC_SUCCESS);
 61: }

 63: static struct _PetscRandomOps PetscRandomOps_Values = {
 64:   PetscDesignatedInitializer(seed, PetscRandomSeed_CURAND),
 65:   PetscDesignatedInitializer(getvalue, NULL),
 66:   PetscDesignatedInitializer(getvaluereal, NULL),
 67:   PetscDesignatedInitializer(getvalues, PetscRandomGetValues_CURAND),
 68:   PetscDesignatedInitializer(getvaluesreal, PetscRandomGetValuesReal_CURAND),
 69:   PetscDesignatedInitializer(destroy, PetscRandomDestroy_CURAND),
 70: };

 72: /*MC
 73:    PETSCCURAND - access to the CUDA random number generator from a `PetscRandom` object

 75:   Level: beginner

 77:   Note:
 78:   This random number generator is available when PETSc is configured with ``./configure --with-cuda=1``

 80: .seealso: `PetscRandomCreate()`, `PetscRandomSetType()`, `PetscRandomType`
 81: M*/

 83: PETSC_EXTERN PetscErrorCode PetscRandomCreate_CURAND(PetscRandom r)
 84: {
 85:   PetscRandom_CURAND *curand;
 86:   PetscDeviceContext  dctx;
 87:   cudaStream_t       *stream;

 89:   PetscFunctionBegin;
 90:   PetscCall(PetscDeviceInitialize(PETSC_DEVICE_CUDA));
 91:   PetscCall(PetscDeviceContextGetCurrentContextAssertType_Internal(&dctx, PETSC_DEVICE_CUDA));
 92:   PetscCall(PetscDeviceContextGetStreamHandle(dctx, (void **)&stream));
 93:   PetscCall(PetscNew(&curand));
 94:   PetscCallCURAND(curandCreateGenerator(&curand->gen, CURAND_RNG_PSEUDO_DEFAULT));
 95:   PetscCallCURAND(curandSetStream(curand->gen, *stream));
 96:   /* https://docs.nvidia.com/cuda/curand/host-api-overview.html#performance-notes2 */
 97:   PetscCallCURAND(curandSetGeneratorOrdering(curand->gen, CURAND_ORDERING_PSEUDO_SEEDED));
 98:   r->ops[0] = PetscRandomOps_Values;
 99:   PetscCall(PetscObjectChangeTypeName((PetscObject)r, PETSCCURAND));
100:   r->data = curand;
101:   PetscCall(PetscRandomSeed_CURAND(r));
102:   PetscFunctionReturn(PETSC_SUCCESS);
103: }