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