151c0b2f7Stbbdev /* 2b15aabb3Stbbdev Copyright (c) 2005-2021 Intel Corporation 351c0b2f7Stbbdev 451c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License"); 551c0b2f7Stbbdev you may not use this file except in compliance with the License. 651c0b2f7Stbbdev You may obtain a copy of the License at 751c0b2f7Stbbdev 851c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0 951c0b2f7Stbbdev 1051c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software 1151c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS, 1251c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1351c0b2f7Stbbdev See the License for the specific language governing permissions and 1451c0b2f7Stbbdev limitations under the License. 1551c0b2f7Stbbdev */ 1651c0b2f7Stbbdev 1751c0b2f7Stbbdev #include "common/parallel_for_each_common.h" 18478de5b1Stbbdev #include "common/concepts_common.h" 19478de5b1Stbbdev #include <vector> 20478de5b1Stbbdev #include <iterator> 2151c0b2f7Stbbdev 2251c0b2f7Stbbdev //! \file test_parallel_for_each.cpp 2351c0b2f7Stbbdev //! \brief Test for [algorithms.parallel_for_each] 2451c0b2f7Stbbdev 2551c0b2f7Stbbdev //! Test forward access iterator support 2651c0b2f7Stbbdev //! \brief \ref error_guessing \ref interface 2751c0b2f7Stbbdev TEST_CASE("Forward iterator support") { 2851c0b2f7Stbbdev for ( auto concurrency_level : utils::concurrency_range() ) { 2951c0b2f7Stbbdev tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level); 3051c0b2f7Stbbdev for(size_t depth = 0; depth <= depths_nubmer; ++depth) { 3151c0b2f7Stbbdev g_tasks_expected = 0; 3251c0b2f7Stbbdev for (size_t i=0; i < depth; ++i) 3351c0b2f7Stbbdev g_tasks_expected += FindNumOfTasks(g_depths[i].value()); 3451c0b2f7Stbbdev TestIterator_Modifiable<utils::ForwardIterator<value_t>>(depth); 3551c0b2f7Stbbdev } 3651c0b2f7Stbbdev } 3751c0b2f7Stbbdev } 3851c0b2f7Stbbdev 3951c0b2f7Stbbdev //! Test random access iterator support 4051c0b2f7Stbbdev //! \brief \ref error_guessing \ref interface 4151c0b2f7Stbbdev TEST_CASE("Random access iterator support") { 4251c0b2f7Stbbdev for ( auto concurrency_level : utils::concurrency_range() ) { 4351c0b2f7Stbbdev tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level); 4451c0b2f7Stbbdev for(size_t depth = 0; depth <= depths_nubmer; ++depth) { 4551c0b2f7Stbbdev g_tasks_expected = 0; 4651c0b2f7Stbbdev for (size_t i=0; i < depth; ++i) 4751c0b2f7Stbbdev g_tasks_expected += FindNumOfTasks(g_depths[i].value()); 4851c0b2f7Stbbdev TestIterator_Modifiable<value_t*>(depth); 4951c0b2f7Stbbdev } 5051c0b2f7Stbbdev } 5151c0b2f7Stbbdev } 5251c0b2f7Stbbdev 5351c0b2f7Stbbdev //! Test const random access iterator support 5451c0b2f7Stbbdev //! \brief \ref error_guessing \ref interface 5551c0b2f7Stbbdev TEST_CASE("Const random access iterator support") { 5651c0b2f7Stbbdev for ( auto concurrency_level : utils::concurrency_range() ) { 5751c0b2f7Stbbdev tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level); 5851c0b2f7Stbbdev for(size_t depth = 0; depth <= depths_nubmer; ++depth) { 5951c0b2f7Stbbdev g_tasks_expected = 0; 6051c0b2f7Stbbdev for (size_t i=0; i < depth; ++i) 6151c0b2f7Stbbdev g_tasks_expected += FindNumOfTasks(g_depths[i].value()); 6251c0b2f7Stbbdev TestIterator_Const<utils::ConstRandomIterator<value_t>>(depth); 6351c0b2f7Stbbdev } 6451c0b2f7Stbbdev } 6551c0b2f7Stbbdev 6651c0b2f7Stbbdev } 6751c0b2f7Stbbdev 6851c0b2f7Stbbdev //! Test container based overload 6951c0b2f7Stbbdev //! \brief \ref error_guessing \ref interface 7051c0b2f7Stbbdev TEST_CASE("Container based overload - forward iterator based container") { 7151c0b2f7Stbbdev container_based_overload_test_case<utils::ForwardIterator>(/*expected_value*/1); 7251c0b2f7Stbbdev } 7351c0b2f7Stbbdev 7451c0b2f7Stbbdev //! Test container based overload 7551c0b2f7Stbbdev //! \brief \ref error_guessing \ref interface 7651c0b2f7Stbbdev TEST_CASE("Container based overload - random access iterator based container") { 7751c0b2f7Stbbdev container_based_overload_test_case<utils::RandomIterator>(/*expected_value*/1); 7851c0b2f7Stbbdev } 7951c0b2f7Stbbdev 8051c0b2f7Stbbdev // Test for iterators over values convertible to work item type 8151c0b2f7Stbbdev //! \brief \ref error_guessing \ref interface 8251c0b2f7Stbbdev TEST_CASE("Using with values convertible to work item type") { 8351c0b2f7Stbbdev for ( auto concurrency_level : utils::concurrency_range() ) { 8451c0b2f7Stbbdev tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level); 8551c0b2f7Stbbdev using Iterator = size_t*; 8651c0b2f7Stbbdev for(size_t depth = 0; depth <= depths_nubmer; ++depth) { 8751c0b2f7Stbbdev g_tasks_expected = 0; 8851c0b2f7Stbbdev for (size_t i=0; i < depth; ++i) 8951c0b2f7Stbbdev g_tasks_expected += FindNumOfTasks(g_depths[i].value()); 9051c0b2f7Stbbdev // Test for iterators over values convertible to work item type 9151c0b2f7Stbbdev TestIterator_Common<Iterator>(depth); 9251c0b2f7Stbbdev TestBody<FakeTaskGeneratorBody_RvalueRefVersion, Iterator>(depth); 9351c0b2f7Stbbdev TestBody<TaskGeneratorBody_RvalueRefVersion, Iterator>(depth); 9451c0b2f7Stbbdev } 9551c0b2f7Stbbdev } 9651c0b2f7Stbbdev } 9751c0b2f7Stbbdev 9851c0b2f7Stbbdev //! Testing workers going to sleep 9951c0b2f7Stbbdev //! \brief \ref resource_usage \ref stress 10051c0b2f7Stbbdev TEST_CASE("That all workers sleep when no work") { 10151c0b2f7Stbbdev const std::size_t N = 100000; 10251c0b2f7Stbbdev std::vector<std::size_t> vec(N, 0); 10351c0b2f7Stbbdev 10451c0b2f7Stbbdev tbb::parallel_for_each(vec.begin(), vec.end(), [&](std::size_t& in) { 105b15aabb3Stbbdev for (int i = 0; i < 1000; ++i) { 10651c0b2f7Stbbdev ++in; 10751c0b2f7Stbbdev } 10851c0b2f7Stbbdev }); 10951c0b2f7Stbbdev TestCPUUserTime(utils::get_platform_max_threads()); 11051c0b2f7Stbbdev } 111478de5b1Stbbdev 112478de5b1Stbbdev #if __TBB_CPP20_CONCEPTS_PRESENT 113478de5b1Stbbdev 114478de5b1Stbbdev template <typename Iterator, typename Body> 115478de5b1Stbbdev concept can_call_parallel_for_each_with_iterator = requires( Iterator it, const Body& body, tbb::task_group_context ctx ) { 116478de5b1Stbbdev tbb::parallel_for_each(it, it, body); 117478de5b1Stbbdev tbb::parallel_for_each(it, it, body, ctx); 118478de5b1Stbbdev }; 119478de5b1Stbbdev 120478de5b1Stbbdev template <typename ContainerBasedSequence, typename Body> 121478de5b1Stbbdev concept can_call_parallel_for_each_with_cbs = requires( ContainerBasedSequence cbs, 122478de5b1Stbbdev const ContainerBasedSequence const_cbs, 123478de5b1Stbbdev const Body& body, tbb::task_group_context ctx ) { 124478de5b1Stbbdev tbb::parallel_for_each(cbs, body); 125478de5b1Stbbdev tbb::parallel_for_each(cbs, body, ctx); 126478de5b1Stbbdev tbb::parallel_for_each(const_cbs, body); 127478de5b1Stbbdev tbb::parallel_for_each(const_cbs, body, ctx); 128478de5b1Stbbdev }; 129478de5b1Stbbdev 130*4eec89feSIvan Kochin using CorrectCBS = test_concepts::container_based_sequence::Correct; 131*4eec89feSIvan Kochin 132478de5b1Stbbdev template <typename Body> 133478de5b1Stbbdev concept can_call_parallel_for_each = 134*4eec89feSIvan Kochin can_call_parallel_for_each_with_iterator<CorrectCBS::iterator, Body> && 135*4eec89feSIvan Kochin can_call_parallel_for_each_with_cbs<CorrectCBS, Body>; 136478de5b1Stbbdev 137478de5b1Stbbdev template <typename Iterator> 138478de5b1Stbbdev using CorrectBody = test_concepts::parallel_for_each_body::Correct<decltype(*std::declval<Iterator>())>; 139478de5b1Stbbdev 140478de5b1Stbbdev void test_pfor_each_iterator_constraints() { 141478de5b1Stbbdev using CorrectIterator = typename std::vector<int>::iterator; // random_access_iterator 142478de5b1Stbbdev using IncorrectIterator = std::ostream_iterator<int>; // output_iterator 143478de5b1Stbbdev static_assert(can_call_parallel_for_each_with_iterator<CorrectIterator, CorrectBody<CorrectIterator>>); 144478de5b1Stbbdev static_assert(!can_call_parallel_for_each_with_iterator<IncorrectIterator, CorrectBody<IncorrectIterator>>); 145478de5b1Stbbdev } 146478de5b1Stbbdev 147478de5b1Stbbdev void test_pfor_each_container_based_sequence_constraints() { 148478de5b1Stbbdev using namespace test_concepts::container_based_sequence; 149*4eec89feSIvan Kochin static_assert(can_call_parallel_for_each_with_cbs<Correct, CorrectBody<Correct::iterator>>); 150*4eec89feSIvan Kochin static_assert(!can_call_parallel_for_each_with_cbs<NoBegin, CorrectBody<NoBegin::iterator>>); 151*4eec89feSIvan Kochin static_assert(!can_call_parallel_for_each_with_cbs<NoEnd, CorrectBody<NoEnd::iterator>>); 152478de5b1Stbbdev } 153478de5b1Stbbdev 154478de5b1Stbbdev void test_pfor_each_body_constraints() { 155478de5b1Stbbdev using namespace test_concepts::parallel_for_each_body; 156478de5b1Stbbdev static_assert(can_call_parallel_for_each<Correct<int>>); 157478de5b1Stbbdev static_assert(can_call_parallel_for_each<WithFeeder<int>>); 158478de5b1Stbbdev static_assert(!can_call_parallel_for_each<NoOperatorRoundBrackets<int>>); 159478de5b1Stbbdev static_assert(!can_call_parallel_for_each<WithFeederNoOperatorRoundBrackets<int>>); 160478de5b1Stbbdev static_assert(!can_call_parallel_for_each<OperatorRoundBracketsNonConst<int>>); 161478de5b1Stbbdev static_assert(!can_call_parallel_for_each<WithFeederOperatorRoundBracketsNonConst<int>>); 162478de5b1Stbbdev static_assert(!can_call_parallel_for_each<WrongInputOperatorRoundBrackets<int>>); 163478de5b1Stbbdev static_assert(!can_call_parallel_for_each<WithFeederWrongFirstInputOperatorRoundBrackets<int>>); 164478de5b1Stbbdev static_assert(!can_call_parallel_for_each<WithFeederWrongSecondInputOperatorRoundBrackets<int>>); 165478de5b1Stbbdev } 166478de5b1Stbbdev 167478de5b1Stbbdev //! \brief \ref error_guessing 168478de5b1Stbbdev TEST_CASE("parallel_for_each constraints") { 169478de5b1Stbbdev test_pfor_each_iterator_constraints(); 170478de5b1Stbbdev test_pfor_each_container_based_sequence_constraints(); 171478de5b1Stbbdev test_pfor_each_body_constraints(); 172478de5b1Stbbdev } 173478de5b1Stbbdev 174478de5b1Stbbdev #endif // __TBB_CPP20_CONCEPTS_PRESENT 175