1 /* 2 Copyright (c) 2005-2021 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #include "common/parallel_for_each_common.h" 18 #include "common/concepts_common.h" 19 #include <vector> 20 #include <iterator> 21 22 //! \file test_parallel_for_each.cpp 23 //! \brief Test for [algorithms.parallel_for_each] 24 25 //! Test forward access iterator support 26 //! \brief \ref error_guessing \ref interface 27 TEST_CASE("Forward iterator support") { 28 for ( auto concurrency_level : utils::concurrency_range() ) { 29 tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level); 30 for(size_t depth = 0; depth <= depths_nubmer; ++depth) { 31 g_tasks_expected = 0; 32 for (size_t i=0; i < depth; ++i) 33 g_tasks_expected += FindNumOfTasks(g_depths[i].value()); 34 TestIterator_Modifiable<utils::ForwardIterator<value_t>>(depth); 35 } 36 } 37 } 38 39 //! Test random access iterator support 40 //! \brief \ref error_guessing \ref interface 41 TEST_CASE("Random access iterator support") { 42 for ( auto concurrency_level : utils::concurrency_range() ) { 43 tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level); 44 for(size_t depth = 0; depth <= depths_nubmer; ++depth) { 45 g_tasks_expected = 0; 46 for (size_t i=0; i < depth; ++i) 47 g_tasks_expected += FindNumOfTasks(g_depths[i].value()); 48 TestIterator_Modifiable<value_t*>(depth); 49 } 50 } 51 } 52 53 //! Test const random access iterator support 54 //! \brief \ref error_guessing \ref interface 55 TEST_CASE("Const random access iterator support") { 56 for ( auto concurrency_level : utils::concurrency_range() ) { 57 tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level); 58 for(size_t depth = 0; depth <= depths_nubmer; ++depth) { 59 g_tasks_expected = 0; 60 for (size_t i=0; i < depth; ++i) 61 g_tasks_expected += FindNumOfTasks(g_depths[i].value()); 62 TestIterator_Const<utils::ConstRandomIterator<value_t>>(depth); 63 } 64 } 65 66 } 67 68 //! Test container based overload 69 //! \brief \ref error_guessing \ref interface 70 TEST_CASE("Container based overload - forward iterator based container") { 71 container_based_overload_test_case<utils::ForwardIterator>(/*expected_value*/1); 72 } 73 74 //! Test container based overload 75 //! \brief \ref error_guessing \ref interface 76 TEST_CASE("Container based overload - random access iterator based container") { 77 container_based_overload_test_case<utils::RandomIterator>(/*expected_value*/1); 78 } 79 80 // Test for iterators over values convertible to work item type 81 //! \brief \ref error_guessing \ref interface 82 TEST_CASE("Using with values convertible to work item type") { 83 for ( auto concurrency_level : utils::concurrency_range() ) { 84 tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level); 85 using Iterator = size_t*; 86 for(size_t depth = 0; depth <= depths_nubmer; ++depth) { 87 g_tasks_expected = 0; 88 for (size_t i=0; i < depth; ++i) 89 g_tasks_expected += FindNumOfTasks(g_depths[i].value()); 90 // Test for iterators over values convertible to work item type 91 TestIterator_Common<Iterator>(depth); 92 TestBody<FakeTaskGeneratorBody_RvalueRefVersion, Iterator>(depth); 93 TestBody<TaskGeneratorBody_RvalueRefVersion, Iterator>(depth); 94 } 95 } 96 } 97 98 //! Testing workers going to sleep 99 //! \brief \ref resource_usage \ref stress 100 TEST_CASE("That all workers sleep when no work") { 101 const std::size_t N = 100000; 102 std::vector<std::size_t> vec(N, 0); 103 104 tbb::parallel_for_each(vec.begin(), vec.end(), [&](std::size_t& in) { 105 for (int i = 0; i < 1000; ++i) { 106 ++in; 107 } 108 }); 109 TestCPUUserTime(utils::get_platform_max_threads()); 110 } 111 112 #if __TBB_CPP20_CONCEPTS_PRESENT 113 114 template <typename Iterator, typename Body> 115 concept can_call_parallel_for_each_with_iterator = requires( Iterator it, const Body& body, tbb::task_group_context ctx ) { 116 tbb::parallel_for_each(it, it, body); 117 tbb::parallel_for_each(it, it, body, ctx); 118 }; 119 120 template <typename ContainerBasedSequence, typename Body> 121 concept can_call_parallel_for_each_with_cbs = requires( ContainerBasedSequence cbs, 122 const ContainerBasedSequence const_cbs, 123 const Body& body, tbb::task_group_context ctx ) { 124 tbb::parallel_for_each(cbs, body); 125 tbb::parallel_for_each(cbs, body, ctx); 126 tbb::parallel_for_each(const_cbs, body); 127 tbb::parallel_for_each(const_cbs, body, ctx); 128 }; 129 130 using CorrectCBS = test_concepts::container_based_sequence::Correct; 131 132 template <typename Body> 133 concept can_call_parallel_for_each = 134 can_call_parallel_for_each_with_iterator<CorrectCBS::iterator, Body> && 135 can_call_parallel_for_each_with_cbs<CorrectCBS, Body>; 136 137 template <typename Iterator> 138 using CorrectBody = test_concepts::parallel_for_each_body::Correct<decltype(*std::declval<Iterator>())>; 139 140 void test_pfor_each_iterator_constraints() { 141 using CorrectIterator = typename std::vector<int>::iterator; // random_access_iterator 142 using IncorrectIterator = std::ostream_iterator<int>; // output_iterator 143 static_assert(can_call_parallel_for_each_with_iterator<CorrectIterator, CorrectBody<CorrectIterator>>); 144 static_assert(!can_call_parallel_for_each_with_iterator<IncorrectIterator, CorrectBody<IncorrectIterator>>); 145 } 146 147 void test_pfor_each_container_based_sequence_constraints() { 148 using namespace test_concepts::container_based_sequence; 149 static_assert(can_call_parallel_for_each_with_cbs<Correct, CorrectBody<Correct::iterator>>); 150 static_assert(!can_call_parallel_for_each_with_cbs<NoBegin, CorrectBody<NoBegin::iterator>>); 151 static_assert(!can_call_parallel_for_each_with_cbs<NoEnd, CorrectBody<NoEnd::iterator>>); 152 } 153 154 void test_pfor_each_body_constraints() { 155 using namespace test_concepts::parallel_for_each_body; 156 static_assert(can_call_parallel_for_each<Correct<int>>); 157 static_assert(can_call_parallel_for_each<WithFeeder<int>>); 158 static_assert(!can_call_parallel_for_each<NoOperatorRoundBrackets<int>>); 159 static_assert(!can_call_parallel_for_each<WithFeederNoOperatorRoundBrackets<int>>); 160 static_assert(!can_call_parallel_for_each<OperatorRoundBracketsNonConst<int>>); 161 static_assert(!can_call_parallel_for_each<WithFeederOperatorRoundBracketsNonConst<int>>); 162 static_assert(!can_call_parallel_for_each<WrongInputOperatorRoundBrackets<int>>); 163 static_assert(!can_call_parallel_for_each<WithFeederWrongFirstInputOperatorRoundBrackets<int>>); 164 static_assert(!can_call_parallel_for_each<WithFeederWrongSecondInputOperatorRoundBrackets<int>>); 165 } 166 167 //! \brief \ref error_guessing 168 TEST_CASE("parallel_for_each constraints") { 169 test_pfor_each_iterator_constraints(); 170 test_pfor_each_container_based_sequence_constraints(); 171 test_pfor_each_body_constraints(); 172 } 173 174 #endif // __TBB_CPP20_CONCEPTS_PRESENT 175