1#include <libmesh/parallel.h>
2#include <libmesh/stored_range.h>
18#if defined(LIBMESH_HAVE_OPENMP) && defined(LIBMESH_HAVE_PTHREAD) && !defined(LIBMESH_HAVE_TBB_API)
19# define LIBMESH_TEST_OPENMP_TEAM_CAP 1
35 void record_invocation()
37 invocations.fetch_add(1, std::memory_order_relaxed);
39 Threads::spin_mutex::scoped_lock lock(mutex);
40 thread_ids.insert(std::this_thread::get_id());
41#ifdef LIBMESH_TEST_OPENMP_TEAM_CAP
45 openmp_team_sizes.insert(omp_get_num_threads());
46 openmp_thread_ids.insert(omp_get_thread_num());
50 void record_value(
const unsigned int value)
52 value_count.fetch_add(1, std::memory_order_relaxed);
53 value_sum.fetch_add(
value, std::memory_order_relaxed);
54 value_sum_sq.fetch_add(
value *
value, std::memory_order_relaxed);
57 std::size_t unique_thread_count()
const
59 Threads::spin_mutex::scoped_lock lock(mutex);
60 return thread_ids.size();
63#ifdef LIBMESH_TEST_OPENMP_TEAM_CAP
64 std::set<int> openmp_teams()
const
66 Threads::spin_mutex::scoped_lock lock(mutex);
67 return openmp_team_sizes;
70 std::set<int> openmp_tids()
const
72 Threads::spin_mutex::scoped_lock lock(mutex);
73 return openmp_thread_ids;
78 std::set<std::thread::id> thread_ids;
79 std::atomic<unsigned int> invocations{0};
80 std::atomic<unsigned int> value_count{0};
81 std::atomic<unsigned int> value_sum{0};
82 std::atomic<unsigned int> value_sum_sq{0};
83#ifdef LIBMESH_TEST_OPENMP_TEAM_CAP
84 std::set<int> openmp_team_sizes;
85 std::set<int> openmp_thread_ids;
92void assert_tracker_matches_values(
const VisitTracker & tracker,
93 const std::vector<unsigned int> & values)
95 unsigned int expected_sum = 0;
96 unsigned int expected_sum_sq = 0;
98 for (
const auto value : values)
100 expected_sum +=
value;
104 CPPUNIT_ASSERT_EQUAL(
static_cast<unsigned int>(values.size()),
105 tracker.value_count.load(std::memory_order_relaxed));
106 CPPUNIT_ASSERT_EQUAL(expected_sum,
107 tracker.value_sum.load(std::memory_order_relaxed));
108 CPPUNIT_ASSERT_EQUAL(expected_sum_sq,
109 tracker.value_sum_sq.load(std::memory_order_relaxed));
112#ifdef LIBMESH_TEST_OPENMP_TEAM_CAP
119void assert_openmp_team_within(
const VisitTracker & tracker,
120 const unsigned int requested_threads)
122 const std::set<int> teams = tracker.openmp_teams();
123 CPPUNIT_ASSERT(!teams.empty());
127 for (
const int team : teams)
129 CPPUNIT_ASSERT(team >= 1);
130 CPPUNIT_ASSERT(team <=
static_cast<int>(requested_threads));
135 for (
const int tid : tracker.openmp_tids())
137 CPPUNIT_ASSERT(tid >= 0);
138 CPPUNIT_ASSERT(tid <
static_cast<int>(requested_threads));
145 explicit ForBody(VisitTracker & tracker_in) : tracker(tracker_in) {}
147 void operator()(
const TestRange & range)
const
149 tracker.record_invocation();
151 for (
const auto value : range)
152 tracker.record_value(
value);
155 VisitTracker & tracker;
160 explicit ReduceBody(std::shared_ptr<VisitTracker> tracker_in) :
161 tracker(
std::move(tracker_in))
165 tracker(other.tracker)
168 void operator()(
const TestRange & range)
170 tracker->record_invocation();
172 for (
const auto value : range)
177 tracker->record_value(
value);
181 void join(
const ReduceBody & other)
183 value_count += other.value_count;
184 value_sum += other.value_sum;
185 value_sum_sq += other.value_sum_sq;
188 std::shared_ptr<VisitTracker> tracker;
189 unsigned int value_count = 0;
190 unsigned int value_sum = 0;
191 unsigned int value_sum_sq = 0;
228#if defined(LIBMESH_ENABLE_EXCEPTIONS)
231#ifdef LIBMESH_TEST_OPENMP_TEAM_CAP
266 std::vector<processor_id_type> vals;
271 CPPUNIT_ASSERT_EQUAL( i , vals[i] );
280 std::vector<std::string> vals;
285 CPPUNIT_ASSERT_EQUAL(
"Processor" +
_number[i % 10] , vals[i] );
294 std::vector<processor_id_type> vals;
298 CPPUNIT_ASSERT_EQUAL( i , vals[i] );
307 std::vector<std::string> vals;
311 CPPUNIT_ASSERT_EQUAL(
"Processor" +
_number[i % 10] , vals[i] );
320 std::vector<std::string> vals;
327 CPPUNIT_ASSERT_EQUAL(
"Processor" +
_number[i % 10] +
"A" , vals[2*i] );
328 CPPUNIT_ASSERT_EQUAL(
"Processor" +
_number[i % 10] +
"B" , vals[2*i+1] );
338 std::vector<std::string> vals;
341 CPPUNIT_ASSERT( vals.empty() );
350 std::vector<std::string> vals;
353 vals.push_back(
"Proc 0 only");
357 CPPUNIT_ASSERT_EQUAL( vals[0], std::string(
"Proc 0 only") );
368 std::vector<unsigned int> src{0,1,2}, dest(3,0);
375 for (std::size_t i=0; i<3; i++)
376 CPPUNIT_ASSERT_EQUAL( src[i] , dest[i] );
386 typedef pair<pair<pair<pair<int, int>,
int>,
int>,
int> pppp;
387 std::vector<pppp> src(3), dest(3);
389 src[0].first.first.first.first=0;
390 src[0].first.first.first.second=-1;
391 src[0].first.second = -2;
393 src[1].first.first.first.first=10;
394 src[1].first.first.first.second=9;
395 src[1].first.second = 8;
397 src[2].first.first.first.first=20;
398 src[2].first.first.first.second=19;
399 src[2].first.second = 18;
407 for (std::size_t i=0; i<src.size(); i++)
409 CPPUNIT_ASSERT_EQUAL(src[i].first.first.first.first,
410 dest[i].first.first.first.first);
411 CPPUNIT_ASSERT_EQUAL(src[i].first.first.first.second,
412 dest[i].first.first.first.second);
413 CPPUNIT_ASSERT_EQUAL(src[i].first.first.second,
414 dest[i].first.first.second);
415 CPPUNIT_ASSERT_EQUAL(src[i].first.second,
416 dest[i].first.second);
417 CPPUNIT_ASSERT_EQUAL(src[i].second,
430 std::vector<processor_id_type> src;
447 std::vector<unsigned int> src;
448 std::vector<unsigned int> dest;
449 static const unsigned int CHUNK_SIZE = 3;
454 for (std::size_t i=0; i<src.size(); i++)
460 for (
unsigned int i=0; i<CHUNK_SIZE; i++)
461 CPPUNIT_ASSERT_EQUAL(
TestCommWorld->rank() * CHUNK_SIZE + i, dest[i] );
466 std::vector<unsigned int> src;
467 std::vector<unsigned int> dest;
468 std::vector<int> counts;
476 for (std::size_t i=0; i<src.size(); i++)
479 counts[i] =
static_cast<int>(i+1);
486 CPPUNIT_ASSERT_EQUAL( start_value + i, dest[i] );
491 std::vector<std::vector<unsigned int>> src;
492 std::vector<unsigned int> dest;
498 for (std::size_t i=0; i<src.size(); ++i)
501 unsigned int global_counter = 0;
502 for (std::size_t i=0; i<src.size(); i++)
503 for (std::size_t j=0; j<src[i].size(); j++)
504 src[i][j] = global_counter++;
511 CPPUNIT_ASSERT_EQUAL( start_value + i, dest[i] );
534 CPPUNIT_ASSERT_EQUAL (min,
static_cast<unsigned int>(0));
547 CPPUNIT_ASSERT_EQUAL (cast_int<processor_id_type>(max+1),
558 unsigned int minid = 0;
562 CPPUNIT_ASSERT_EQUAL (min,
static_cast<int>(0));
563 CPPUNIT_ASSERT_EQUAL (minid,
static_cast<unsigned int>(
TestCommWorld->size()-1));
573 unsigned int maxid = 0;
577 CPPUNIT_ASSERT_EQUAL (max+1,
579 CPPUNIT_ASSERT_EQUAL (maxid,
static_cast<unsigned int>(
TestCommWorld->size()-1));
589 unsigned int minid = 0;
593 CPPUNIT_ASSERT_EQUAL (min,
Real(0));
594 CPPUNIT_ASSERT_EQUAL (minid,
static_cast<unsigned int>(
TestCommWorld->size()-1));
604 unsigned int maxid = 0;
610 CPPUNIT_ASSERT_EQUAL (maxid,
static_cast<unsigned int>(
TestCommWorld->size()-1));
619 double min = std::numeric_limits<double>::infinity();
623 CPPUNIT_ASSERT_EQUAL (min, std::numeric_limits<double>::infinity());
625 min = -std::numeric_limits<double>::infinity();
629 CPPUNIT_ASSERT_EQUAL (min, -std::numeric_limits<double>::infinity());
638 double max = std::numeric_limits<double>::infinity();
642 CPPUNIT_ASSERT_EQUAL (max, std::numeric_limits<double>::infinity());
644 max = -std::numeric_limits<double>::infinity();
648 CPPUNIT_ASSERT_EQUAL (max, -std::numeric_limits<double>::infinity());
663 std::vector<unsigned int> src_val(3), recv_val(3);
683 Parallel::wait (request);
685 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
687 for (std::size_t i=0; i<src_val.size(); i++)
688 CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
693 std::fill (recv_val.begin(), recv_val.end(), 0);
702 Parallel::wait (request);
704 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
706 for (std::size_t i=0; i<src_val.size(); i++)
707 CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
726 std::vector<unsigned int> src_val(3), recv_val(3);
746 Parallel::wait (request);
748 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
750 for (std::size_t i=0; i<src_val.size(); i++)
751 CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
755 std::fill (recv_val.begin(), recv_val.end(), 0);
765 Parallel::wait (request);
767 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
769 for (std::size_t i=0; i<src_val.size(); i++)
770 CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
788 std::set<unsigned int> src_val, recv_val;
792 src_val.insert(1337);
803 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
805 for (std::set<unsigned int>::const_iterator
806 it = src_val.begin(), end = src_val.end(); it != end;
808 CPPUNIT_ASSERT ( recv_val.count(*it) );
810 Parallel::wait (request);
828 std::vector<std::vector<unsigned int> > src_val(3), recv_val;
830 src_val[0].push_back(4);
831 src_val[2].push_back(procup);
843 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
845 for (std::size_t i = 0; i != 3; ++i)
846 CPPUNIT_ASSERT_EQUAL ( src_val[i].size(), recv_val[i].size() );
848 CPPUNIT_ASSERT_EQUAL ( recv_val[0][0],
static_cast<unsigned int> (4) );
849 CPPUNIT_ASSERT_EQUAL ( recv_val[2][0],
static_cast<unsigned int> (
TestCommWorld->rank()) );
850 CPPUNIT_ASSERT_EQUAL ( recv_val[2][1], procdown );
852 Parallel::wait (request);
873 std::vector<std::vector<unsigned int> > src_val(3), recv_val;
875 src_val[0].push_back(4);
876 src_val[2].push_back(procup);
888 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
890 for (std::size_t i = 0; i != 3; ++i)
891 CPPUNIT_ASSERT_EQUAL ( src_val[i].size(), recv_val[i].size() );
893 CPPUNIT_ASSERT_EQUAL ( recv_val[0][0],
static_cast<unsigned int> (4) );
894 CPPUNIT_ASSERT_EQUAL ( recv_val[2][0],
static_cast<unsigned int> (
TestCommWorld->rank()) );
895 CPPUNIT_ASSERT_EQUAL ( recv_val[2][1], procdown );
907 double inf = std::numeric_limits<double>::infinity();
913 inf = -std::numeric_limits<double>::infinity();
925 unsigned int color = rank % 2;
928 CPPUNIT_ASSERT(subcomm.
size() >= 1);
942#ifdef LIBMESH_HAVE_MPI
943 type = MPI_COMM_TYPE_SHARED;
948 CPPUNIT_ASSERT(subcomm.
size() >= 1);
956 const unsigned int requested_threads =
958 std::vector<unsigned int> values(3);
959 std::iota(values.begin(), values.end(), 0u);
960 const TestRange range(values.cbegin(), values.cend(),
962 VisitTracker tracker;
966 assert_tracker_matches_values(tracker, values);
968#ifdef LIBMESH_HAVE_PTHREAD
969 CPPUNIT_ASSERT_EQUAL(requested_threads,
970 tracker.invocations.load(std::memory_order_relaxed));
971 CPPUNIT_ASSERT(tracker.unique_thread_count() <= requested_threads);
979 const unsigned int requested_threads =
981 std::vector<unsigned int> values(3);
982 std::iota(values.begin(), values.end(), 0u);
983 const TestRange range(values.cbegin(), values.cend(),
985 auto tracker = std::make_shared<VisitTracker>();
986 ReduceBody body(tracker);
990 assert_tracker_matches_values(*tracker, values);
991 CPPUNIT_ASSERT_EQUAL(
static_cast<unsigned int>(values.size()), body.value_count);
992 CPPUNIT_ASSERT_EQUAL(tracker->value_sum.load(std::memory_order_relaxed), body.value_sum);
993 CPPUNIT_ASSERT_EQUAL(tracker->value_sum_sq.load(std::memory_order_relaxed), body.value_sum_sq);
995#ifdef LIBMESH_HAVE_PTHREAD
996 CPPUNIT_ASSERT_EQUAL(requested_threads,
997 tracker->invocations.load(std::memory_order_relaxed));
998 CPPUNIT_ASSERT(tracker->unique_thread_count() <= requested_threads);
1002#if defined(LIBMESH_ENABLE_EXCEPTIONS)
1007 std::vector<unsigned int> values(3);
1008 std::iota(values.begin(), values.end(), 0u);
1009 const TestRange range(values.cbegin(), values.cend());
1010 VisitTracker for_tracker;
1011 auto reduce_tracker = std::make_shared<VisitTracker>();
1012 ReduceBody reduce_body(reduce_tracker);
1015 ForBody(for_tracker),
1025#ifdef LIBMESH_TEST_OPENMP_TEAM_CAP
1039 const unsigned int requested_threads = 2u;
1043 std::vector<unsigned int> values(16);
1044 std::iota(values.begin(), values.end(), 0u);
1045 const TestRange range(values.cbegin(), values.cend(),
1047 VisitTracker tracker;
1051 assert_tracker_matches_values(tracker, values);
1052 assert_openmp_team_within(tracker, requested_threads);
1062 const unsigned int requested_threads = 2u;
1064 std::vector<unsigned int> values(16);
1065 std::iota(values.begin(), values.end(), 0u);
1066 const TestRange range(values.cbegin(), values.cend(),
1068 auto tracker = std::make_shared<VisitTracker>();
1069 ReduceBody body(tracker);
1073 assert_tracker_matches_values(*tracker, values);
1074 assert_openmp_team_within(*tracker, requested_threads);
void testAllGatherVectorString()
void testAllGatherEmptyVectorString()
CPPUNIT_TEST(testBroadcastNestedType)
CPPUNIT_TEST(testScatter)
void testParallelForOpenMPTeamCap()
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)
void testParallelReduceOpenMPTeamCap()
CPPUNIT_TEST(testParallelForThreadSubset)
CPPUNIT_TEST(testBroadcast)
std::vector< std::string > _number
CPPUNIT_TEST(testParallelForOpenMPTeamCap)
void testRequestedThreadCountExceedsGlobal()
CPPUNIT_TEST(testParallelReduceOpenMPTeamCap)
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)