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 template <typename Body> 131 concept can_call_parallel_for_each = 132 can_call_parallel_for_each_with_iterator<test_concepts::container_based_sequence::iterator, Body> && 133 can_call_parallel_for_each_with_cbs<test_concepts::container_based_sequence::Correct, Body>; 134 135 template <typename Iterator> 136 using CorrectBody = test_concepts::parallel_for_each_body::Correct<decltype(*std::declval<Iterator>())>; 137 138 void test_pfor_each_iterator_constraints() { 139 using CorrectIterator = typename std::vector<int>::iterator; // random_access_iterator 140 using IncorrectIterator = std::ostream_iterator<int>; // output_iterator 141 static_assert(can_call_parallel_for_each_with_iterator<CorrectIterator, CorrectBody<CorrectIterator>>); 142 static_assert(!can_call_parallel_for_each_with_iterator<IncorrectIterator, CorrectBody<IncorrectIterator>>); 143 } 144 145 void test_pfor_each_container_based_sequence_constraints() { 146 using namespace test_concepts::container_based_sequence; 147 using iterator = test_concepts::container_based_sequence::iterator; 148 static_assert(can_call_parallel_for_each_with_cbs<Correct, CorrectBody<iterator>>); 149 static_assert(!can_call_parallel_for_each_with_cbs<NoBegin, CorrectBody<iterator>>); 150 static_assert(!can_call_parallel_for_each_with_cbs<NoEnd, CorrectBody<iterator>>); 151 } 152 153 void test_pfor_each_body_constraints() { 154 using namespace test_concepts::parallel_for_each_body; 155 static_assert(can_call_parallel_for_each<Correct<int>>); 156 static_assert(can_call_parallel_for_each<WithFeeder<int>>); 157 static_assert(!can_call_parallel_for_each<NoOperatorRoundBrackets<int>>); 158 static_assert(!can_call_parallel_for_each<WithFeederNoOperatorRoundBrackets<int>>); 159 static_assert(!can_call_parallel_for_each<OperatorRoundBracketsNonConst<int>>); 160 static_assert(!can_call_parallel_for_each<WithFeederOperatorRoundBracketsNonConst<int>>); 161 static_assert(!can_call_parallel_for_each<WrongInputOperatorRoundBrackets<int>>); 162 static_assert(!can_call_parallel_for_each<WithFeederWrongFirstInputOperatorRoundBrackets<int>>); 163 static_assert(!can_call_parallel_for_each<WithFeederWrongSecondInputOperatorRoundBrackets<int>>); 164 } 165 166 //! \brief \ref error_guessing 167 TEST_CASE("parallel_for_each constraints") { 168 test_pfor_each_iterator_constraints(); 169 test_pfor_each_container_based_sequence_constraints(); 170 test_pfor_each_body_constraints(); 171 } 172 173 #endif // __TBB_CPP20_CONCEPTS_PRESENT 174