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