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};
57void 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;
162#if defined(LIBMESH_ENABLE_EXCEPTIONS)
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++)
391 CPPUNIT_ASSERT_EQUAL(
TestCommWorld->rank() * CHUNK_SIZE + i, dest[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);
613 Parallel::wait (request);
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);
632 Parallel::wait (request);
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);
676 Parallel::wait (request);
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);
695 Parallel::wait (request);
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) );
740 Parallel::wait (request);
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 );
782 Parallel::wait (request);
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);
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 testAllGatherVectorString()
void testAllGatherEmptyVectorString()
CPPUNIT_TEST(testBroadcastNestedType)
CPPUNIT_TEST(testScatter)
CPPUNIT_TEST(testAllGather)
CPPUNIT_TEST(testMinlocReal)
CPPUNIT_TEST(testAllGatherVectorString)
void testAllGatherHalfEmptyVectorString()
void testRecvIsendVecVecs()
void testAllGatherString()
CPPUNIT_TEST(testInfinityMin)
CPPUNIT_TEST(testAllGatherHalfEmptyVectorString)
void testParallelReduceThreadSubset()
CPPUNIT_TEST(testSemiVerify)
void testParallelForThreadSubset()
CPPUNIT_TEST(testRecvIsendVecVecs)
CPPUNIT_TEST(testSendRecvVecVecs)
void testBroadcastNestedType()
CPPUNIT_TEST(testInfinityMax)
CPPUNIT_TEST(testIrecvSend)
CPPUNIT_TEST(testAllGatherEmptyVectorString)
CPPUNIT_TEST(testGatherString)
CPPUNIT_TEST(testRecvIsendSets)
void testSendRecvVecVecs()
CPPUNIT_TEST(testAllGatherString)
CPPUNIT_TEST(testIsendRecv)
CPPUNIT_TEST(testRequestedThreadCountExceedsGlobal)
CPPUNIT_TEST(testParallelForThreadSubset)
CPPUNIT_TEST(testBroadcast)
std::vector< std::string > _number
void testRequestedThreadCountExceedsGlobal()
CPPUNIT_TEST(testParallelReduceThreadSubset)
CPPUNIT_TEST(testMaxlocReal)
LIBMESH_CPPUNIT_TEST_SUITE(ParallelTest)
CPPUNIT_TEST(testBarrier)
processor_id_type size() const
A class to represent the internal "this should never happen" errors, to be thrown by "libmesh_error()...
The StoredRange class defines a contiguous, divisible set of objects.
Dummy "splitting object" used to distinguish splitting constructors from copy constructors.
Communicator * TestCommWorld
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.
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.
The libMesh namespace provides an interface to certain functionality in the library.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
CPPUNIT_TEST_SUITE_REGISTRATION(ParallelTest)