From 4376306e471c4a77991c89b2f9874bc6a65feb83 Mon Sep 17 00:00:00 2001
From: Ben Cumming <bcumming@cscs.ch>
Date: Tue, 23 Aug 2016 11:34:08 +0200
Subject: [PATCH] Support for multi-threaded sort

* `nest::mc::threading::sort` is analogous to `std::sort`
    * when using TBB the `tbb::parallel_sort` is used
    * otherwise `std::sort` is used
* used to parallelise connection construction during setup
    * now all initialization and simulation is multi-threaded
* added a unit test
---
 src/communication/communicator.hpp |  2 +-
 src/threading/serial.hpp           | 16 +++++++++++++++-
 src/threading/tbb.hpp              | 15 +++++++++++++++
 tests/unit/test_algorithms.cpp     | 22 ++++++++++++++++++++++
 4 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/src/communication/communicator.hpp b/src/communication/communicator.hpp
index c2036d91..802d94f9 100644
--- a/src/communication/communicator.hpp
+++ b/src/communication/communicator.hpp
@@ -69,7 +69,7 @@ public:
     /// must be called after all connections have been added
     void construct() {
         if (!std::is_sorted(connections_.begin(), connections_.end())) {
-            std::sort(connections_.begin(), connections_.end());
+            threading::sort(connections_);
         }
     }
 
diff --git a/src/threading/serial.hpp b/src/threading/serial.hpp
index da2740a6..d3205817 100644
--- a/src/threading/serial.hpp
+++ b/src/threading/serial.hpp
@@ -62,10 +62,24 @@ struct parallel_for {
     }
 };
 
+template <typename RandomIt>
+void sort(RandomIt begin, RandomIt end) {
+    std::sort(begin, end);
+}
+
+template <typename RandomIt, typename Compare>
+void sort(RandomIt begin, RandomIt end, Compare comp) {
+    std::sort(begin, end, comp);
+}
+
+template <typename Container>
+void sort(Container& c) {
+    std::sort(c.begin(), c.end());
+}
+
 template <typename T>
 using parallel_vector = std::vector<T>;
 
-
 inline std::string description() {
     return "serial";
 }
diff --git a/src/threading/tbb.hpp b/src/threading/tbb.hpp
index 853ceefd..91a7b59b 100644
--- a/src/threading/tbb.hpp
+++ b/src/threading/tbb.hpp
@@ -51,6 +51,21 @@ using parallel_vector = tbb::concurrent_vector<T>;
 
 using task_group = tbb::task_group;
 
+template <typename RandomIt>
+void sort(RandomIt begin, RandomIt end) {
+    tbb::parallel_sort(begin, end);
+}
+
+template <typename RandomIt, typename Compare>
+void sort(RandomIt begin, RandomIt end, Compare comp) {
+    tbb::parallel_sort(begin, end, comp);
+}
+
+template <typename Container>
+void sort(Container& c) {
+    tbb::parallel_sort(c.begin(), c.end());
+}
+
 } // threading
 } // mc
 } // nest
diff --git a/tests/unit/test_algorithms.cpp b/tests/unit/test_algorithms.cpp
index b371b9d6..9d370dda 100644
--- a/tests/unit/test_algorithms.cpp
+++ b/tests/unit/test_algorithms.cpp
@@ -6,6 +6,28 @@
 #include "../test_util.hpp"
 #include "util/debug.hpp"
 
+/// tests the sort implementation in threading
+/// is only parallel if TBB is being used
+TEST(algorithms, parallel_sort)
+{
+    auto n = 10000;
+    std::vector<int> v(n);
+    std::iota(v.begin(), v.end(), 1);
+
+    std::random_device rd;
+    std::shuffle(v.begin(), v.end(), std::mt19937(rd()));
+
+    // assert that the original vector has in fact been permuted
+    EXPECT_FALSE(std::is_sorted(v.begin(), v.end()));
+
+    nest::mc::threading::sort(v);
+
+    EXPECT_TRUE(std::is_sorted(v.begin(), v.end()));
+    for(auto i=0; i<n; ++i) {
+       EXPECT_EQ(i+1, v[i]);
+   }
+}
+
 
 TEST(algorithms, sum)
 {
-- 
GitLab