[arrayfire] 270/284: Fixes to random.hpp to work in multi-threaded environment
Ghislain Vaillant
ghisvail-guest at moszumanska.debian.org
Sun Feb 7 18:59:41 UTC 2016
This is an automated email from the git hooks/post-receive script.
ghisvail-guest pushed a commit to branch debian/experimental
in repository arrayfire.
commit a9385003330a999b125eaf2f8d193bf78954b424
Author: Pavan Yalamanchili <pavan at arrayfire.com>
Date: Thu Feb 4 01:53:08 2016 -0500
Fixes to random.hpp to work in multi-threaded environment
---
src/backend/cpu/kernel/random.hpp | 119 ++++++++++++++++++++++++++++----------
src/backend/cpu/random.cpp | 40 ++-----------
test/random.cpp | 4 ++
3 files changed, 97 insertions(+), 66 deletions(-)
diff --git a/src/backend/cpu/kernel/random.hpp b/src/backend/cpu/kernel/random.hpp
index f9cb390..9c59a64 100644
--- a/src/backend/cpu/kernel/random.hpp
+++ b/src/backend/cpu/kernel/random.hpp
@@ -24,6 +24,12 @@ namespace kernel
using namespace std;
+#if defined(_WIN32)
+ #define __THREAD_LOCAL static __declspec(thread)
+#else
+ #define __THREAD_LOCAL static __thread
+#endif
+
template<typename T>
using is_arithmetic_t = typename enable_if< is_arithmetic<T>::value, function<T()>>::type;
template<typename T>
@@ -68,74 +74,125 @@ nrand(GenType &generator)
return [func] () { return T(func(), func());};
}
-static mt19937 generator;
-static unsigned long long gen_seed = 0;
-static bool is_first = true;
-#define GLOBAL 1
+mt19937& getGenerator()
+{
+ // FIXME: This abomination of a work around is brought to you
+ // by incomplete standards from Xcode and Visual Studio
+ // Should ideally be using thread_local on object instead of pointer
+ __THREAD_LOCAL mt19937 *generator = NULL;
+ if (generator == NULL) generator = new mt19937();
+ return *generator;
+}
+
+unsigned long long& getSeed()
+{
+ __THREAD_LOCAL unsigned long long gen_seed = 0;
+ return gen_seed;
+}
+
+void getSeedPtr(unsigned long long *seed)
+{
+ *seed = getSeed();
+}
+
+bool& isFirst()
+{
+ __THREAD_LOCAL bool is_first = true;
+ return is_first;
+}
+
+void setSeed(const uintl seed)
+{
+ getGenerator().seed(seed);
+ getSeed() = seed;
+ isFirst() = false;
+}
+
+//FIXME: See if we can use functors instead of function pointer directly
+template<typename T>
+struct RandomDistribution
+{
+ std::function<T()> func;
+ RandomDistribution(std::function<T()> dist_func) : func(dist_func)
+ {
+ }
+};
template<typename T>
void randn(Array<T> out)
{
- static unsigned long long my_seed = 0;
- if (is_first) {
- setSeed(gen_seed);
- my_seed = gen_seed;
+ __THREAD_LOCAL unsigned long long my_seed = 0;
+ if (isFirst()) {
+ my_seed = getSeed();
+ setSeed(my_seed);
}
- static auto gen = nrand<T>(generator);
+ // FIXME: This abomination of a work around is brought to you
+ // by incomplete standards from Xcode and Visual Studio
+ // Should ideally be using thread_local on object instead of pointer
+ __THREAD_LOCAL RandomDistribution<T> *distPtr = NULL;
- if (my_seed != gen_seed) {
- gen = nrand<T>(generator);
- my_seed = gen_seed;
+ if (!distPtr || my_seed != getSeed()) {
+ if (distPtr) delete distPtr;
+ distPtr = new RandomDistribution<T>(nrand<T>(getGenerator()));
+ my_seed = getSeed();
}
T *outPtr = out.get();
for (int i = 0; i < (int)out.elements(); i++) {
- outPtr[i] = gen();
+ outPtr[i] = distPtr->func();
}
}
template<typename T>
void randu(Array<T> out)
{
- static unsigned long long my_seed = 0;
- if (is_first) {
- setSeed(gen_seed);
- my_seed = gen_seed;
+ __THREAD_LOCAL unsigned long long my_seed = 0;
+ if (isFirst()) {
+ my_seed = getSeed();
+ setSeed(my_seed);
}
- static auto gen = urand<T>(generator);
+ // FIXME: This abomination of a work around is brought to you
+ // by incomplete standards from Xcode and Visual Studio
+ // Should ideally be using thread_local on object instead of pointer
+ __THREAD_LOCAL RandomDistribution<T> *distPtr = NULL;
- if (my_seed != gen_seed) {
- gen = urand<T>(generator);
- my_seed = gen_seed;
+ if (!distPtr || my_seed != getSeed()) {
+ if (distPtr) delete distPtr;
+ distPtr = new RandomDistribution<T>(urand<T>(getGenerator()));
+ my_seed = getSeed();
}
T *outPtr = out.get();
for (int i = 0; i < (int)out.elements(); i++) {
- outPtr[i] = gen();
+ outPtr[i] = distPtr->func();
}
}
template<>
void randu(Array<char> out)
{
- static unsigned long long my_seed = 0;
- if (is_first) {
- setSeed(gen_seed);
- my_seed = gen_seed;
+ __THREAD_LOCAL unsigned long long my_seed = 0;
+ if (isFirst()) {
+ my_seed = getSeed();
+ setSeed(my_seed);
}
- static auto gen = urand<float>(generator);
+ // FIXME: This abomination of a work around is brought to you
+ // by incomplete standards from Xcode and Visual Studio
+ // Should ideally be using thread_local on object instead of pointer
+ __THREAD_LOCAL RandomDistribution<float> *distPtr = NULL;
- if (my_seed != gen_seed) {
- gen = urand<float>(generator);
- my_seed = gen_seed;
+ if (!distPtr || my_seed != getSeed()) {
+ if (distPtr) delete distPtr;
+ distPtr = new RandomDistribution<float>(nrand<float>(getGenerator()));
+ my_seed = getSeed();
}
char *outPtr = out.get();
for (int i = 0; i < (int)out.elements(); i++) {
- outPtr[i] = gen() > 0.5;
+ outPtr[i] = distPtr->func() > 0.5;
}
}
diff --git a/src/backend/cpu/random.cpp b/src/backend/cpu/random.cpp
index 89d86c3..06cbca3 100644
--- a/src/backend/cpu/random.cpp
+++ b/src/backend/cpu/random.cpp
@@ -39,6 +39,7 @@ INSTANTIATE_UNIFORM(uint)
INSTANTIATE_UNIFORM(intl)
INSTANTIATE_UNIFORM(uintl)
INSTANTIATE_UNIFORM(uchar)
+INSTANTIATE_UNIFORM(char)
INSTANTIATE_UNIFORM(short)
INSTANTIATE_UNIFORM(ushort)
@@ -58,48 +59,17 @@ INSTANTIATE_NORMAL(double)
INSTANTIATE_NORMAL(cfloat)
INSTANTIATE_NORMAL(cdouble)
-template<>
-Array<char> randu(const af::dim4 &dims)
-{
- static unsigned long long my_seed = 0;
- if (kernel::is_first) {
- setSeed(kernel::gen_seed);
- my_seed = kernel::gen_seed;
- }
-
- static auto gen = kernel::urand<float>(kernel::generator);
-
- if (my_seed != kernel::gen_seed) {
- gen = kernel::urand<float>(kernel::generator);
- my_seed = kernel::gen_seed;
- }
-
- Array<char> outArray = createEmptyArray<char>(dims);
- auto func = [=](Array<char> outArray) {
- char *outPtr = outArray.get();
- for (int i = 0; i < (int)outArray.elements(); i++) {
- outPtr[i] = gen() > 0.5;
- }
- };
- getQueue().enqueue(func, outArray);
-
- return outArray;
-}
-
void setSeed(const uintl seed)
{
- auto f = [=](const uintl seed){
- kernel::generator.seed(seed);
- kernel::is_first = false;
- kernel::gen_seed = seed;
- };
- getQueue().enqueue(f, seed);
+ getQueue().enqueue(kernel::setSeed, seed);
}
uintl getSeed()
{
+ uintl seed = 0;
+ getQueue().enqueue(kernel::getSeedPtr, &seed);
getQueue().sync();
- return kernel::gen_seed;
+ return seed;
}
}
diff --git a/test/random.cpp b/test/random.cpp
index 29f157a..74f7e65 100644
--- a/test/random.cpp
+++ b/test/random.cpp
@@ -59,6 +59,7 @@ void randuTest(af::dim4 & dims)
af_array outArray = 0;
ASSERT_EQ(AF_SUCCESS, af_randu(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<T>::af_type));
+ ASSERT_EQ(af_sync(-1), AF_SUCCESS);
if(outArray != 0) af_release_array(outArray);
}
@@ -69,6 +70,7 @@ void randnTest(af::dim4 &dims)
af_array outArray = 0;
ASSERT_EQ(AF_SUCCESS, af_randn(&outArray, dims.ndims(), dims.get(), (af_dtype) af::dtype_traits<T>::af_type));
+ ASSERT_EQ(af_sync(-1), AF_SUCCESS);
if(outArray != 0) af_release_array(outArray);
}
@@ -124,6 +126,7 @@ void randuArgsTest()
dim_t dims[] = {1, 2, 3, 0};
af_array outArray = 0;
ASSERT_EQ(AF_ERR_SIZE, af_randu(&outArray, ndims, dims, (af_dtype) af::dtype_traits<char>::af_type));
+ ASSERT_EQ(af_sync(-1), AF_SUCCESS);
if(outArray != 0) af_release_array(outArray);
}
@@ -143,6 +146,7 @@ TEST(Random, CPP)
af::dim4 dims(1, 2, 3, 1);
af::array out1 = af::randu(dims);
af::array out2 = af::randn(dims);
+ af::sync();
}
template<typename T>
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/arrayfire.git
More information about the debian-science-commits
mailing list