libMesh
Loading...
Searching...
No Matches
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// The OpenMP team cap these tests exercise (the num_threads(actual_threads)
14// clause on the parallel-for pragmas in threads_pthread.h) only exists in the
15// pthread threading backend's OpenMP code path. TBB provides its own
16// parallel_for/parallel_reduce and the no-threads backend never spawns a team,
17// so there is nothing to check in those configurations.
18#if defined(LIBMESH_HAVE_OPENMP) && defined(LIBMESH_HAVE_PTHREAD) && !defined(LIBMESH_HAVE_TBB_API)
19# define LIBMESH_TEST_OPENMP_TEAM_CAP 1
20# include <omp.h>
21#endif
22
23
24using namespace libMesh;
25
26namespace {
27
28using TestRange = StoredRange<std::vector<unsigned int>::const_iterator, unsigned int>;
29
30// Shared helper state for the thread-subset tests. Each body records how many
31// subrange invocations happened, which thread ids executed them, and a few
32// simple aggregate checksums so we can verify every input value was visited.
33struct VisitTracker
34{
35 void record_invocation()
36 {
37 invocations.fetch_add(1, std::memory_order_relaxed);
38
39 Threads::spin_mutex::scoped_lock lock(mutex);
40 thread_ids.insert(std::this_thread::get_id());
41#ifdef LIBMESH_TEST_OPENMP_TEAM_CAP
42 // Capture the OpenMP team size and this thread's id from *inside* the
43 // parallel region, so the tests can confirm the team was capped at the
44 // requested per-dispatch count rather than the process-wide n_threads().
45 openmp_team_sizes.insert(omp_get_num_threads());
46 openmp_thread_ids.insert(omp_get_thread_num());
47#endif
48 }
49
50 void record_value(const unsigned int value)
51 {
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);
55 }
56
57 std::size_t unique_thread_count() const
58 {
59 Threads::spin_mutex::scoped_lock lock(mutex);
60 return thread_ids.size();
61 }
62
63#ifdef LIBMESH_TEST_OPENMP_TEAM_CAP
64 std::set<int> openmp_teams() const
65 {
66 Threads::spin_mutex::scoped_lock lock(mutex);
67 return openmp_team_sizes;
68 }
69
70 std::set<int> openmp_tids() const
71 {
72 Threads::spin_mutex::scoped_lock lock(mutex);
73 return openmp_thread_ids;
74 }
75#endif
76
77 mutable Threads::spin_mutex mutex;
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;
86#endif
87};
88
89// Compare the aggregates collected by VisitTracker against the known test
90// input values. Using count/sum/sum-of-squares gives us a compact way to catch
91// dropped or duplicated work without depending on any particular scheduling.
92void assert_tracker_matches_values(const VisitTracker & tracker,
93 const std::vector<unsigned int> & values)
94{
95 unsigned int expected_sum = 0;
96 unsigned int expected_sum_sq = 0;
97
98 for (const auto value : values)
99 {
100 expected_sum += value;
101 expected_sum_sq += value * value;
102 }
103
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));
110}
111
112#ifdef LIBMESH_TEST_OPENMP_TEAM_CAP
113// Verify the OpenMP team the dispatch ran on was capped at the number of
114// threads that dispatch requested. Without the num_threads(actual_threads)
115// clause on the pragma, the team defaults to the process-wide
116// libMesh::n_threads(), so omp_get_num_threads() would report that larger
117// count and omp_get_thread_num() could exceed the reduced per-dispatch count
118// and index past per-thread storage sized to it.
119void assert_openmp_team_within(const VisitTracker & tracker,
120 const unsigned int requested_threads)
121{
122 const std::set<int> teams = tracker.openmp_teams();
123 CPPUNIT_ASSERT(!teams.empty());
124
125 // The runtime is allowed to hand us fewer threads than requested (e.g. with
126 // OpenMP dynamic adjustment enabled), but it must never exceed the cap.
127 for (const int team : teams)
128 {
129 CPPUNIT_ASSERT(team >= 1);
130 CPPUNIT_ASSERT(team <= static_cast<int>(requested_threads));
131 }
132
133 // Every thread id observed must be a valid index into per-thread storage
134 // sized to the (capped) team.
135 for (const int tid : tracker.openmp_tids())
136 {
137 CPPUNIT_ASSERT(tid >= 0);
138 CPPUNIT_ASSERT(tid < static_cast<int>(requested_threads));
139 }
140}
141#endif
142
143struct ForBody
144{
145 explicit ForBody(VisitTracker & tracker_in) : tracker(tracker_in) {}
146
147 void operator()(const TestRange & range) const
148 {
149 tracker.record_invocation();
150
151 for (const auto value : range)
152 tracker.record_value(value);
153 }
154
155 VisitTracker & tracker;
156};
157
158struct ReduceBody
159{
160 explicit ReduceBody(std::shared_ptr<VisitTracker> tracker_in) :
161 tracker(std::move(tracker_in))
162 {}
163
164 ReduceBody(ReduceBody & other, Threads::split) :
165 tracker(other.tracker)
166 {}
167
168 void operator()(const TestRange & range)
169 {
170 tracker->record_invocation();
171
172 for (const auto value : range)
173 {
174 ++value_count;
175 value_sum += value;
176 value_sum_sq += value * value;
177 tracker->record_value(value);
178 }
179 }
180
181 void join(const ReduceBody & other)
182 {
183 value_count += other.value_count;
184 value_sum += other.value_sum;
185 value_sum_sq += other.value_sum_sq;
186 }
187
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;
192};
193
194} // anonymous namespace
195
196class ParallelTest : public CppUnit::TestCase {
197public:
199
228#if defined(LIBMESH_ENABLE_EXCEPTIONS)
230#endif
231#ifdef LIBMESH_TEST_OPENMP_TEAM_CAP
234#endif
235
237
238private:
239 std::vector<std::string> _number;
240
241public:
242 void setUp()
243 {
244 _number.resize(10);
245 _number[0] = "Zero";
246 _number[1] = "One";
247 _number[2] = "Two";
248 _number[3] = "Three";
249 _number[4] = "Four";
250 _number[5] = "Five";
251 _number[6] = "Six";
252 _number[7] = "Seven";
253 _number[8] = "Eight";
254 _number[9] = "Nine";
255 }
256
257 void tearDown()
258 {}
259
260
261
263 {
264 LOG_UNIT_TEST;
265
266 std::vector<processor_id_type> vals;
267 TestCommWorld->gather(0,cast_int<processor_id_type>(TestCommWorld->rank()),vals);
268
269 if (TestCommWorld->rank() == 0)
270 for (processor_id_type i=0; i<vals.size(); i++)
271 CPPUNIT_ASSERT_EQUAL( i , vals[i] );
272 }
273
274
275
277 {
278 LOG_UNIT_TEST;
279
280 std::vector<std::string> vals;
281 TestCommWorld->gather(0, "Processor" + _number[TestCommWorld->rank() % 10], vals);
282
283 if (TestCommWorld->rank() == 0)
284 for (processor_id_type i=0; i<vals.size(); i++)
285 CPPUNIT_ASSERT_EQUAL( "Processor" + _number[i % 10] , vals[i] );
286 }
287
288
289
291 {
292 LOG_UNIT_TEST;
293
294 std::vector<processor_id_type> vals;
295 TestCommWorld->allgather(cast_int<processor_id_type>(TestCommWorld->rank()),vals);
296
297 for (processor_id_type i=0; i<vals.size(); i++)
298 CPPUNIT_ASSERT_EQUAL( i , vals[i] );
299 }
300
301
302
304 {
305 LOG_UNIT_TEST;
306
307 std::vector<std::string> vals;
308 TestCommWorld->gather(0, "Processor" + _number[TestCommWorld->rank() % 10], vals);
309
310 for (processor_id_type i=0; i<vals.size(); i++)
311 CPPUNIT_ASSERT_EQUAL( "Processor" + _number[i % 10] , vals[i] );
312 }
313
314
315
317 {
318 LOG_UNIT_TEST;
319
320 std::vector<std::string> vals;
321 vals.push_back("Processor" + _number[TestCommWorld->rank() % 10] + "A");
322 vals.push_back("Processor" + _number[TestCommWorld->rank() % 10] + "B");
323 TestCommWorld->allgather(vals);
324
325 for (processor_id_type i=0; i<(vals.size()/2); i++)
326 {
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] );
329 }
330 }
331
332
333
335 {
336 LOG_UNIT_TEST;
337
338 std::vector<std::string> vals;
339 TestCommWorld->allgather(vals);
340
341 CPPUNIT_ASSERT( vals.empty() );
342 }
343
344
345
347 {
348 LOG_UNIT_TEST;
349
350 std::vector<std::string> vals;
351
352 if (!TestCommWorld->rank())
353 vals.push_back("Proc 0 only");
354
355 TestCommWorld->allgather(vals);
356
357 CPPUNIT_ASSERT_EQUAL( vals[0], std::string("Proc 0 only") );
358 }
359
360
361
363 {
364 LOG_UNIT_TEST;
365
366 // Workaround for spurious warning from operator=
367 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100366
368 std::vector<unsigned int> src{0,1,2}, dest(3,0);
369
370 if (TestCommWorld->rank() == 0)
371 dest = src;
372
373 TestCommWorld->broadcast(dest);
374
375 for (std::size_t i=0; i<3; i++)
376 CPPUNIT_ASSERT_EQUAL( src[i] , dest[i] );
377 }
378
379
380
382 {
383 LOG_UNIT_TEST;
384
385 using std::pair;
386 typedef pair<pair<pair<pair<int, int>, int>, int>, int> pppp;
387 std::vector<pppp> src(3), dest(3);
388
389 src[0].first.first.first.first=0;
390 src[0].first.first.first.second=-1;
391 src[0].first.second = -2;
392 src[0].second = -3;
393 src[1].first.first.first.first=10;
394 src[1].first.first.first.second=9;
395 src[1].first.second = 8;
396 src[1].second = 7;
397 src[2].first.first.first.first=20;
398 src[2].first.first.first.second=19;
399 src[2].first.second = 18;
400 src[2].second = 17;
401
402 if (TestCommWorld->rank() == 0)
403 dest = src;
404
405 TestCommWorld->broadcast(dest);
406
407 for (std::size_t i=0; i<src.size(); i++)
408 {
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,
418 dest[i].second);
419 }
420 }
421
422
423
425 {
426 LOG_UNIT_TEST;
427
428 // Test Scalar scatter
429 {
430 std::vector<processor_id_type> src;
432
433 if (TestCommWorld->rank() == 0)
434 {
435 src.resize(TestCommWorld->size());
436 for (processor_id_type i=0; i<src.size(); i++)
437 src[i] = i;
438 }
439
440 TestCommWorld->scatter(src, dest);
441
442 CPPUNIT_ASSERT_EQUAL( TestCommWorld->rank(), dest );
443 }
444
445 // Test Vector Scatter (equal-sized chunks)
446 {
447 std::vector<unsigned int> src;
448 std::vector<unsigned int> dest;
449 static const unsigned int CHUNK_SIZE = 3;
450
451 if (TestCommWorld->rank() == 0)
452 {
453 src.resize(TestCommWorld->size() * CHUNK_SIZE);
454 for (std::size_t i=0; i<src.size(); i++)
455 src[i] = i;
456 }
457
458 TestCommWorld->scatter(src, dest);
459
460 for (unsigned int i=0; i<CHUNK_SIZE; i++)
461 CPPUNIT_ASSERT_EQUAL( TestCommWorld->rank() * CHUNK_SIZE + i, dest[i] );
462 }
463
464 // Test Vector Scatter (jagged chunks)
465 {
466 std::vector<unsigned int> src;
467 std::vector<unsigned int> dest;
468 std::vector<int> counts;
469
470 if (TestCommWorld->rank() == 0)
471 {
472 // Give each processor "rank" number of items ( Sum i=1..n == (n * (n + 1))/2 )
473 src.resize((TestCommWorld->size() * (TestCommWorld->size() + 1)) / 2);
474 counts.resize(TestCommWorld->size());
475
476 for (std::size_t i=0; i<src.size(); i++)
477 src[i] = i;
478 for (unsigned int i=0; i<TestCommWorld->size(); i++)
479 counts[i] = static_cast<int>(i+1);
480 }
481
482 TestCommWorld->scatter(src, counts, dest);
483
484 unsigned int start_value = (TestCommWorld->rank() * (TestCommWorld->rank() + 1)) / 2;
485 for (unsigned int i=0; i<=TestCommWorld->rank(); i++)
486 CPPUNIT_ASSERT_EQUAL( start_value + i, dest[i] );
487 }
488
489 // Test Vector of Vector Scatter
490 {
491 std::vector<std::vector<unsigned int>> src;
492 std::vector<unsigned int> dest;
493
494 if (TestCommWorld->rank() == 0)
495 {
496 // Give each processor "rank" number of items ( Sum i=1..n == (n * (n + 1))/2 )
497 src.resize(TestCommWorld->size());
498 for (std::size_t i=0; i<src.size(); ++i)
499 src[i].resize(i+1);
500
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++;
505 }
506
507 TestCommWorld->scatter(src, dest);
508
509 unsigned int start_value = (TestCommWorld->rank() * (TestCommWorld->rank() + 1)) / 2;
510 for (unsigned int i=0; i<=TestCommWorld->rank(); i++)
511 CPPUNIT_ASSERT_EQUAL( start_value + i, dest[i] );
512 }
513 }
514
515
516
518 {
519 LOG_UNIT_TEST;
520
521 TestCommWorld->barrier();
522 }
523
524
525
526 void testMin ()
527 {
528 LOG_UNIT_TEST;
529
530 unsigned int min = TestCommWorld->rank();
531
532 TestCommWorld->min(min);
533
534 CPPUNIT_ASSERT_EQUAL (min, static_cast<unsigned int>(0));
535 }
536
537
538
539 void testMax ()
540 {
541 LOG_UNIT_TEST;
542
543 processor_id_type max = TestCommWorld->rank();
544
545 TestCommWorld->max(max);
546
547 CPPUNIT_ASSERT_EQUAL (cast_int<processor_id_type>(max+1),
548 cast_int<processor_id_type>(TestCommWorld->size()));
549 }
550
551
552
554 {
555 LOG_UNIT_TEST;
556
557 int min = (TestCommWorld->rank() + 1) % TestCommWorld->size();
558 unsigned int minid = 0;
559
560 TestCommWorld->minloc(min, minid);
561
562 CPPUNIT_ASSERT_EQUAL (min, static_cast<int>(0));
563 CPPUNIT_ASSERT_EQUAL (minid, static_cast<unsigned int>(TestCommWorld->size()-1));
564 }
565
566
567
569 {
570 LOG_UNIT_TEST;
571
572 int max = TestCommWorld->rank();
573 unsigned int maxid = 0;
574
575 TestCommWorld->maxloc(max, maxid);
576
577 CPPUNIT_ASSERT_EQUAL (max+1,
578 cast_int<int>(TestCommWorld->size()));
579 CPPUNIT_ASSERT_EQUAL (maxid, static_cast<unsigned int>(TestCommWorld->size()-1));
580 }
581
582
583
585 {
586 LOG_UNIT_TEST;
587
588 Real min = (TestCommWorld->rank() + 1) % TestCommWorld->size();
589 unsigned int minid = 0;
590
591 TestCommWorld->minloc(min, minid);
592
593 CPPUNIT_ASSERT_EQUAL (min, Real(0));
594 CPPUNIT_ASSERT_EQUAL (minid, static_cast<unsigned int>(TestCommWorld->size()-1));
595 }
596
597
598
600 {
601 LOG_UNIT_TEST;
602
603 Real max = TestCommWorld->rank();
604 unsigned int maxid = 0;
605
606 TestCommWorld->maxloc(max, maxid);
607
608 // Hope nobody uses 1677216 procs with single precision
609 CPPUNIT_ASSERT_EQUAL (max+1, Real(TestCommWorld->size()));
610 CPPUNIT_ASSERT_EQUAL (maxid, static_cast<unsigned int>(TestCommWorld->size()-1));
611 }
612
613
614
616 {
617 LOG_UNIT_TEST;
618
619 double min = std::numeric_limits<double>::infinity();
620
621 TestCommWorld->min(min);
622
623 CPPUNIT_ASSERT_EQUAL (min, std::numeric_limits<double>::infinity());
624
625 min = -std::numeric_limits<double>::infinity();
626
627 TestCommWorld->min(min);
628
629 CPPUNIT_ASSERT_EQUAL (min, -std::numeric_limits<double>::infinity());
630 }
631
632
633
635 {
636 LOG_UNIT_TEST;
637
638 double max = std::numeric_limits<double>::infinity();
639
640 TestCommWorld->max(max);
641
642 CPPUNIT_ASSERT_EQUAL (max, std::numeric_limits<double>::infinity());
643
644 max = -std::numeric_limits<double>::infinity();
645
646 TestCommWorld->max(max);
647
648 CPPUNIT_ASSERT_EQUAL (max, -std::numeric_limits<double>::infinity());
649 }
650
651
652
654 {
655 LOG_UNIT_TEST;
656
657 unsigned int procup = (TestCommWorld->rank() + 1) %
658 TestCommWorld->size();
659 unsigned int procdown = (TestCommWorld->size() +
660 TestCommWorld->rank() - 1) %
661 TestCommWorld->size();
662
663 std::vector<unsigned int> src_val(3), recv_val(3);
664
665 src_val[0] = 0;
666 src_val[1] = 1;
667 src_val[2] = 2;
668
669 Parallel::Request request;
670
671 if (TestCommWorld->size() > 1)
672 {
673 // Default communication
675
676 TestCommWorld->send (procup,
677 src_val,
678 request);
679
680 TestCommWorld->receive (procdown,
681 recv_val);
682
683 Parallel::wait (request);
684
685 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
686
687 for (std::size_t i=0; i<src_val.size(); i++)
688 CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
689
690
691 // Synchronous communication
693 std::fill (recv_val.begin(), recv_val.end(), 0);
694
695 TestCommWorld->send (procup,
696 src_val,
697 request);
698
699 TestCommWorld->receive (procdown,
700 recv_val);
701
702 Parallel::wait (request);
703
704 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
705
706 for (std::size_t i=0; i<src_val.size(); i++)
707 CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
708
709 // Restore default communication
711 }
712 }
713
714
715
717 {
718 LOG_UNIT_TEST;
719
720 unsigned int procup = (TestCommWorld->rank() + 1) %
721 TestCommWorld->size();
722 unsigned int procdown = (TestCommWorld->size() +
723 TestCommWorld->rank() - 1) %
724 TestCommWorld->size();
725
726 std::vector<unsigned int> src_val(3), recv_val(3);
727
728 src_val[0] = 0;
729 src_val[1] = 1;
730 src_val[2] = 2;
731
732 Parallel::Request request;
733
734 if (TestCommWorld->size() > 1)
735 {
736 // Default communication
738
739 TestCommWorld->receive (procdown,
740 recv_val,
741 request);
742
743 TestCommWorld->send (procup,
744 src_val);
745
746 Parallel::wait (request);
747
748 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
749
750 for (std::size_t i=0; i<src_val.size(); i++)
751 CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
752
753 // Synchronous communication
755 std::fill (recv_val.begin(), recv_val.end(), 0);
756
757
758 TestCommWorld->receive (procdown,
759 recv_val,
760 request);
761
762 TestCommWorld->send (procup,
763 src_val);
764
765 Parallel::wait (request);
766
767 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
768
769 for (std::size_t i=0; i<src_val.size(); i++)
770 CPPUNIT_ASSERT_EQUAL( src_val[i] , recv_val[i] );
771
772 // Restore default communication
774 }
775 }
776
777
779 {
780 LOG_UNIT_TEST;
781
782 unsigned int procup = (TestCommWorld->rank() + 1) %
783 TestCommWorld->size();
784 unsigned int procdown = (TestCommWorld->size() +
785 TestCommWorld->rank() - 1) %
786 TestCommWorld->size();
787
788 std::set<unsigned int> src_val, recv_val;
789
790 src_val.insert(4); // Chosen by fair dice roll
791 src_val.insert(42);
792 src_val.insert(1337);
793
794 Parallel::Request request;
795
796 if (TestCommWorld->size() > 1)
797 {
798 TestCommWorld->send (procup, src_val, request);
799
800 TestCommWorld->receive (procdown,
801 recv_val);
802
803 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
804
805 for (std::set<unsigned int>::const_iterator
806 it = src_val.begin(), end = src_val.end(); it != end;
807 ++it)
808 CPPUNIT_ASSERT ( recv_val.count(*it) );
809
810 Parallel::wait (request);
811
812 recv_val.clear();
813 }
814 }
815
816
817
819 {
820 LOG_UNIT_TEST;
821
822 unsigned int procup = (TestCommWorld->rank() + 1) %
823 TestCommWorld->size();
824 unsigned int procdown = (TestCommWorld->size() +
825 TestCommWorld->rank() - 1) %
826 TestCommWorld->size();
827
828 std::vector<std::vector<unsigned int> > src_val(3), recv_val;
829
830 src_val[0].push_back(4); // Chosen by fair dice roll
831 src_val[2].push_back(procup);
832 src_val[2].push_back(TestCommWorld->rank());
833
834 Parallel::Request request;
835
836 if (TestCommWorld->size() > 1)
837 {
838 TestCommWorld->send (procup, src_val, request);
839
840 TestCommWorld->receive (procdown,
841 recv_val);
842
843 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
844
845 for (std::size_t i = 0; i != 3; ++i)
846 CPPUNIT_ASSERT_EQUAL ( src_val[i].size(), recv_val[i].size() );
847
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 );
851
852 Parallel::wait (request);
853
854 recv_val.clear();
855 }
856 }
857
858
860 {
861 LOG_UNIT_TEST;
862
863 unsigned int procup = (TestCommWorld->rank() + 1) %
864 TestCommWorld->size();
865 unsigned int procdown = (TestCommWorld->size() +
866 TestCommWorld->rank() - 1) %
867 TestCommWorld->size();
868
869 // Any odd processor out does nothing
870 if ((TestCommWorld->size() % 2) && procup == 0)
871 return;
872
873 std::vector<std::vector<unsigned int> > src_val(3), recv_val;
874
875 src_val[0].push_back(4); // Chosen by fair dice roll
876 src_val[2].push_back(procup);
877 src_val[2].push_back(TestCommWorld->rank());
878
879 // Other even numbered processors send
880 if (TestCommWorld->rank() % 2 == 0)
881 TestCommWorld->send (procup, src_val);
882 // Other odd numbered processors receive
883 else
884 {
885 TestCommWorld->receive (procdown,
886 recv_val);
887
888 CPPUNIT_ASSERT_EQUAL ( src_val.size() , recv_val.size() );
889
890 for (std::size_t i = 0; i != 3; ++i)
891 CPPUNIT_ASSERT_EQUAL ( src_val[i].size(), recv_val[i].size() );
892
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 );
896
897 recv_val.clear();
898 }
899 }
900
901
902
904 {
905 LOG_UNIT_TEST;
906
907 double inf = std::numeric_limits<double>::infinity();
908
909 double *infptr = TestCommWorld->rank()%2 ? NULL : &inf;
910
911 CPPUNIT_ASSERT (TestCommWorld->semiverify(infptr));
912
913 inf = -std::numeric_limits<double>::infinity();
914
915 CPPUNIT_ASSERT (TestCommWorld->semiverify(infptr));
916 }
917
918
919 void testSplit ()
920 {
921 LOG_UNIT_TEST;
922
924 unsigned int rank = TestCommWorld->rank();
925 unsigned int color = rank % 2;
926 TestCommWorld->split(color, rank, subcomm);
927
928 CPPUNIT_ASSERT(subcomm.size() >= 1);
929 CPPUNIT_ASSERT(subcomm.size() >= TestCommWorld->size() / 2);
930 CPPUNIT_ASSERT(subcomm.size() <= TestCommWorld->size() / 2 + 1);
931 }
932
933
935 {
936 LOG_UNIT_TEST;
937
939 unsigned int rank = TestCommWorld->rank();
940 Parallel::info i = 0;
941 int type = 0;
942#ifdef LIBMESH_HAVE_MPI
943 type = MPI_COMM_TYPE_SHARED;
944 i = MPI_INFO_NULL;
945#endif
946 TestCommWorld->split_by_type(type, rank, i, subcomm);
947
948 CPPUNIT_ASSERT(subcomm.size() >= 1);
949 CPPUNIT_ASSERT(subcomm.size() <= TestCommWorld->size());
950 }
951
953 {
954 LOG_UNIT_TEST;
955
956 const unsigned int requested_threads =
957 (libMesh::n_threads() > 2) ? 2u : 1u;
958 std::vector<unsigned int> values(3);
959 std::iota(values.begin(), values.end(), 0u);
960 const TestRange range(values.cbegin(), values.cend(),
961 /* grainsize */ 1);
962 VisitTracker tracker;
963
964 Threads::parallel_for(range, ForBody(tracker), requested_threads);
965
966 assert_tracker_matches_values(tracker, values);
967
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);
972#endif
973 }
974
976 {
977 LOG_UNIT_TEST;
978
979 const unsigned int requested_threads =
980 (libMesh::n_threads() > 2) ? 2u : 1u;
981 std::vector<unsigned int> values(3);
982 std::iota(values.begin(), values.end(), 0u);
983 const TestRange range(values.cbegin(), values.cend(),
984 /* grainsize */ 1);
985 auto tracker = std::make_shared<VisitTracker>();
986 ReduceBody body(tracker);
987
988 Threads::parallel_reduce(range, body, requested_threads);
989
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);
994
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);
999#endif
1000 }
1001
1002#if defined(LIBMESH_ENABLE_EXCEPTIONS)
1004 {
1005 LOG_UNIT_TEST;
1006
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);
1013
1014 CPPUNIT_ASSERT_THROW(Threads::parallel_for(range,
1015 ForBody(for_tracker),
1016 libMesh::n_threads() + 1u),
1018 CPPUNIT_ASSERT_THROW(Threads::parallel_reduce(range,
1019 reduce_body,
1020 libMesh::n_threads() + 1u),
1022 }
1023#endif
1024
1025#ifdef LIBMESH_TEST_OPENMP_TEAM_CAP
1027 {
1028 LOG_UNIT_TEST;
1029
1030 // parallel_for only enters the OpenMP region when it uses more than one
1031 // thread; with a single global thread it short-circuits to a serial call
1032 // and there is no team to inspect.
1033 if (libMesh::n_threads() < 2)
1034 return;
1035
1036 // Requesting two threads exercises a strict subset whenever the run has
1037 // more than two threads available -- exactly the case in which an uncapped
1038 // team (the bug) would differ from the count we asked for.
1039 const unsigned int requested_threads = 2u;
1040
1041 // Grainsize 1 with more values than threads makes actual_threads ==
1042 // requested_threads, so the team we expect is precisely requested_threads.
1043 std::vector<unsigned int> values(16);
1044 std::iota(values.begin(), values.end(), 0u);
1045 const TestRange range(values.cbegin(), values.cend(),
1046 /* grainsize */ 1);
1047 VisitTracker tracker;
1048
1049 Threads::parallel_for(range, ForBody(tracker), requested_threads);
1050
1051 assert_tracker_matches_values(tracker, values);
1052 assert_openmp_team_within(tracker, requested_threads);
1053 }
1054
1056 {
1057 LOG_UNIT_TEST;
1058
1059 if (libMesh::n_threads() < 2)
1060 return;
1061
1062 const unsigned int requested_threads = 2u;
1063
1064 std::vector<unsigned int> values(16);
1065 std::iota(values.begin(), values.end(), 0u);
1066 const TestRange range(values.cbegin(), values.cend(),
1067 /* grainsize */ 1);
1068 auto tracker = std::make_shared<VisitTracker>();
1069 ReduceBody body(tracker);
1070
1071 Threads::parallel_reduce(range, body, requested_threads);
1072
1073 assert_tracker_matches_values(*tracker, values);
1074 assert_openmp_team_within(*tracker, requested_threads);
1075 }
1076#endif
1077};
1078
void testAllGatherVectorString()
void testAllGatherEmptyVectorString()
CPPUNIT_TEST(testBroadcastNestedType)
CPPUNIT_TEST(testScatter)
void testParallelForOpenMPTeamCap()
CPPUNIT_TEST_SUITE_END()
CPPUNIT_TEST(testAllGather)
CPPUNIT_TEST(testMaxloc)
CPPUNIT_TEST(testMinlocReal)
CPPUNIT_TEST(testAllGatherVectorString)
void testAllGatherHalfEmptyVectorString()
CPPUNIT_TEST(testMinloc)
void testRecvIsendVecVecs()
void testInfinityMax()
CPPUNIT_TEST(testMin)
void testAllGatherString()
CPPUNIT_TEST(testInfinityMin)
void testGatherString()
CPPUNIT_TEST(testAllGatherHalfEmptyVectorString)
void testParallelReduceThreadSubset()
CPPUNIT_TEST(testSemiVerify)
void testMinlocReal()
void testParallelForThreadSubset()
CPPUNIT_TEST(testRecvIsendVecVecs)
CPPUNIT_TEST(testSendRecvVecVecs)
CPPUNIT_TEST(testMax)
void testBroadcastNestedType()
CPPUNIT_TEST(testGather)
CPPUNIT_TEST(testInfinityMax)
CPPUNIT_TEST(testIrecvSend)
CPPUNIT_TEST(testAllGatherEmptyVectorString)
CPPUNIT_TEST(testGatherString)
void testInfinityMin()
CPPUNIT_TEST(testRecvIsendSets)
void testSendRecvVecVecs()
CPPUNIT_TEST(testAllGatherString)
CPPUNIT_TEST(testIsendRecv)
CPPUNIT_TEST(testRequestedThreadCountExceedsGlobal)
void testSemiVerify()
void testParallelReduceOpenMPTeamCap()
CPPUNIT_TEST(testParallelForThreadSubset)
void testMaxlocReal()
CPPUNIT_TEST(testBroadcast)
std::vector< std::string > _number
CPPUNIT_TEST(testParallelForOpenMPTeamCap)
void testIrecvSend()
void testRequestedThreadCountExceedsGlobal()
CPPUNIT_TEST(testParallelReduceOpenMPTeamCap)
CPPUNIT_TEST(testParallelReduceThreadSubset)
void testSplitByType()
CPPUNIT_TEST(testMaxlocReal)
void testIsendRecv()
void testAllGather()
LIBMESH_CPPUNIT_TEST_SUITE(ParallelTest)
void testRecvIsendSets()
CPPUNIT_TEST(testSplit)
void testBroadcast()
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
MPI_Info info
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
Definition id_types.h:104
unsigned int n_threads()
CPPUNIT_TEST_SUITE_REGISTRATION(ParallelTest)
static const bool value
Definition xdr_io.C:55