1 #include <libmesh/parallel.h> 2 #include <libmesh/stored_range.h> 25 void record_invocation()
27 invocations.fetch_add(1, std::memory_order_relaxed);
29 Threads::spin_mutex::scoped_lock lock(mutex);
30 thread_ids.insert(std::this_thread::get_id());
33 void record_value(
const unsigned int value)
35 value_count.fetch_add(1, std::memory_order_relaxed);
36 value_sum.fetch_add(
value, std::memory_order_relaxed);
37 value_sum_sq.fetch_add(
value *
value, std::memory_order_relaxed);
40 std::size_t unique_thread_count()
const 42 Threads::spin_mutex::scoped_lock lock(mutex);
43 return thread_ids.size();
47 std::set<std::thread::id> thread_ids;
48 std::atomic<unsigned int> invocations{0};
49 std::atomic<unsigned int> value_count{0};
50 std::atomic<unsigned int> value_sum{0};
51 std::atomic<unsigned int> value_sum_sq{0};
57 void assert_tracker_matches_values(
const VisitTracker & tracker,
58 const std::vector<unsigned int> & values)
60 unsigned int expected_sum = 0;
61 unsigned int expected_sum_sq = 0;
63 for (
const auto value : values)
65 expected_sum +=
value;
69 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(values.size()),
70 tracker.value_count.load(std::memory_order_relaxed));
71 CPPUNIT_ASSERT_EQUAL(expected_sum,
72 tracker.value_sum.load(std::memory_order_relaxed));
73 CPPUNIT_ASSERT_EQUAL(expected_sum_sq,
74 tracker.value_sum_sq.load(std::memory_order_relaxed));
79 explicit ForBody(VisitTracker & tracker_in) : tracker(tracker_in) {}
81 void operator()(
const TestRange & range)
const 83 tracker.record_invocation();
85 for (
const auto value : range)
86 tracker.record_value(
value);
89 VisitTracker & tracker;
94 explicit ReduceBody(std::shared_ptr<VisitTracker> tracker_in) :
95 tracker(
std::move(tracker_in))
99 tracker(other.tracker)
102 void operator()(
const TestRange & range)
104 tracker->record_invocation();
106 for (
const auto value : range)
111 tracker->record_value(
value);
115 void join(
const ReduceBody & other)
117 value_count += other.value_count;
118 value_sum += other.value_sum;
119 value_sum_sq += other.value_sum_sq;
122 std::shared_ptr<VisitTracker> tracker;
123 unsigned int value_count = 0;
124 unsigned int value_sum = 0;
125 unsigned int value_sum_sq = 0;
149 CPPUNIT_TEST( testMinlocReal );
150 CPPUNIT_TEST( testMaxlocReal );
158 CPPUNIT_TEST( testSemiVerify );
160 CPPUNIT_TEST( testParallelForThreadSubset );
161 CPPUNIT_TEST( testParallelReduceThreadSubset );
162 #if defined(LIBMESH_ENABLE_EXCEPTIONS) 163 CPPUNIT_TEST( testRequestedThreadCountExceedsGlobal );
166 CPPUNIT_TEST_SUITE_END();
178 _number[3] =
"Three";
182 _number[7] =
"Seven";
183 _number[8] =
"Eight";
196 std::vector<processor_id_type> vals;
201 CPPUNIT_ASSERT_EQUAL( i , vals[i] );
210 std::vector<std::string> vals;
215 CPPUNIT_ASSERT_EQUAL(
"Processor" + _number[i % 10] , vals[i] );
224 std::vector<processor_id_type> vals;
228 CPPUNIT_ASSERT_EQUAL( i , vals[i] );
237 std::vector<std::string> vals;
241 CPPUNIT_ASSERT_EQUAL(
"Processor" + _number[i % 10] , vals[i] );
250 std::vector<std::string> vals;
257 CPPUNIT_ASSERT_EQUAL(
"Processor" + _number[i % 10] +
"A" , vals[2*i] );
258 CPPUNIT_ASSERT_EQUAL(
"Processor" + _number[i % 10] +
"B" , vals[2*i+1] );
268 std::vector<std::string> vals;
271 CPPUNIT_ASSERT( vals.empty() );
280 std::vector<std::string> vals;
283 vals.push_back(
"Proc 0 only");
287 CPPUNIT_ASSERT_EQUAL( vals[0], std::string(
"Proc 0 only") );
298 std::vector<unsigned int> src{0,1,2}, dest(3,0);
305 for (std::size_t i=0; i<3; i++)
306 CPPUNIT_ASSERT_EQUAL( src[i] , dest[i] );
316 typedef pair<pair<pair<pair<int, int>,
int>,
int>,
int> pppp;
317 std::vector<pppp> src(3), dest(3);
319 src[0].first.first.first.first=0;
320 src[0].first.first.first.second=-1;
321 src[0].first.second = -2;
323 src[1].first.first.first.first=10;
324 src[1].first.first.first.second=9;
325 src[1].first.second = 8;
327 src[2].first.first.first.first=20;
328 src[2].first.first.first.second=19;
329 src[2].first.second = 18;
337 for (std::size_t i=0; i<src.size(); i++)
339 CPPUNIT_ASSERT_EQUAL(src[i].first.first.first.first,
340 dest[i].first.first.first.first);
341 CPPUNIT_ASSERT_EQUAL(src[i].first.first.first.second,
342 dest[i].first.first.first.second);
343 CPPUNIT_ASSERT_EQUAL(src[i].first.first.second,
344 dest[i].first.first.second);
345 CPPUNIT_ASSERT_EQUAL(src[i].first.second,
346 dest[i].first.second);
347 CPPUNIT_ASSERT_EQUAL(src[i].second,
360 std::vector<processor_id_type> src;
377 std::vector<unsigned int> src;
378 std::vector<unsigned int> dest;
379 static const unsigned int CHUNK_SIZE = 3;
384 for (std::size_t i=0; i<src.size(); i++)
390 for (
unsigned int i=0; i<CHUNK_SIZE; i++)
396 std::vector<unsigned int> src;
397 std::vector<unsigned int> dest;
398 std::vector<int> counts;
406 for (std::size_t i=0; i<src.size(); i++)
409 counts[i] = static_cast<int>(i+1);
416 CPPUNIT_ASSERT_EQUAL( start_value + i, dest[i] );
421 std::vector<std::vector<unsigned int>> src;
422 std::vector<unsigned int> dest;
428 for (std::size_t i=0; i<src.size(); ++i)
431 unsigned int global_counter = 0;
432 for (std::size_t i=0; i<src.size(); i++)
433 for (std::size_t j=0; j<src[i].size(); j++)
434 src[i][j] = global_counter++;
441 CPPUNIT_ASSERT_EQUAL( start_value + i, dest[i] );
464 CPPUNIT_ASSERT_EQUAL (min, static_cast<unsigned int>(0));
477 CPPUNIT_ASSERT_EQUAL (cast_int<processor_id_type>(max+1),
488 unsigned int minid = 0;
492 CPPUNIT_ASSERT_EQUAL (min, static_cast<int>(0));
493 CPPUNIT_ASSERT_EQUAL (minid, static_cast<unsigned int>(
TestCommWorld->
size()-1));
503 unsigned int maxid = 0;
507 CPPUNIT_ASSERT_EQUAL (max+1,
509 CPPUNIT_ASSERT_EQUAL (maxid, static_cast<unsigned int>(
TestCommWorld->
size()-1));
519 unsigned int minid = 0;
523 CPPUNIT_ASSERT_EQUAL (min,
Real(0));
524 CPPUNIT_ASSERT_EQUAL (minid, static_cast<unsigned int>(
TestCommWorld->
size()-1));
534 unsigned int maxid = 0;
540 CPPUNIT_ASSERT_EQUAL (maxid, static_cast<unsigned int>(
TestCommWorld->
size()-1));
549 double min = std::numeric_limits<double>::infinity();
553 CPPUNIT_ASSERT_EQUAL (min, std::numeric_limits<double>::infinity());
555 min = -std::numeric_limits<double>::infinity();
559 CPPUNIT_ASSERT_EQUAL (min, -std::numeric_limits<double>::infinity());
568 double max = std::numeric_limits<double>::infinity();
572 CPPUNIT_ASSERT_EQUAL (max, std::numeric_limits<double>::infinity());
574 max = -std::numeric_limits<double>::infinity();
578 CPPUNIT_ASSERT_EQUAL (max, -std::numeric_limits<double>::infinity());
593 std::vector<unsigned int> src_val(3), recv_val(3);
615 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
617 for (std::size_t i=0; i<src_val.size(); i++)
618 CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
623 std::fill (recv_val.begin(), recv_val.end(), 0);
634 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
636 for (std::size_t i=0; i<src_val.size(); i++)
637 CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
656 std::vector<unsigned int> src_val(3), recv_val(3);
678 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
680 for (std::size_t i=0; i<src_val.size(); i++)
681 CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
685 std::fill (recv_val.begin(), recv_val.end(), 0);
697 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
699 for (std::size_t i=0; i<src_val.size(); i++)
700 CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
718 std::set<unsigned int> src_val, recv_val;
722 src_val.insert(1337);
733 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
735 for (std::set<unsigned int>::const_iterator
736 it = src_val.begin(), end = src_val.end(); it != end;
738 CPPUNIT_ASSERT ( recv_val.count(*it) );
758 std::vector<std::vector<unsigned int> > src_val(3), recv_val;
760 src_val[0].push_back(4);
761 src_val[2].push_back(procup);
773 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
775 for (std::size_t i = 0; i != 3; ++i)
776 CPPUNIT_ASSERT_EQUAL ( src_val[i].size(), recv_val[i].size() );
778 CPPUNIT_ASSERT_EQUAL ( recv_val[0][0], static_cast<unsigned int> (4) );
779 CPPUNIT_ASSERT_EQUAL ( recv_val[2][0], static_cast<unsigned int> (
TestCommWorld->
rank()) );
780 CPPUNIT_ASSERT_EQUAL ( recv_val[2][1], procdown );
803 std::vector<std::vector<unsigned int> > src_val(3), recv_val;
805 src_val[0].push_back(4);
806 src_val[2].push_back(procup);
818 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
820 for (std::size_t i = 0; i != 3; ++i)
821 CPPUNIT_ASSERT_EQUAL ( src_val[i].size(), recv_val[i].size() );
823 CPPUNIT_ASSERT_EQUAL ( recv_val[0][0], static_cast<unsigned int> (4) );
824 CPPUNIT_ASSERT_EQUAL ( recv_val[2][0], static_cast<unsigned int> (
TestCommWorld->
rank()) );
825 CPPUNIT_ASSERT_EQUAL ( recv_val[2][1], procdown );
837 double inf = std::numeric_limits<double>::infinity();
843 inf = -std::numeric_limits<double>::infinity();
855 unsigned int color = rank % 2;
858 CPPUNIT_ASSERT(subcomm.
size() >= 1);
870 Parallel::info i = 0;
872 #ifdef LIBMESH_HAVE_MPI 873 type = MPI_COMM_TYPE_SHARED;
878 CPPUNIT_ASSERT(subcomm.
size() >= 1);
886 const unsigned int requested_threads =
888 std::vector<unsigned int> values(3);
889 std::iota(values.begin(), values.end(), 0u);
890 const TestRange range(values.cbegin(), values.cend(),
892 VisitTracker tracker;
896 assert_tracker_matches_values(tracker, values);
898 #ifdef LIBMESH_HAVE_PTHREAD 899 CPPUNIT_ASSERT_EQUAL(requested_threads,
900 tracker.invocations.load(std::memory_order_relaxed));
901 CPPUNIT_ASSERT(tracker.unique_thread_count() <= requested_threads);
909 const unsigned int requested_threads =
911 std::vector<unsigned int> values(3);
912 std::iota(values.begin(), values.end(), 0u);
913 const TestRange range(values.cbegin(), values.cend(),
915 auto tracker = std::make_shared<VisitTracker>();
916 ReduceBody body(tracker);
920 assert_tracker_matches_values(*tracker, values);
921 CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(values.size()), body.value_count);
922 CPPUNIT_ASSERT_EQUAL(tracker->value_sum.load(std::memory_order_relaxed), body.value_sum);
923 CPPUNIT_ASSERT_EQUAL(tracker->value_sum_sq.load(std::memory_order_relaxed), body.value_sum_sq);
925 #ifdef LIBMESH_HAVE_PTHREAD 926 CPPUNIT_ASSERT_EQUAL(requested_threads,
927 tracker->invocations.load(std::memory_order_relaxed));
928 CPPUNIT_ASSERT(tracker->unique_thread_count() <= requested_threads);
932 #if defined(LIBMESH_ENABLE_EXCEPTIONS) 937 std::vector<unsigned int> values(3);
938 std::iota(values.begin(), values.end(), 0u);
939 const TestRange range(values.cbegin(), values.cend());
940 VisitTracker for_tracker;
941 auto reduce_tracker = std::make_shared<VisitTracker>();
942 ReduceBody reduce_body(reduce_tracker);
945 ForBody(for_tracker),
void testBroadcast(Container &&src)
void parallel_for(const Range &range, const Body &body, unsigned int n_threads=libMesh::n_threads())
Execute the provided function object in parallel on the specified range.
void send_mode(const SendMode sm)
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
void testAllGatherHalfEmptyVectorString()
void testAllGatherEmptyVectorString()
void scatter(const std::vector< T, A > &data, T &recv, const unsigned int root_id=0) const
void testBroadcastNestedType()
void minloc(T &r, unsigned int &min_id) const
libMesh::Parallel::Communicator * TestCommWorld
void testAllGatherEmptyVectorString()
void gather(const unsigned int root_id, const T &send_data, std::vector< T, A > &recv) const
Dummy "splitting object" used to distinguish splitting constructors from copy constructors.
void testParallelReduceThreadSubset()
void testAllGatherString()
processor_id_type rank() const
void testRequestedThreadCountExceedsGlobal()
The StoredRange class defines a contiguous, divisible set of objects.
void testBroadcastNestedType()
The libMesh namespace provides an interface to certain functionality in the library.
void testAllGatherHalfEmptyVectorString()
void testParallelForThreadSubset()
void testRecvIsendVecVecs()
void testAllGatherString()
void testSendRecvVecVecs()
processor_id_type size() const
uint8_t processor_id_type
Status receive(const unsigned int dest_processor_id, T &buf, const MessageTag &tag=any_tag) const
void min(const T &r, T &o, Request &req) const
void testAllGatherVectorString()
void testAllGatherVectorString()
void split(int color, int key, Communicator &target) const
void maxloc(T &r, unsigned int &max_id) const
timpi_pure bool semiverify(const T *r) const
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
void split_by_type(int split_type, int key, info i, Communicator &target) const
void parallel_reduce(const Range &range, Body &body, unsigned int n_threads=libMesh::n_threads())
Execute the provided reduction operation in parallel on the specified range.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void max(const T &r, T &o, Request &req) const
A class to represent the internal "this should never happen" errors, to be thrown by "libmesh_error()...
void send(const unsigned int dest_processor_id, const T &buf, const MessageTag &tag=no_tag) const
CPPUNIT_TEST_SUITE_REGISTRATION(ParallelTest)
void testRecvIsendVecVecs()
void testSendRecvVecVecs()
std::vector< std::string > _number