1 // Copyright 2019, University of Freiburg.
2 // Chair of Algorithms and Data Structures.
3 // Markus Näther <naetherm@informatik.uni-freiburg.de>
4 
5 module derelict.curand.curand;
6 
7 import derelict.util.loader;
8 import derelict.cuda.runtimeapi;
9 
10 private
11 {
12   import derelict.util.system;
13 
14   static if(Derelict_OS_Windows)
15     enum libNames = "curand32_100.dll,curand64_100.dll";
16   else static if (Derelict_OS_Mac)
17     enum libNames = "libcurand.dylib,/usr/local/lib/libcurand.dylib";
18   else static if (Derelict_OS_Linux)
19   {
20     version(X86)
21       enum libNames = "libcurand.so,libcurand.so.10.0,/opt/cuda/lib/libcurand.so";
22     else version(X86_64)
23       enum libNames = "libcurand.so,libcurand.so.10.0,/opt/cuda/lib64/libcurand.so,/usr/lib/x86_64-linux-gnu/libcurand.so.10.0";
24     else
25       static assert(0, "Need to implement CUDA libNames for this arch.");
26   }
27   else
28     static assert(0, "Need to implement CUDA libNames for this operating system.");
29 }
30 
31 
32 // curand_discrete.h:
33 
34 
35 /**
36  * CURAND distribution
37  */
38 /** \cond UNHIDE_TYPEDEFS */
39 alias curandDistribution_st = double;
40 alias curandDistribution_t = curandDistribution_st*;
41 /** \endcond */
42 /**
43  * CURAND distribution M2
44  */
45 /** \cond UNHIDE_TYPEDEFS */
46 alias curandHistogramM2K_st = uint;
47 alias curandHistogramM2K_t = curandHistogramM2K_st*;
48 alias curandHistogramM2V_st = curandDistribution_st;
49 alias curandHistogramM2V_t = curandHistogramM2V_st *;
50 
51 alias curandDiscreteDistribution_t = curandDiscreteDistribution_st *;
52 /** \endcond */
53 
54 struct curandDistributionShift_st {
55   curandDistribution_t probability;
56   curandDistribution_t host_probability;
57   uint shift;
58   uint length;
59   uint host_gen;
60 };
61 
62 alias curandDistributionShift_t = curandDistributionShift_st*;
63 
64 struct curandHistogramM2_st {
65   curandHistogramM2V_t V;
66   curandHistogramM2V_t host_V;
67   curandHistogramM2K_t K;
68   curandHistogramM2K_t host_K;
69   uint host_gen;
70 };
71 
72 
73 struct curandDistributionM2Shift_st {
74   curandHistogramM2_t histogram;
75   curandHistogramM2_t host_histogram;
76   uint shift;
77   uint length;
78   uint host_gen;
79 };
80 
81 struct curandDiscreteDistribution_st {
82   curandDiscreteDistribution_t self_host_ptr;
83   curandDistributionM2Shift_t M2;
84   curandDistributionM2Shift_t host_M2;
85   double stddev;
86   double mean;
87   curandMethod_t method;
88   uint host_gen;
89 };
90 
91 alias curandDistributionM2Shift_t = curandDistributionM2Shift_st*;
92 alias curandHistogramM2_t = curandHistogramM2_st*;
93 
94 // curand.h
95 
96 /**
97  * CURAND function call status types
98  */
99 alias curandStatus = int;
100 enum : curandStatus {
101   CURAND_STATUS_SUCCESS = 0, ///< No errors
102   CURAND_STATUS_VERSION_MISMATCH = 100, ///< Header file and linked library version do not match
103   CURAND_STATUS_NOT_INITIALIZED = 101, ///< Generator not initialized
104   CURAND_STATUS_ALLOCATION_FAILED = 102, ///< Memory allocation failed
105   CURAND_STATUS_TYPE_ERROR = 103, ///< Generator is wrong type
106   CURAND_STATUS_OUT_OF_RANGE = 104, ///< Argument out of range
107   CURAND_STATUS_LENGTH_NOT_MULTIPLE = 105, ///< Length requested is not a multple of dimension
108   CURAND_STATUS_DOUBLE_PRECISION_REQUIRED = 106, ///< GPU does not have double precision required by MRG32k3a
109   CURAND_STATUS_LAUNCH_FAILURE = 201, ///< Kernel launch failure
110   CURAND_STATUS_PREEXISTING_FAILURE = 202, ///< Preexisting failure on library entry
111   CURAND_STATUS_INITIALIZATION_FAILED = 203, ///< Initialization of CUDA failed
112   CURAND_STATUS_ARCH_MISMATCH = 204, ///< Architecture mismatch, GPU does not support requested feature
113   CURAND_STATUS_INTERNAL_ERROR = 999 ///< Internal library error
114 }
115 
116 /*
117  * CURAND function call status types
118 */
119 /** \cond UNHIDE_TYPEDEFS */
120 alias curandStatus_t = curandStatus;
121 /** \endcond */
122 
123 /**
124  * CURAND generator types
125  */
126 alias curandRngType = int;
127 enum : curandRngType {
128   CURAND_RNG_TEST = 0,
129   CURAND_RNG_PSEUDO_DEFAULT = 100, ///< Default pseudorandom generator
130   CURAND_RNG_PSEUDO_XORWOW = 101, ///< XORWOW pseudorandom generator
131   CURAND_RNG_PSEUDO_MRG32K3A = 121, ///< MRG32k3a pseudorandom generator
132   CURAND_RNG_PSEUDO_MTGP32 = 141, ///< Mersenne Twister MTGP32 pseudorandom generator
133   CURAND_RNG_PSEUDO_MT19937 = 142, ///< Mersenne Twister MT19937 pseudorandom generator
134   CURAND_RNG_PSEUDO_PHILOX4_32_10 = 161, ///< PHILOX-4x32-10 pseudorandom generator
135   CURAND_RNG_QUASI_DEFAULT = 200, ///< Default quasirandom generator
136   CURAND_RNG_QUASI_SOBOL32 = 201, ///< Sobol32 quasirandom generator
137   CURAND_RNG_QUASI_SCRAMBLED_SOBOL32 = 202,  ///< Scrambled Sobol32 quasirandom generator
138   CURAND_RNG_QUASI_SOBOL64 = 203, ///< Sobol64 quasirandom generator
139   CURAND_RNG_QUASI_SCRAMBLED_SOBOL64 = 204  ///< Scrambled Sobol64 quasirandom generator
140 }
141 
142 /*
143  * CURAND generator types
144  */
145 /** \cond UNHIDE_TYPEDEFS */
146 alias curandRngType_t = curandRngType;
147 /** \endcond */
148 
149 /**
150  * CURAND ordering of results in memory
151  */
152 alias curandOrdering = int;
153 enum : curandOrdering {
154   CURAND_ORDERING_PSEUDO_BEST = 100, ///< Best ordering for pseudorandom results
155   CURAND_ORDERING_PSEUDO_DEFAULT = 101, ///< Specific default 4096 thread sequence for pseudorandom results
156   CURAND_ORDERING_PSEUDO_SEEDED = 102, ///< Specific seeding pattern for fast lower quality pseudorandom results
157   CURAND_ORDERING_QUASI_DEFAULT = 201 ///< Specific n-dimensional ordering for quasirandom results
158 }
159 
160 /*
161  * CURAND ordering of results in memory
162  */
163 /** \cond UNHIDE_TYPEDEFS */
164 alias curandOrdering_t = curandOrdering;
165 /** \endcond */
166 
167 /**
168  * CURAND choice of direction vector set
169  */
170 alias curandDirectionVectorSet = int;
171 enum : curandDirectionVectorSet {
172   CURAND_DIRECTION_VECTORS_32_JOEKUO6 = 101, ///< Specific set of 32-bit direction vectors generated from polynomials recommended by S. Joe and F. Y. Kuo, for up to 20,000 dimensions
173   CURAND_SCRAMBLED_DIRECTION_VECTORS_32_JOEKUO6 = 102, ///< Specific set of 32-bit direction vectors generated from polynomials recommended by S. Joe and F. Y. Kuo, for up to 20,000 dimensions, and scrambled
174   CURAND_DIRECTION_VECTORS_64_JOEKUO6 = 103, ///< Specific set of 64-bit direction vectors generated from polynomials recommended by S. Joe and F. Y. Kuo, for up to 20,000 dimensions
175   CURAND_SCRAMBLED_DIRECTION_VECTORS_64_JOEKUO6 = 104 ///< Specific set of 64-bit direction vectors generated from polynomials recommended by S. Joe and F. Y. Kuo, for up to 20,000 dimensions, and scrambled
176 }
177 
178 /*
179  * CURAND choice of direction vector set
180  */
181 /** \cond UNHIDE_TYPEDEFS */
182 alias curandDirectionVectorSet_t = curandDirectionVectorSet;
183 /** \endcond */
184 
185 /**
186  * CURAND array of 32-bit direction vectors
187  */
188 /** \cond UNHIDE_TYPEDEFS */
189 alias curandDirectionVectors32_t = uint[32];
190 /** \endcond */
191 
192  /**
193  * CURAND array of 64-bit direction vectors
194  */
195 /** \cond UNHIDE_TYPEDEFS */
196 alias curandDirectionVectors64_t = ulong[64];
197 /** \endcond **/
198 
199 /**
200  * CURAND generator (opaque)
201  */
202 struct curandGenerator_st;
203 
204 /**
205  * CURAND generator
206  */
207 /** \cond UNHIDE_TYPEDEFS */
208 alias curandGenerator_t = curandGenerator_st *;
209 /** \endcond */
210 
211 /*
212  * CURAND METHOD
213  */
214 /** \cond UNHIDE_ENUMS */
215 alias curandMethod = int;
216 enum : curandMethod {
217   CURAND_CHOOSE_BEST = 0, // choose best depends on args
218   CURAND_ITR = 1,
219   CURAND_KNUTH = 2,
220   CURAND_HITR = 3,
221   CURAND_M1 = 4,
222   CURAND_M2 = 5,
223   CURAND_BINARY_SEARCH = 6,
224   CURAND_DISCRETE_GAUSS = 7,
225   CURAND_REJECTION = 8,
226   CURAND_DEVICE_API = 9,
227   CURAND_FAST_REJECTION = 10,
228   CURAND_3RD = 11,
229   CURAND_DEFINITION = 12,
230   CURAND_POISSON = 13
231 }
232 
233 alias curandMethod_t = curandMethod;
234 
235 
236 extern(System) nothrow {
237 
238 }
239 
240 
241 extern(System) @nogc nothrow {
242 
243   alias da_curandCreateGenerator = curandStatus_t function(curandGenerator_t *generator, curandRngType_t rng_type);
244   alias da_curandCreateGeneratorHost = curandStatus_t function(curandGenerator_t *generator, curandRngType_t rng_type);
245   alias da_curandDestroyGenerator = curandStatus_t function(curandGenerator_t generator);
246   alias da_curandGetVersion = curandStatus_t function(int *pVersion);
247   alias da_curandGetProperty = curandStatus_t function(libraryPropertyType type, int *value);
248   alias da_curandSetStream = curandStatus_t function(curandGenerator_t generator, cudaStream_t stream);
249   alias da_curandSetPseudoRandomGeneratorSeed = curandStatus_t function(curandGenerator_t generator, ulong seed);
250   alias da_curandSetGeneratorOffset = curandStatus_t function(curandGenerator_t generator, ulong offset);
251   alias da_curandSetGeneratorOrdering = curandStatus_t function(curandGenerator_t generator, curandOrdering_t order);
252   alias da_curandSetQuasiRandomGeneratorDimensions = curandStatus_t function(curandGenerator_t generator, uint num_dimensions);
253   alias da_curandGenerate = curandStatus_t function(curandGenerator_t generator, uint *outputPtr, size_t num);
254   alias da_curandGenerateLongLong = curandStatus_t function(curandGenerator_t generator, ulong *outputPtr, size_t num);
255   alias da_curandGenerateUniform = curandStatus_t function(curandGenerator_t generator, float *outputPtr, size_t num);
256   alias da_curandGenerateUniformDouble = curandStatus_t function(curandGenerator_t generator, double *outputPtr, size_t num);
257   alias da_curandGenerateNormal = curandStatus_t function(curandGenerator_t generator, float *outputPtr, size_t n, float mean, float stddev);
258   alias da_curandGenerateNormalDouble = curandStatus_t function(curandGenerator_t generator, double *outputPtr, size_t n, double mean, double stddev);
259   alias da_curandGenerateLogNormal = curandStatus_t function(curandGenerator_t generator, float *outputPtr, size_t n, float mean, float stddev);
260   alias da_curandGenerateLogNormalDouble = curandStatus_t function(curandGenerator_t generator, double *outputPtr,size_t n, double mean, double stddev);
261   alias da_curandCreatePoissonDistribution = curandStatus_t function(double lambda, curandDiscreteDistribution_t *discrete_distribution);
262   alias da_curandDestroyDistribution = curandStatus_t function(curandDiscreteDistribution_t discrete_distribution);
263   alias da_curandGeneratePoisson = curandStatus_t function(curandGenerator_t generator, uint *outputPtr,size_t n, double lambda);
264   alias da_curandGeneratePoissonMethod = curandStatus_t function(curandGenerator_t generator, uint *outputPtr,size_t n, double lambda, curandMethod_t method);
265   //alias da_curandGenerateBinomial = curandStatus_t function(curandGenerator_t generator, uint *outputPtr,size_t num, uint n, double p);
266   //alias da_curandGenerateBinomialMethod = curandStatus_t function(curandGenerator_t generator,uint *outputPtr,size_t num, uint n, double p,curandMethod_t method);
267   alias da_curandGenerateSeeds = curandStatus_t function(curandGenerator_t generator);
268   alias da_curandGetDirectionVectors32 = curandStatus_t function(curandDirectionVectors32_t *[] vectors, curandDirectionVectorSet_t set);
269   alias da_curandGetScrambleConstants32 = curandStatus_t function(uint * * constants);
270   alias da_curandGetDirectionVectors64 = curandStatus_t function(curandDirectionVectors64_t *[] vectors, curandDirectionVectorSet_t set);
271   alias da_curandGetScrambleConstants64 = curandStatus_t function(ulong * * constants);
272 
273 }
274 
275 __gshared
276 {
277   da_curandCreateGenerator curandCreateGenerator;
278   da_curandCreateGeneratorHost curandCreateGeneratorHost;
279   da_curandDestroyGenerator curandDestroyGenerator;
280   da_curandGetVersion curandGetVersion;
281   da_curandGetProperty curandGetProperty;
282   da_curandSetStream curandSetStream;
283   da_curandSetPseudoRandomGeneratorSeed curandSetPseudoRandomGeneratorSeed;
284   da_curandSetGeneratorOffset curandSetGeneratorOffset;
285   da_curandSetGeneratorOrdering curandSetGeneratorOrdering;
286   da_curandSetQuasiRandomGeneratorDimensions curandSetQuasiRandomGeneratorDimensions;
287   da_curandGenerate curandGenerate;
288   da_curandGenerateLongLong curandGenerateLongLong;
289   da_curandGenerateUniform curandGenerateUniform;
290   da_curandGenerateUniformDouble curandGenerateUniformDouble;
291   da_curandGenerateNormal curandGenerateNormal;
292   da_curandGenerateNormalDouble curandGenerateNormalDouble;
293   da_curandGenerateLogNormal curandGenerateLogNormal;
294   da_curandGenerateLogNormalDouble curandGenerateLogNormalDouble;
295   da_curandCreatePoissonDistribution curandCreatePoissonDistribution;
296   da_curandDestroyDistribution curandDestroyDistribution;
297   da_curandGeneratePoisson curandGeneratePoisson;
298   da_curandGeneratePoissonMethod curandGeneratePoissonMethod;
299   //da_curandGenerateBinomial curandGenerateBinomial;
300   //da_curandGenerateBinomialMethod curandGenerateBinomialMethod;
301   da_curandGenerateSeeds curandGenerateSeeds;
302   da_curandGetDirectionVectors32 curandGetDirectionVectors32;
303   da_curandGetScrambleConstants32 curandGetScrambleConstants32;
304   da_curandGetDirectionVectors64 curandGetDirectionVectors64;
305   da_curandGetScrambleConstants64 curandGetScrambleConstants64;
306 }
307 
308 // Runtime API loader
309 class DerelictCuRANDLoader : SharedLibLoader
310 {
311   protected
312   {
313     override void loadSymbols()
314     {
315       bindFunc(cast(void**)&curandCreateGenerator, "curandCreateGenerator");
316       bindFunc(cast(void**)&curandCreateGeneratorHost, "curandCreateGeneratorHost");
317       bindFunc(cast(void**)&curandDestroyGenerator, "curandDestroyGenerator");
318       bindFunc(cast(void**)&curandGetVersion, "curandGetVersion");
319       bindFunc(cast(void**)&curandGetProperty, "curandGetProperty");
320       bindFunc(cast(void**)&curandSetStream, "curandSetStream");
321       bindFunc(cast(void**)&curandSetPseudoRandomGeneratorSeed, "curandSetPseudoRandomGeneratorSeed");
322       bindFunc(cast(void**)&curandSetGeneratorOffset, "curandSetGeneratorOffset");
323       bindFunc(cast(void**)&curandSetGeneratorOrdering, "curandSetGeneratorOrdering");
324       bindFunc(cast(void**)&curandSetQuasiRandomGeneratorDimensions, "curandSetQuasiRandomGeneratorDimensions");
325       bindFunc(cast(void**)&curandGenerate, "curandGenerate");
326       bindFunc(cast(void**)&curandGenerateLongLong, "curandGenerateLongLong");
327       bindFunc(cast(void**)&curandGenerateUniform, "curandGenerateUniform");
328       bindFunc(cast(void**)&curandGenerateUniformDouble, "curandGenerateUniformDouble");
329       bindFunc(cast(void**)&curandGenerateNormal, "curandGenerateNormal");
330       bindFunc(cast(void**)&curandGenerateNormalDouble, "curandGenerateNormalDouble");
331       bindFunc(cast(void**)&curandGenerateLogNormal, "curandGenerateLogNormal");
332       bindFunc(cast(void**)&curandGenerateLogNormalDouble, "curandGenerateLogNormalDouble");
333       bindFunc(cast(void**)&curandCreatePoissonDistribution, "curandCreatePoissonDistribution");
334       bindFunc(cast(void**)&curandDestroyDistribution, "curandDestroyDistribution");
335       bindFunc(cast(void**)&curandGeneratePoisson, "curandGeneratePoisson");
336       bindFunc(cast(void**)&curandGeneratePoissonMethod, "curandGeneratePoissonMethod");
337       //bindFunc(cast(void**)&curandGenerateBinomial, "curandGenerateBinomial");
338       //bindFunc(cast(void**)&curandGenerateBinomialMethod, "curandGenerateBinomialMethod");
339       bindFunc(cast(void**)&curandGenerateSeeds, "curandGenerateSeeds");
340       bindFunc(cast(void**)&curandGetDirectionVectors32, "curandGetDirectionVectors32");
341       bindFunc(cast(void**)&curandGetScrambleConstants32, "curandGetScrambleConstants32");
342       bindFunc(cast(void**)&curandGetDirectionVectors64, "curandGetDirectionVectors64");
343       bindFunc(cast(void**)&curandGetScrambleConstants64, "curandGetScrambleConstants64");
344     }
345   }
346 
347   public
348   {
349     this()
350     {
351       super(libNames);
352     }
353   }
354 }
355 
356 __gshared DerelictCuRANDLoader DerelictCuRAND;
357 
358 shared static this()
359 {
360   DerelictCuRAND = new DerelictCuRANDLoader();
361 }