1 /*
2 Copyright (c) 2005-2022 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/test.h"
18 #include "common/utils.h"
19 #include "common/utils_assert.h"
20 #include "common/utils_concurrency_limit.h"
21
22 #include "oneapi/tbb/blocked_range.h"
23 #include "oneapi/tbb/parallel_for.h"
24 #include "oneapi/tbb/global_control.h"
25
26 #include <vector>
27
28 //! \file conformance_blocked_range.cpp
29 //! \brief Test for [algorithms.blocked_range] specification
30
31 class AbstractValueType {
AbstractValueType()32 AbstractValueType() {}
33 int value;
34 public:
35 friend AbstractValueType MakeAbstractValueType( int i );
GetValueOf(const AbstractValueType & v)36 friend int GetValueOf( const AbstractValueType& v ) {return v.value;}
37 };
38
MakeAbstractValueType(int i)39 AbstractValueType MakeAbstractValueType( int i ) {
40 AbstractValueType x;
41 x.value = i;
42 return x;
43 }
44
operator -(const AbstractValueType & u,const AbstractValueType & v)45 std::size_t operator-( const AbstractValueType& u, const AbstractValueType& v ) {
46 return GetValueOf(u) - GetValueOf(v);
47 }
48
operator <(const AbstractValueType & u,const AbstractValueType & v)49 bool operator<( const AbstractValueType& u, const AbstractValueType& v ) {
50 return GetValueOf(u) < GetValueOf(v);
51 }
52
operator +(const AbstractValueType & u,std::size_t offset)53 AbstractValueType operator+( const AbstractValueType& u, std::size_t offset ) {
54 return MakeAbstractValueType(GetValueOf(u) + int(offset));
55 }
56
SerialTest()57 static void SerialTest() {
58 for( int x=-10; x<10; ++x ) {
59 for( int y=-10; y<10; ++y ) {
60 AbstractValueType i = MakeAbstractValueType(x);
61 AbstractValueType j = MakeAbstractValueType(y);
62 for( std::size_t k=1; k<10; ++k ) {
63 typedef oneapi::tbb::blocked_range<AbstractValueType> range_type;
64 range_type r( i, j, k );
65 utils::AssertSameType( r.empty(), true );
66 utils::AssertSameType( range_type::size_type(), std::size_t() );
67 utils::AssertSameType( static_cast<range_type::const_iterator*>(nullptr), static_cast<AbstractValueType*>(nullptr) );
68 utils::AssertSameType( r.begin(), MakeAbstractValueType(0) );
69 utils::AssertSameType( r.end(), MakeAbstractValueType(0) );
70 CHECK( r.empty()==(y<=x));
71 CHECK( r.grainsize()==k);
72 if( x<=y ) {
73 utils::AssertSameType( r.is_divisible(), true );
74 CHECK( r.is_divisible()==(std::size_t(y-x)>k) );
75 CHECK( r.size()==std::size_t(y-x) );
76 if( r.is_divisible() ) {
77 oneapi::tbb::blocked_range<AbstractValueType> r2(r,oneapi::tbb::split());
78 CHECK( GetValueOf(r.begin())==x );
79 CHECK( GetValueOf(r.end())==GetValueOf(r2.begin()) );
80 CHECK( GetValueOf(r2.end())==y );
81 CHECK( r.grainsize()==k );
82 CHECK( r2.grainsize()==k );
83 }
84 }
85 }
86 }
87 }
88 }
89
90 const int N = 1<<22;
91 unsigned char Array[N];
92
93 struct Striker {
operator ()Striker94 void operator()( const oneapi::tbb::blocked_range<int>& r ) const {
95 for( oneapi::tbb::blocked_range<int>::const_iterator i=r.begin(); i!=r.end(); ++i )
96 ++Array[i];
97 }
98 };
99
ParallelTest()100 void ParallelTest() {
101 for (int i=0; i<N; i=i<3 ? i+1 : i*3) {
102 const oneapi::tbb::blocked_range<int> r( 0, i, 10 );
103 oneapi::tbb::parallel_for( r, Striker() );
104 for (int k=0; k<N; ++k) {
105 if (Array[k] != (k<i)) CHECK(false);
106 Array[k] = 0;
107 }
108 }
109 }
110
111 //! Testing blocked_range interface
112 //! \brief \ref interface \ref requirement
113 TEST_CASE("Basic serial") {
114 SerialTest();
115 }
116
117 //! Testing blocked_range interface with parallel_for
118 //! \brief \ref requirement
119 TEST_CASE("Basic parallel") {
120 for ( auto concurrency_level : utils::concurrency_range() ) {
121 oneapi::tbb::global_control control(oneapi::tbb::global_control::max_allowed_parallelism, concurrency_level);
122 ParallelTest();
123 }
124 }
125
126 //! Testing blocked_range with proportional splitting
127 //! \brief \ref interface \ref requirement
128 TEST_CASE("blocked_range proportional splitting") {
129 oneapi::tbb::blocked_range<int> original(0, 100);
130 oneapi::tbb::blocked_range<int> first(original);
131 oneapi::tbb::proportional_split ps(3, 1);
132 oneapi::tbb::blocked_range<int> second(first, ps);
133
134 // Test proportional_split -> split conversion
135 oneapi::tbb::blocked_range<int> copy(original);
136 oneapi::tbb::split s = oneapi::tbb::split(ps);
137 oneapi::tbb::blocked_range<int> splitted_copy(copy, s);
138 CHECK(copy.size() == original.size() / 2);
139 CHECK(splitted_copy.size() == copy.size());
140
141
142 int expected_first_end = static_cast<int>(
143 original.begin() + ps.left() * (original.end() - original.begin()) / (ps.left() + ps.right())
144 );
145 utils::check_range_bounds_after_splitting(original, first, second, expected_first_end);
146 }
147
148 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
149 //! Testing blocked_range deduction guides
150 //! \brief \ref interface
151 TEST_CASE("Deduction guides") {
152 std::vector<const int *> v;
153
154 // check blocked_range(Value, Value, size_t)
155 oneapi::tbb::blocked_range r1(v.begin(), v.end());
156 static_assert(std::is_same<decltype(r1), oneapi::tbb::blocked_range<decltype(v)::iterator>>::value);
157
158 // check blocked_range(blocked_range &)
159 oneapi::tbb::blocked_range r2(r1);
160 static_assert(std::is_same<decltype(r2), decltype(r1)>::value);
161
162 // check blocked_range(blocked_range &&)
163 oneapi::tbb::blocked_range r3(std::move(r1));
164 static_assert(std::is_same<decltype(r3), decltype(r1)>::value);
165 }
166 #endif
167
168