PSCF v1.4.0
CudaVecRandom.cu
1#include "CudaVecRandom.h"
2#include "ThreadArray.h"
3#include <util/global.h>
4#include <sys/time.h>
5#include <string>
6
7namespace Pscf {
8
9 using namespace Util;
10
11 // Anonymous namesapce, for functions that are only used in this file
12 namespace {
13
14 /*
15 * Linear array transformation a[i] => c*a[i] + s (float).
16 */
17 __global__
18 void _linearScale(float* a, float c, float s, int n)
19 {
20 int nThreads = blockDim.x * gridDim.x;
21 int startID = blockIdx.x * blockDim.x + threadIdx.x;
22 for (int i = startID; i < n; i += nThreads) {
23 a[i] = a[i] * c + s;
24 }
25 }
26
27 /*
28 * Linear array transformation a[i] => c*a[i] + s (double).
29 */
30 __global__
31 void _linearScale(double* a, double c, double s, int n)
32 {
33 int nThreads = blockDim.x * gridDim.x;
34 int startID = blockIdx.x * blockDim.x + threadIdx.x;
35 for (int i = startID; i < n; i += nThreads) {
36 a[i] = a[i] * c + s;
37 }
38 }
39
40 /*
41 * Linear array transformation a[i] => c*a[i] + s (float).
42 */
43 void linearScale(DeviceArray<float>& a, float c, float s)
44 {
45 const int n = a.capacity();
46
47 // GPU resources
48 int nBlocks, nThreads;
49 ThreadArray::setThreadsLogical(n, nBlocks, nThreads);
50
51 // Launch kernel
52 _linearScale<<<nBlocks, nThreads>>>(a.cArray(), c, s, n);
53 }
54
55 /*
56 * Linear array transformation a[i] => c*a[i] + s (double).
57 */
58 void linearScale(DeviceArray<double>& a, double c, double s)
59 {
60 const int n = a.capacity();
61
62 // GPU resources
63 int nBlocks, nThreads;
64 ThreadArray::setThreadsLogical(n, nBlocks, nThreads);
65
66 // Launch kernel
67 _linearScale<<<nBlocks, nThreads>>>(a.cArray(), c, s, n);
68 }
69
70 } // end anonymous namespace
71
72 // Public class member functions
73
74 /*
75 * Constructor.
76 */
78 : gen_(),
79 seed_(0),
80 isInitialized_(false)
81 {
82 // Create pseudo-random number generator on gpu
83 curandStatus_t status;
84 status = curandCreateGenerator(&gen_, CURAND_RNG_PSEUDO_DEFAULT);
85 errorCheck(status);
86 }
87
88 /*
89 * Destructor.
90 */
93
94 /*
95 * Set random random number generator seed.
96 *
97 * \param seed value for random seed (private member variable seed)
98 */
99 void CudaVecRandom::setSeed(unsigned long long seed)
100 {
101 if (seed == 0) {
102 timeval time;
103 gettimeofday(&time, NULL);
104 seed_ = time.tv_sec + 1123*time.tv_usec;
105 } else {
106 seed_ = seed;
107 }
108 curandStatus_t status;
109 status = curandSetPseudoRandomGeneratorSeed(gen_, seed_);
110 errorCheck(status);
111
112 isInitialized_ = true;
113 }
114
115 /*
116 * Populate array with uniform random floats in (0, 1].
117 */
119 {
120 const int n = data.capacity();
121 UTIL_CHECK(n > 0);
122 if (!isInitialized_) {
123 setSeed(0);
124 }
125
126 curandStatus_t status;
127 status = curandGenerateUniform(gen_, data.cArray(), n);
128 errorCheck(status);
129 }
130
131 /*
132 * Populate array with uniform random doubles in (0, 1].
133 */
135 {
136 const int n = data.capacity();
137 UTIL_CHECK(n > 0);
138 if (!isInitialized_) {
139 setSeed(0);
140 }
141
142 curandStatus_t status;
143 status = curandGenerateUniformDouble(gen_, data.cArray(), n);
144 errorCheck(status);
145 }
146
147 /*
148 * Populate array with uniform random floats in (min, max].
149 */
151 float min, float max)
152 {
153 UTIL_CHECK(max > min);
154 uniform(data);
155 linearScale(data, max - min, min);
156 }
157
158 /*
159 * Populate array with uniform random doubles in (min, max].
160 */
162 double min, double max)
163 {
164 UTIL_CHECK(max > min);
165 uniform(data);
166 linearScale(data, max - min, min);
167 }
168
169 /*
170 * Populate array with normal-distributed random floats.
171 */
173 float stddev, float mean)
174 {
175 UTIL_CHECK(data.capacity() > 0);
176 if (!isInitialized_) {
177 setSeed(0);
178 }
179
180 int n = data.capacity();
181 if (n % 2 == 1) {
182 UTIL_THROW("normal() requires array size to be an even number.");
183 }
184
185 curandStatus_t status;
186 status = curandGenerateNormal(gen_, data.cArray(), n, mean, stddev);
187 errorCheck(status);
188 }
189
190 /*
191 * Populate array with normal-distributed random doubles.
192 */
194 double stddev, double mean)
195 {
196 UTIL_CHECK(data.capacity() > 0);
197 if (!isInitialized_) {
198 setSeed(0);
199 }
200
201 int n = data.capacity();
202 if (n % 2 == 1) {
203 UTIL_THROW("normal() requires array size to be an even number.");
204 }
205
206 curandStatus_t status;
207 status = curandGenerateNormalDouble(gen_, data.cArray(),
208 n, mean, stddev);
209 errorCheck(status);
210 }
211
212 /*
213 * Check generator error status.
214 *
215 * If not success, print info and throw Exception.
216 */
217 void CudaVecRandom::errorCheck(curandStatus_t const & error)
218 {
219 if (error == CURAND_STATUS_SUCCESS) {
220 return;
221 } else {
222 std::string errString;
223 switch (error)
224 {
225 default:
226 errString = "UNKNOWN";
227 break;
228 case CURAND_STATUS_VERSION_MISMATCH:
229 errString = "CURAND_STATUS_VERSION_MISMATCH";
230 break;
231 case CURAND_STATUS_NOT_INITIALIZED:
232 errString = "CURAND_STATUS_NOT_INITIALIZED";
233 break;
234 case CURAND_STATUS_ALLOCATION_FAILED:
235 errString = "CURAND_STATUS_ALLOCATION_FAILED";
236 break;
237 case CURAND_STATUS_TYPE_ERROR:
238 errString = "CURAND_STATUS_TYPE_ERROR";
239 break;
240 case CURAND_STATUS_OUT_OF_RANGE:
241 errString = "CURAND_STATUS_OUT_OF_RANGE";
242 break;
243 case CURAND_STATUS_LENGTH_NOT_MULTIPLE:
244 errString = "CURAND_STATUS_LENGTH_NOT_MULTIPLE";
245 break;
246 case CURAND_STATUS_DOUBLE_PRECISION_REQUIRED:
247 errString = "CURAND_STATUS_DOUBLE_PRECISION_REQUIRED";
248 break;
249 case CURAND_STATUS_LAUNCH_FAILURE:
250 errString = "CURAND_STATUS_LAUNCH_FAILURE";
251 break;
252 case CURAND_STATUS_PREEXISTING_FAILURE:
253 errString = "CURAND_STATUS_PREEXISTING_FAILURE";
254 break;
255 case CURAND_STATUS_INITIALIZATION_FAILED:
256 errString = "CURAND_STATUS_INITIALIZATION_FAILED";
257 break;
258 case CURAND_STATUS_INTERNAL_ERROR:
259 errString = "CURAND_STATUS_INTERNAL_ERROR";
260 break;
261 case CURAND_STATUS_ARCH_MISMATCH:
262 errString = "CURAND_STATUS_ARCH_MISMATCH";
263 break;
264 }
265
266 Log::file() << "CudaVecRandom error: " << errString << std::endl;
267 UTIL_THROW("CudaVecRandom number generation failed.");
268 }
269 }
270
271}
long seed()
Returns value of random seed (private member variable seed_).
void setSeed(unsigned long long seed)
Set value of random seed (private member variable seed_).
virtual ~CudaVecRandom()
Destructor.
void uniform(DeviceArray< float > &data)
Populate array with uniform random floats in (0, 1].
CudaVecRandom()
Constructor.
void normal(DeviceArray< float > &data, float stddev, float mean=0.0)
Populate array on device with normal-distributed random floats.
Dynamic array on the GPU device with aligned data.
Definition DeviceArray.h:96
int capacity() const
Return array capacity.
Data * cArray()
Return pointer to underlying C array.
static std::ostream & file()
Get log ostream by reference.
Definition Log.cpp:59
File containing preprocessor macros for error handling.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition global.h:49
void setThreadsLogical(int nThreadsLogical)
Given total number of threads, set 1D execution configuration.
int nThreads()
Get the number of threads per block for execution.
int nBlocks()
Get the current number of blocks for execution.
PSCF package top-level namespace.