[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