libMesh
parallel_test.C
Go to the documentation of this file.
1 #include <libmesh/parallel.h>
2 #include <libmesh/stored_range.h>
3 
4 #include "test_comm.h"
5 #include "libmesh_cppunit.h"
6 
7 #include <atomic>
8 #include <memory>
9 #include <numeric>
10 #include <set>
11 #include <thread>
12 
13 
14 using namespace libMesh;
15 
16 namespace {
17 
18 using TestRange = StoredRange<std::vector<unsigned int>::const_iterator, unsigned int>;
19 
20 // Shared helper state for the thread-subset tests. Each body records how many
21 // subrange invocations happened, which thread ids executed them, and a few
22 // simple aggregate checksums so we can verify every input value was visited.
23 struct VisitTracker
24 {
25  void record_invocation()
26  {
27  invocations.fetch_add(1, std::memory_order_relaxed);
28 
29  Threads::spin_mutex::scoped_lock lock(mutex);
30  thread_ids.insert(std::this_thread::get_id());
31  }
32 
33  void record_value(const unsigned int value)
34  {
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);
38  }
39 
40  std::size_t unique_thread_count() const
41  {
42  Threads::spin_mutex::scoped_lock lock(mutex);
43  return thread_ids.size();
44  }
45 
46  mutable Threads::spin_mutex mutex;
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};
52 };
53 
54 // Compare the aggregates collected by VisitTracker against the known test
55 // input values. Using count/sum/sum-of-squares gives us a compact way to catch
56 // dropped or duplicated work without depending on any particular scheduling.
57 void assert_tracker_matches_values(const VisitTracker & tracker,
58  const std::vector<unsigned int> & values)
59 {
60  unsigned int expected_sum = 0;
61  unsigned int expected_sum_sq = 0;
62 
63  for (const auto value : values)
64  {
65  expected_sum += value;
66  expected_sum_sq += value * value;
67  }
68 
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));
75 }
76 
77 struct ForBody
78 {
79  explicit ForBody(VisitTracker & tracker_in) : tracker(tracker_in) {}
80 
81  void operator()(const TestRange & range) const
82  {
83  tracker.record_invocation();
84 
85  for (const auto value : range)
86  tracker.record_value(value);
87  }
88 
89  VisitTracker & tracker;
90 };
91 
92 struct ReduceBody
93 {
94  explicit ReduceBody(std::shared_ptr<VisitTracker> tracker_in) :
95  tracker(std::move(tracker_in))
96  {}
97 
98  ReduceBody(ReduceBody & other, Threads::split) :
99  tracker(other.tracker)
100  {}
101 
102  void operator()(const TestRange & range)
103  {
104  tracker->record_invocation();
105 
106  for (const auto value : range)
107  {
108  ++value_count;
109  value_sum += value;
110  value_sum_sq += value * value;
111  tracker->record_value(value);
112  }
113  }
114 
115  void join(const ReduceBody & other)
116  {
117  value_count += other.value_count;
118  value_sum += other.value_sum;
119  value_sum_sq += other.value_sum_sq;
120  }
121 
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;
126 };
127 
128 } // anonymous namespace
129 
130 class ParallelTest : public CppUnit::TestCase {
131 public:
132  LIBMESH_CPPUNIT_TEST_SUITE( ParallelTest );
133 
134  CPPUNIT_TEST( testGather );
135  CPPUNIT_TEST( testAllGather );
136  CPPUNIT_TEST( testGatherString );
137  CPPUNIT_TEST( testAllGatherString );
138  CPPUNIT_TEST( testAllGatherVectorString );
139  CPPUNIT_TEST( testAllGatherEmptyVectorString );
140  CPPUNIT_TEST( testAllGatherHalfEmptyVectorString );
141  CPPUNIT_TEST( testBroadcast );
142  CPPUNIT_TEST( testBroadcastNestedType );
143  CPPUNIT_TEST( testScatter );
144  CPPUNIT_TEST( testBarrier );
145  CPPUNIT_TEST( testMin );
146  CPPUNIT_TEST( testMax );
147  CPPUNIT_TEST( testMinloc );
148  CPPUNIT_TEST( testMaxloc );
149  CPPUNIT_TEST( testMinlocReal );
150  CPPUNIT_TEST( testMaxlocReal );
151  CPPUNIT_TEST( testInfinityMin );
152  CPPUNIT_TEST( testInfinityMax );
153  CPPUNIT_TEST( testIsendRecv );
154  CPPUNIT_TEST( testIrecvSend );
155  CPPUNIT_TEST( testRecvIsendSets );
156  CPPUNIT_TEST( testRecvIsendVecVecs );
157  CPPUNIT_TEST( testSendRecvVecVecs );
158  CPPUNIT_TEST( testSemiVerify );
159  CPPUNIT_TEST( testSplit );
160  CPPUNIT_TEST( testParallelForThreadSubset );
161  CPPUNIT_TEST( testParallelReduceThreadSubset );
162 #if defined(LIBMESH_ENABLE_EXCEPTIONS)
163  CPPUNIT_TEST( testRequestedThreadCountExceedsGlobal );
164 #endif
165 
166  CPPUNIT_TEST_SUITE_END();
167 
168 private:
169  std::vector<std::string> _number;
170 
171 public:
172  void setUp()
173  {
174  _number.resize(10);
175  _number[0] = "Zero";
176  _number[1] = "One";
177  _number[2] = "Two";
178  _number[3] = "Three";
179  _number[4] = "Four";
180  _number[5] = "Five";
181  _number[6] = "Six";
182  _number[7] = "Seven";
183  _number[8] = "Eight";
184  _number[9] = "Nine";
185  }
186 
187  void tearDown()
188  {}
189 
190 
191 
192  void testGather()
193  {
194  LOG_UNIT_TEST;
195 
196  std::vector<processor_id_type> vals;
197  TestCommWorld->gather(0,cast_int<processor_id_type>(TestCommWorld->rank()),vals);
198 
199  if (TestCommWorld->rank() == 0)
200  for (processor_id_type i=0; i<vals.size(); i++)
201  CPPUNIT_ASSERT_EQUAL( i , vals[i] );
202  }
203 
204 
205 
207  {
208  LOG_UNIT_TEST;
209 
210  std::vector<std::string> vals;
211  TestCommWorld->gather(0, "Processor" + _number[TestCommWorld->rank() % 10], vals);
212 
213  if (TestCommWorld->rank() == 0)
214  for (processor_id_type i=0; i<vals.size(); i++)
215  CPPUNIT_ASSERT_EQUAL( "Processor" + _number[i % 10] , vals[i] );
216  }
217 
218 
219 
221  {
222  LOG_UNIT_TEST;
223 
224  std::vector<processor_id_type> vals;
225  TestCommWorld->allgather(cast_int<processor_id_type>(TestCommWorld->rank()),vals);
226 
227  for (processor_id_type i=0; i<vals.size(); i++)
228  CPPUNIT_ASSERT_EQUAL( i , vals[i] );
229  }
230 
231 
232 
234  {
235  LOG_UNIT_TEST;
236 
237  std::vector<std::string> vals;
238  TestCommWorld->gather(0, "Processor" + _number[TestCommWorld->rank() % 10], vals);
239 
240  for (processor_id_type i=0; i<vals.size(); i++)
241  CPPUNIT_ASSERT_EQUAL( "Processor" + _number[i % 10] , vals[i] );
242  }
243 
244 
245 
247  {
248  LOG_UNIT_TEST;
249 
250  std::vector<std::string> vals;
251  vals.push_back("Processor" + _number[TestCommWorld->rank() % 10] + "A");
252  vals.push_back("Processor" + _number[TestCommWorld->rank() % 10] + "B");
253  TestCommWorld->allgather(vals);
254 
255  for (processor_id_type i=0; i<(vals.size()/2); i++)
256  {
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] );
259  }
260  }
261 
262 
263 
265  {
266  LOG_UNIT_TEST;
267 
268  std::vector<std::string> vals;
269  TestCommWorld->allgather(vals);
270 
271  CPPUNIT_ASSERT( vals.empty() );
272  }
273 
274 
275 
277  {
278  LOG_UNIT_TEST;
279 
280  std::vector<std::string> vals;
281 
282  if (!TestCommWorld->rank())
283  vals.push_back("Proc 0 only");
284 
285  TestCommWorld->allgather(vals);
286 
287  CPPUNIT_ASSERT_EQUAL( vals[0], std::string("Proc 0 only") );
288  }
289 
290 
291 
293  {
294  LOG_UNIT_TEST;
295 
296  // Workaround for spurious warning from operator=
297  // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100366
298  std::vector<unsigned int> src{0,1,2}, dest(3,0);
299 
300  if (TestCommWorld->rank() == 0)
301  dest = src;
302 
303  TestCommWorld->broadcast(dest);
304 
305  for (std::size_t i=0; i<3; i++)
306  CPPUNIT_ASSERT_EQUAL( src[i] , dest[i] );
307  }
308 
309 
310 
312  {
313  LOG_UNIT_TEST;
314 
315  using std::pair;
316  typedef pair<pair<pair<pair<int, int>, int>, int>, int> pppp;
317  std::vector<pppp> src(3), dest(3);
318 
319  src[0].first.first.first.first=0;
320  src[0].first.first.first.second=-1;
321  src[0].first.second = -2;
322  src[0].second = -3;
323  src[1].first.first.first.first=10;
324  src[1].first.first.first.second=9;
325  src[1].first.second = 8;
326  src[1].second = 7;
327  src[2].first.first.first.first=20;
328  src[2].first.first.first.second=19;
329  src[2].first.second = 18;
330  src[2].second = 17;
331 
332  if (TestCommWorld->rank() == 0)
333  dest = src;
334 
335  TestCommWorld->broadcast(dest);
336 
337  for (std::size_t i=0; i<src.size(); i++)
338  {
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,
348  dest[i].second);
349  }
350  }
351 
352 
353 
354  void testScatter()
355  {
356  LOG_UNIT_TEST;
357 
358  // Test Scalar scatter
359  {
360  std::vector<processor_id_type> src;
361  processor_id_type dest;
362 
363  if (TestCommWorld->rank() == 0)
364  {
365  src.resize(TestCommWorld->size());
366  for (processor_id_type i=0; i<src.size(); i++)
367  src[i] = i;
368  }
369 
370  TestCommWorld->scatter(src, dest);
371 
372  CPPUNIT_ASSERT_EQUAL( TestCommWorld->rank(), dest );
373  }
374 
375  // Test Vector Scatter (equal-sized chunks)
376  {
377  std::vector<unsigned int> src;
378  std::vector<unsigned int> dest;
379  static const unsigned int CHUNK_SIZE = 3;
380 
381  if (TestCommWorld->rank() == 0)
382  {
383  src.resize(TestCommWorld->size() * CHUNK_SIZE);
384  for (std::size_t i=0; i<src.size(); i++)
385  src[i] = i;
386  }
387 
388  TestCommWorld->scatter(src, dest);
389 
390  for (unsigned int i=0; i<CHUNK_SIZE; i++)
391  CPPUNIT_ASSERT_EQUAL( TestCommWorld->rank() * CHUNK_SIZE + i, dest[i] );
392  }
393 
394  // Test Vector Scatter (jagged chunks)
395  {
396  std::vector<unsigned int> src;
397  std::vector<unsigned int> dest;
398  std::vector<int> counts;
399 
400  if (TestCommWorld->rank() == 0)
401  {
402  // Give each processor "rank" number of items ( Sum i=1..n == (n * (n + 1))/2 )
403  src.resize((TestCommWorld->size() * (TestCommWorld->size() + 1)) / 2);
404  counts.resize(TestCommWorld->size());
405 
406  for (std::size_t i=0; i<src.size(); i++)
407  src[i] = i;
408  for (unsigned int i=0; i<TestCommWorld->size(); i++)
409  counts[i] = static_cast<int>(i+1);
410  }
411 
412  TestCommWorld->scatter(src, counts, dest);
413 
414  unsigned int start_value = (TestCommWorld->rank() * (TestCommWorld->rank() + 1)) / 2;
415  for (unsigned int i=0; i<=TestCommWorld->rank(); i++)
416  CPPUNIT_ASSERT_EQUAL( start_value + i, dest[i] );
417  }
418 
419  // Test Vector of Vector Scatter
420  {
421  std::vector<std::vector<unsigned int>> src;
422  std::vector<unsigned int> dest;
423 
424  if (TestCommWorld->rank() == 0)
425  {
426  // Give each processor "rank" number of items ( Sum i=1..n == (n * (n + 1))/2 )
427  src.resize(TestCommWorld->size());
428  for (std::size_t i=0; i<src.size(); ++i)
429  src[i].resize(i+1);
430 
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++;
435  }
436 
437  TestCommWorld->scatter(src, dest);
438 
439  unsigned int start_value = (TestCommWorld->rank() * (TestCommWorld->rank() + 1)) / 2;
440  for (unsigned int i=0; i<=TestCommWorld->rank(); i++)
441  CPPUNIT_ASSERT_EQUAL( start_value + i, dest[i] );
442  }
443  }
444 
445 
446 
447  void testBarrier()
448  {
449  LOG_UNIT_TEST;
450 
452  }
453 
454 
455 
456  void testMin ()
457  {
458  LOG_UNIT_TEST;
459 
460  unsigned int min = TestCommWorld->rank();
461 
462  TestCommWorld->min(min);
463 
464  CPPUNIT_ASSERT_EQUAL (min, static_cast<unsigned int>(0));
465  }
466 
467 
468 
469  void testMax ()
470  {
471  LOG_UNIT_TEST;
472 
474 
475  TestCommWorld->max(max);
476 
477  CPPUNIT_ASSERT_EQUAL (cast_int<processor_id_type>(max+1),
478  cast_int<processor_id_type>(TestCommWorld->size()));
479  }
480 
481 
482 
483  void testMinloc ()
484  {
485  LOG_UNIT_TEST;
486 
487  int min = (TestCommWorld->rank() + 1) % TestCommWorld->size();
488  unsigned int minid = 0;
489 
490  TestCommWorld->minloc(min, minid);
491 
492  CPPUNIT_ASSERT_EQUAL (min, static_cast<int>(0));
493  CPPUNIT_ASSERT_EQUAL (minid, static_cast<unsigned int>(TestCommWorld->size()-1));
494  }
495 
496 
497 
498  void testMaxloc ()
499  {
500  LOG_UNIT_TEST;
501 
502  int max = TestCommWorld->rank();
503  unsigned int maxid = 0;
504 
505  TestCommWorld->maxloc(max, maxid);
506 
507  CPPUNIT_ASSERT_EQUAL (max+1,
508  cast_int<int>(TestCommWorld->size()));
509  CPPUNIT_ASSERT_EQUAL (maxid, static_cast<unsigned int>(TestCommWorld->size()-1));
510  }
511 
512 
513 
515  {
516  LOG_UNIT_TEST;
517 
518  Real min = (TestCommWorld->rank() + 1) % TestCommWorld->size();
519  unsigned int minid = 0;
520 
521  TestCommWorld->minloc(min, minid);
522 
523  CPPUNIT_ASSERT_EQUAL (min, Real(0));
524  CPPUNIT_ASSERT_EQUAL (minid, static_cast<unsigned int>(TestCommWorld->size()-1));
525  }
526 
527 
528 
530  {
531  LOG_UNIT_TEST;
532 
533  Real max = TestCommWorld->rank();
534  unsigned int maxid = 0;
535 
536  TestCommWorld->maxloc(max, maxid);
537 
538  // Hope nobody uses 1677216 procs with single precision
539  CPPUNIT_ASSERT_EQUAL (max+1, Real(TestCommWorld->size()));
540  CPPUNIT_ASSERT_EQUAL (maxid, static_cast<unsigned int>(TestCommWorld->size()-1));
541  }
542 
543 
544 
546  {
547  LOG_UNIT_TEST;
548 
549  double min = std::numeric_limits<double>::infinity();
550 
551  TestCommWorld->min(min);
552 
553  CPPUNIT_ASSERT_EQUAL (min, std::numeric_limits<double>::infinity());
554 
555  min = -std::numeric_limits<double>::infinity();
556 
557  TestCommWorld->min(min);
558 
559  CPPUNIT_ASSERT_EQUAL (min, -std::numeric_limits<double>::infinity());
560  }
561 
562 
563 
565  {
566  LOG_UNIT_TEST;
567 
568  double max = std::numeric_limits<double>::infinity();
569 
570  TestCommWorld->max(max);
571 
572  CPPUNIT_ASSERT_EQUAL (max, std::numeric_limits<double>::infinity());
573 
574  max = -std::numeric_limits<double>::infinity();
575 
576  TestCommWorld->max(max);
577 
578  CPPUNIT_ASSERT_EQUAL (max, -std::numeric_limits<double>::infinity());
579  }
580 
581 
582 
584  {
585  LOG_UNIT_TEST;
586 
587  unsigned int procup = (TestCommWorld->rank() + 1) %
588  TestCommWorld->size();
589  unsigned int procdown = (TestCommWorld->size() +
590  TestCommWorld->rank() - 1) %
591  TestCommWorld->size();
592 
593  std::vector<unsigned int> src_val(3), recv_val(3);
594 
595  src_val[0] = 0;
596  src_val[1] = 1;
597  src_val[2] = 2;
598 
599  Parallel::Request request;
600 
601  if (TestCommWorld->size() > 1)
602  {
603  // Default communication
605 
606  TestCommWorld->send (procup,
607  src_val,
608  request);
609 
610  TestCommWorld->receive (procdown,
611  recv_val);
612 
613  Parallel::wait (request);
614 
615  CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
616 
617  for (std::size_t i=0; i<src_val.size(); i++)
618  CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
619 
620 
621  // Synchronous communication
623  std::fill (recv_val.begin(), recv_val.end(), 0);
624 
625  TestCommWorld->send (procup,
626  src_val,
627  request);
628 
629  TestCommWorld->receive (procdown,
630  recv_val);
631 
632  Parallel::wait (request);
633 
634  CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
635 
636  for (std::size_t i=0; i<src_val.size(); i++)
637  CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
638 
639  // Restore default communication
641  }
642  }
643 
644 
645 
647  {
648  LOG_UNIT_TEST;
649 
650  unsigned int procup = (TestCommWorld->rank() + 1) %
651  TestCommWorld->size();
652  unsigned int procdown = (TestCommWorld->size() +
653  TestCommWorld->rank() - 1) %
654  TestCommWorld->size();
655 
656  std::vector<unsigned int> src_val(3), recv_val(3);
657 
658  src_val[0] = 0;
659  src_val[1] = 1;
660  src_val[2] = 2;
661 
662  Parallel::Request request;
663 
664  if (TestCommWorld->size() > 1)
665  {
666  // Default communication
668 
669  TestCommWorld->receive (procdown,
670  recv_val,
671  request);
672 
673  TestCommWorld->send (procup,
674  src_val);
675 
676  Parallel::wait (request);
677 
678  CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
679 
680  for (std::size_t i=0; i<src_val.size(); i++)
681  CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
682 
683  // Synchronous communication
685  std::fill (recv_val.begin(), recv_val.end(), 0);
686 
687 
688  TestCommWorld->receive (procdown,
689  recv_val,
690  request);
691 
692  TestCommWorld->send (procup,
693  src_val);
694 
695  Parallel::wait (request);
696 
697  CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
698 
699  for (std::size_t i=0; i<src_val.size(); i++)
700  CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
701 
702  // Restore default communication
704  }
705  }
706 
707 
709  {
710  LOG_UNIT_TEST;
711 
712  unsigned int procup = (TestCommWorld->rank() + 1) %
713  TestCommWorld->size();
714  unsigned int procdown = (TestCommWorld->size() +
715  TestCommWorld->rank() - 1) %
716  TestCommWorld->size();
717 
718  std::set<unsigned int> src_val, recv_val;
719 
720  src_val.insert(4); // Chosen by fair dice roll
721  src_val.insert(42);
722  src_val.insert(1337);
723 
724  Parallel::Request request;
725 
726  if (TestCommWorld->size() > 1)
727  {
728  TestCommWorld->send (procup, src_val, request);
729 
730  TestCommWorld->receive (procdown,
731  recv_val);
732 
733  CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
734 
735  for (std::set<unsigned int>::const_iterator
736  it = src_val.begin(), end = src_val.end(); it != end;
737  ++it)
738  CPPUNIT_ASSERT ( recv_val.count(*it) );
739 
740  Parallel::wait (request);
741 
742  recv_val.clear();
743  }
744  }
745 
746 
747 
749  {
750  LOG_UNIT_TEST;
751 
752  unsigned int procup = (TestCommWorld->rank() + 1) %
753  TestCommWorld->size();
754  unsigned int procdown = (TestCommWorld->size() +
755  TestCommWorld->rank() - 1) %
756  TestCommWorld->size();
757 
758  std::vector<std::vector<unsigned int> > src_val(3), recv_val;
759 
760  src_val[0].push_back(4); // Chosen by fair dice roll
761  src_val[2].push_back(procup);
762  src_val[2].push_back(TestCommWorld->rank());
763 
764  Parallel::Request request;
765 
766  if (TestCommWorld->size() > 1)
767  {
768  TestCommWorld->send (procup, src_val, request);
769 
770  TestCommWorld->receive (procdown,
771  recv_val);
772 
773  CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
774 
775  for (std::size_t i = 0; i != 3; ++i)
776  CPPUNIT_ASSERT_EQUAL ( src_val[i].size(), recv_val[i].size() );
777 
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 );
781 
782  Parallel::wait (request);
783 
784  recv_val.clear();
785  }
786  }
787 
788 
790  {
791  LOG_UNIT_TEST;
792 
793  unsigned int procup = (TestCommWorld->rank() + 1) %
794  TestCommWorld->size();
795  unsigned int procdown = (TestCommWorld->size() +
796  TestCommWorld->rank() - 1) %
797  TestCommWorld->size();
798 
799  // Any odd processor out does nothing
800  if ((TestCommWorld->size() % 2) && procup == 0)
801  return;
802 
803  std::vector<std::vector<unsigned int> > src_val(3), recv_val;
804 
805  src_val[0].push_back(4); // Chosen by fair dice roll
806  src_val[2].push_back(procup);
807  src_val[2].push_back(TestCommWorld->rank());
808 
809  // Other even numbered processors send
810  if (TestCommWorld->rank() % 2 == 0)
811  TestCommWorld->send (procup, src_val);
812  // Other odd numbered processors receive
813  else
814  {
815  TestCommWorld->receive (procdown,
816  recv_val);
817 
818  CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
819 
820  for (std::size_t i = 0; i != 3; ++i)
821  CPPUNIT_ASSERT_EQUAL ( src_val[i].size(), recv_val[i].size() );
822 
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 );
826 
827  recv_val.clear();
828  }
829  }
830 
831 
832 
834  {
835  LOG_UNIT_TEST;
836 
837  double inf = std::numeric_limits<double>::infinity();
838 
839  double *infptr = TestCommWorld->rank()%2 ? NULL : &inf;
840 
841  CPPUNIT_ASSERT (TestCommWorld->semiverify(infptr));
842 
843  inf = -std::numeric_limits<double>::infinity();
844 
845  CPPUNIT_ASSERT (TestCommWorld->semiverify(infptr));
846  }
847 
848 
849  void testSplit ()
850  {
851  LOG_UNIT_TEST;
852 
853  Parallel::Communicator subcomm;
854  unsigned int rank = TestCommWorld->rank();
855  unsigned int color = rank % 2;
856  TestCommWorld->split(color, rank, subcomm);
857 
858  CPPUNIT_ASSERT(subcomm.size() >= 1);
859  CPPUNIT_ASSERT(subcomm.size() >= TestCommWorld->size() / 2);
860  CPPUNIT_ASSERT(subcomm.size() <= TestCommWorld->size() / 2 + 1);
861  }
862 
863 
865  {
866  LOG_UNIT_TEST;
867 
868  Parallel::Communicator subcomm;
869  unsigned int rank = TestCommWorld->rank();
870  Parallel::info i = 0;
871  int type = 0;
872 #ifdef LIBMESH_HAVE_MPI
873  type = MPI_COMM_TYPE_SHARED;
874  i = MPI_INFO_NULL;
875 #endif
876  TestCommWorld->split_by_type(type, rank, i, subcomm);
877 
878  CPPUNIT_ASSERT(subcomm.size() >= 1);
879  CPPUNIT_ASSERT(subcomm.size() <= TestCommWorld->size());
880  }
881 
883  {
884  LOG_UNIT_TEST;
885 
886  const unsigned int requested_threads =
887  (libMesh::n_threads() > 2) ? 2u : 1u;
888  std::vector<unsigned int> values(3);
889  std::iota(values.begin(), values.end(), 0u);
890  const TestRange range(values.cbegin(), values.cend(),
891  /* grainsize */ 1);
892  VisitTracker tracker;
893 
894  Threads::parallel_for(range, ForBody(tracker), requested_threads);
895 
896  assert_tracker_matches_values(tracker, values);
897 
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);
902 #endif
903  }
904 
906  {
907  LOG_UNIT_TEST;
908 
909  const unsigned int requested_threads =
910  (libMesh::n_threads() > 2) ? 2u : 1u;
911  std::vector<unsigned int> values(3);
912  std::iota(values.begin(), values.end(), 0u);
913  const TestRange range(values.cbegin(), values.cend(),
914  /* grainsize */ 1);
915  auto tracker = std::make_shared<VisitTracker>();
916  ReduceBody body(tracker);
917 
918  Threads::parallel_reduce(range, body, requested_threads);
919 
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);
924 
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);
929 #endif
930  }
931 
932 #if defined(LIBMESH_ENABLE_EXCEPTIONS)
934  {
935  LOG_UNIT_TEST;
936 
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);
943 
944  CPPUNIT_ASSERT_THROW(Threads::parallel_for(range,
945  ForBody(for_tracker),
946  libMesh::n_threads() + 1u),
948  CPPUNIT_ASSERT_THROW(Threads::parallel_reduce(range,
949  reduce_body,
950  libMesh::n_threads() + 1u),
952  }
953 #endif
954 };
955 
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.
Definition: threads_none.h:73
MPI_Request request
void send_mode(const SendMode sm)
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
void testAllGatherHalfEmptyVectorString()
void testIsendRecv()
void testAllGatherEmptyVectorString()
void testBarrier()
unsigned int n_threads()
Definition: libmesh_base.h:109
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
Definition: driver.C:218
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.
Definition: threads_none.h:63
void testScatter()
void testParallelReduceThreadSubset()
void barrier() const
void testAllGatherString()
processor_id_type rank() const
void testSplitByType()
void testRequestedThreadCountExceedsGlobal()
The StoredRange class defines a contiguous, divisible set of objects.
Definition: stored_range.h:54
void testBroadcastNestedType()
The libMesh namespace provides an interface to certain functionality in the library.
void testAllGatherHalfEmptyVectorString()
void testBroadcast()
void testParallelForThreadSubset()
void testIrecvSend()
void testIrecvSend()
void testRecvIsendVecVecs()
void testSplit()
void testAllGatherString()
void testSendRecvVecVecs()
void testRecvIsendSets()
processor_id_type size() const
uint8_t processor_id_type
void testMinlocReal()
Status receive(const unsigned int dest_processor_id, T &buf, const MessageTag &tag=any_tag) const
void testMin()
void min(const T &r, T &o, Request &req) const
void testGatherString()
void testScatter()
void testAllGatherVectorString()
void testGather()
void testAllGatherVectorString()
void split(int color, int key, Communicator &target) const
void testRecvIsendSets()
void testMaxloc()
void maxloc(T &r, unsigned int &max_id) const
timpi_pure bool semiverify(const T *r) const
void testMinloc()
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
void testMinloc()
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.
Definition: threads_none.h:109
void testSemiVerify()
void testInfinityMin()
void testMaxlocReal()
void testInfinityMax()
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void testAllGather()
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 testMaxloc()
void testIsendRecv()
void send(const unsigned int dest_processor_id, const T &buf, const MessageTag &tag=no_tag) const
void testInfinityMax()
static const bool value
Definition: xdr_io.C:55
void testGather()
void testMax()
void testBarrier()
void testSplit()
CPPUNIT_TEST_SUITE_REGISTRATION(ParallelTest)
void testInfinityMin()
void testRecvIsendVecVecs()
void testSendRecvVecVecs()
void testAllGather()
void testGatherString()
std::vector< std::string > _number