1 | /* |
2 | Copyright (c) 2005-2019 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 "tbb/blocked_range.h" |
18 | #include "harness_assert.h" |
19 | |
20 | // First test as much as we can without including other headers. |
21 | // Doing so should catch problems arising from failing to include headers. |
22 | |
23 | class AbstractValueType { |
24 | AbstractValueType() {} |
25 | int value; |
26 | public: |
27 | friend AbstractValueType MakeAbstractValueType( int i ); |
28 | friend int GetValueOf( const AbstractValueType& v ) {return v.value;} |
29 | }; |
30 | |
31 | AbstractValueType MakeAbstractValueType( int i ) { |
32 | AbstractValueType x; |
33 | x.value = i; |
34 | return x; |
35 | } |
36 | |
37 | std::size_t operator-( const AbstractValueType& u, const AbstractValueType& v ) { |
38 | return GetValueOf(u) - GetValueOf(v); |
39 | } |
40 | |
41 | bool operator<( const AbstractValueType& u, const AbstractValueType& v ) { |
42 | return GetValueOf(u) < GetValueOf(v); |
43 | } |
44 | |
45 | AbstractValueType operator+( const AbstractValueType& u, std::size_t offset ) { |
46 | return MakeAbstractValueType(GetValueOf(u) + int(offset)); |
47 | } |
48 | |
49 | static void SerialTest() { |
50 | for( int x=-10; x<10; ++x ) |
51 | for( int y=-10; y<10; ++y ) { |
52 | AbstractValueType i = MakeAbstractValueType(x); |
53 | AbstractValueType j = MakeAbstractValueType(y); |
54 | for( std::size_t k=1; k<10; ++k ) { |
55 | typedef tbb::blocked_range<AbstractValueType> range_type; |
56 | range_type r( i, j, k ); |
57 | AssertSameType( r.empty(), true ); |
58 | AssertSameType( range_type::size_type(), std::size_t() ); |
59 | AssertSameType( static_cast<range_type::const_iterator*>(0), static_cast<AbstractValueType*>(0) ); |
60 | AssertSameType( r.begin(), MakeAbstractValueType(0) ); |
61 | AssertSameType( r.end(), MakeAbstractValueType(0) ); |
62 | ASSERT( r.empty()==(y<=x), NULL ); |
63 | ASSERT( r.grainsize()==k, NULL ); |
64 | if( x<=y ) { |
65 | AssertSameType( r.is_divisible(), true ); |
66 | ASSERT( r.is_divisible()==(std::size_t(y-x)>k), NULL ); |
67 | ASSERT( r.size()==std::size_t(y-x), NULL ); |
68 | if( r.is_divisible() ) { |
69 | tbb::blocked_range<AbstractValueType> r2(r,tbb::split()); |
70 | ASSERT( GetValueOf(r.begin())==x, NULL ); |
71 | ASSERT( GetValueOf(r.end())==GetValueOf(r2.begin()), NULL ); |
72 | ASSERT( GetValueOf(r2.end())==y, NULL ); |
73 | ASSERT( r.grainsize()==k, NULL ); |
74 | ASSERT( r2.grainsize()==k, NULL ); |
75 | } |
76 | } |
77 | } |
78 | } |
79 | } |
80 | |
81 | #include "tbb/parallel_for.h" |
82 | #include "harness.h" |
83 | |
84 | const int N = 1<<22; |
85 | |
86 | unsigned char Array[N]; |
87 | |
88 | struct Striker { |
89 | // Note: we use <int> here instead of <long> in order to test for Quad 407676 |
90 | void operator()( const tbb::blocked_range<int>& r ) const { |
91 | for( tbb::blocked_range<int>::const_iterator i=r.begin(); i!=r.end(); ++i ) |
92 | ++Array[i]; |
93 | } |
94 | }; |
95 | |
96 | void ParallelTest() { |
97 | for( int i=0; i<N; i=i<3 ? i+1 : i*3 ) { |
98 | const tbb::blocked_range<int> r( 0, i, 10 ); |
99 | tbb::parallel_for( r, Striker() ); |
100 | for( int k=0; k<N; ++k ) { |
101 | ASSERT( Array[k]==(k<i), NULL ); |
102 | Array[k] = 0; |
103 | } |
104 | } |
105 | } |
106 | |
107 | #if __TBB_RANGE_BASED_FOR_PRESENT |
108 | #include "test_range_based_for.h" |
109 | #include <functional> |
110 | void TestRangeBasedFor() { |
111 | using namespace range_based_for_support_tests; |
112 | REMARK("testing range based for loop compatibility \n" ); |
113 | |
114 | size_t int_array[100] = {0}; |
115 | const size_t sequence_length = Harness::array_length(int_array); |
116 | |
117 | for (size_t i = 0; i < sequence_length; ++i) { |
118 | int_array[i] = i + 1; |
119 | } |
120 | |
121 | const tbb::blocked_range<size_t*> r(int_array, Harness::end(int_array), 1); |
122 | |
123 | ASSERT(range_based_for_accumulate<size_t>(r, std::plus<size_t>(), size_t(0)) == gauss_summ_of_int_sequence(sequence_length), "incorrect accumulated value generated via range based for ?" ); |
124 | } |
125 | #endif //if __TBB_RANGE_BASED_FOR_PRESENT |
126 | |
127 | #if __TBB_USE_PROPORTIONAL_SPLIT_IN_BLOCKED_RANGES |
128 | |
129 | void TestProportionalSplitOverflow() |
130 | { |
131 | REMARK("Testing overflow during proportional split - " ); |
132 | using tbb::blocked_range; |
133 | using tbb::proportional_split; |
134 | |
135 | blocked_range<size_t> r1(0, size_t(-1) / 2); |
136 | size_t size = r1.size(); |
137 | size_t begin = r1.begin(); |
138 | size_t end = r1.end(); |
139 | |
140 | proportional_split p(1, 3); |
141 | blocked_range<size_t> r2(r1, p); |
142 | |
143 | // overflow-free computation |
144 | size_t parts = p.left() + p.right(); |
145 | size_t int_part = size / parts; |
146 | size_t fraction = size - int_part * parts; // fraction < parts |
147 | size_t right_idx = int_part * p.right() + fraction * p.right() / parts + 1; |
148 | size_t newRangeBegin = end - right_idx; |
149 | |
150 | // Division in 'right_idx' very likely is inexact also. |
151 | size_t tolerance = 1; |
152 | size_t diff = (r2.begin() < newRangeBegin) ? (newRangeBegin - r2.begin()) : (r2.begin() - newRangeBegin); |
153 | bool is_split_correct = diff <= tolerance; |
154 | bool test_passed = (r1.begin() == begin && r1.end() == r2.begin() && is_split_correct && |
155 | r2.end() == end); |
156 | if (!test_passed) { |
157 | REPORT("Incorrect split of blocked range[%lu, %lu) into r1[%lu, %lu) and r2[%lu, %lu), " |
158 | "must be r1[%lu, %lu) and r2[%lu, %lu)\n" , begin, end, r1.begin(), r1.end(), r2.begin(), r2.end(), begin, newRangeBegin, newRangeBegin, end); |
159 | ASSERT(test_passed, NULL); |
160 | } |
161 | REMARK("OK\n" ); |
162 | } |
163 | #endif /* __TBB_USE_PROPORTIONAL_SPLIT_IN_BLOCKED_RANGES */ |
164 | |
165 | #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT |
166 | void TestDeductionGuides() { |
167 | std::vector<const int *> v; |
168 | |
169 | // check blocked_range(Value, Value, size_t) |
170 | tbb::blocked_range r1(v.begin(), v.end()); |
171 | static_assert(std::is_same<decltype(r1), tbb::blocked_range<decltype(v)::iterator>>::value); |
172 | |
173 | // check blocked_range(blocked_range &) |
174 | tbb::blocked_range r2(r1); |
175 | static_assert(std::is_same<decltype(r2), decltype(r1)>::value); |
176 | |
177 | // check blocked_range(blocked_range &&) |
178 | tbb::blocked_range r3(std::move(r1)); |
179 | static_assert(std::is_same<decltype(r3), decltype(r1)>::value); |
180 | } |
181 | #endif |
182 | |
183 | //------------------------------------------------------------------------ |
184 | // Test driver |
185 | #include "tbb/task_scheduler_init.h" |
186 | |
187 | int TestMain () { |
188 | SerialTest(); |
189 | for( int p=MinThread; p<=MaxThread; ++p ) { |
190 | tbb::task_scheduler_init init(p); |
191 | ParallelTest(); |
192 | } |
193 | |
194 | #if __TBB_RANGE_BASED_FOR_PRESENT |
195 | TestRangeBasedFor(); |
196 | #endif //if __TBB_RANGE_BASED_FOR_PRESENT |
197 | |
198 | #if __TBB_USE_PROPORTIONAL_SPLIT_IN_BLOCKED_RANGES |
199 | TestProportionalSplitOverflow(); |
200 | #endif |
201 | |
202 | #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT |
203 | TestDeductionGuides(); |
204 | #endif |
205 | return Harness::Done; |
206 | } |
207 | |