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/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_range2d.h"
23 #include "oneapi/tbb/parallel_for.h"
24 #include "oneapi/tbb/global_control.h"
25
26 //! \file conformance_blocked_range2d.cpp
27 //! \brief Test for [algorithms.blocked_range2d] specification
28
29 template<typename Tag>
30 class AbstractValueType {
AbstractValueType()31 AbstractValueType() {}
32 int value;
33 public:
34 template<typename OtherTag>
35 friend AbstractValueType<OtherTag> MakeAbstractValueType( int i );
36
37 template<typename OtherTag>
38 friend int GetValueOf( const AbstractValueType<OtherTag>& v ) ;
39 };
40
41 template<typename Tag>
MakeAbstractValueType(int i)42 AbstractValueType<Tag> MakeAbstractValueType( int i ) {
43 AbstractValueType<Tag> x;
44 x.value = i;
45 return x;
46 }
47
48 template<typename Tag>
GetValueOf(const AbstractValueType<Tag> & v)49 int GetValueOf( const AbstractValueType<Tag>& v ) {return v.value;}
50
51 template<typename Tag>
operator <(const AbstractValueType<Tag> & u,const AbstractValueType<Tag> & v)52 bool operator<( const AbstractValueType<Tag>& u, const AbstractValueType<Tag>& v ) {
53 return GetValueOf(u)<GetValueOf(v);
54 }
55
56 template<typename Tag>
operator -(const AbstractValueType<Tag> & u,const AbstractValueType<Tag> & v)57 std::size_t operator-( const AbstractValueType<Tag>& u, const AbstractValueType<Tag>& v ) {
58 return GetValueOf(u)-GetValueOf(v);
59 }
60
61 template<typename Tag>
operator +(const AbstractValueType<Tag> & u,std::size_t offset)62 AbstractValueType<Tag> operator+( const AbstractValueType<Tag>& u, std::size_t offset ) {
63 return MakeAbstractValueType<Tag>(GetValueOf(u)+int(offset));
64 }
65
66 struct RowTag {};
67 struct ColTag {};
68
SerialTest()69 static void SerialTest() {
70 typedef AbstractValueType<RowTag> row_type;
71 typedef AbstractValueType<ColTag> col_type;
72 typedef oneapi::tbb::blocked_range2d<row_type,col_type> range_type;
73 for( int row_x=-10; row_x<10; ++row_x ) {
74 for( int row_y=row_x; row_y<10; ++row_y ) {
75 row_type row_i = MakeAbstractValueType<RowTag>(row_x);
76 row_type row_j = MakeAbstractValueType<RowTag>(row_y);
77 for( int row_grain=1; row_grain<10; ++row_grain ) {
78 for( int col_x=-10; col_x<10; ++col_x ) {
79 for( int col_y=col_x; col_y<10; ++col_y ) {
80 col_type col_i = MakeAbstractValueType<ColTag>(col_x);
81 col_type col_j = MakeAbstractValueType<ColTag>(col_y);
82 for( int col_grain=1; col_grain<10; ++col_grain ) {
83 range_type r( row_i, row_j, row_grain, col_i, col_j, col_grain );
84 utils::AssertSameType( r.is_divisible(), true );
85 utils::AssertSameType( r.empty(), true );
86 utils::AssertSameType( static_cast<range_type::row_range_type::const_iterator*>(0), static_cast<row_type*>(0) );
87 utils::AssertSameType( static_cast<range_type::col_range_type::const_iterator*>(0), static_cast<col_type*>(0) );
88 utils::AssertSameType( r.rows(), oneapi::tbb::blocked_range<row_type>( row_i, row_j, 1 ));
89 utils::AssertSameType( r.cols(), oneapi::tbb::blocked_range<col_type>( col_i, col_j, 1 ));
90 REQUIRE( r.empty()==(row_x==row_y||col_x==col_y) );
91 REQUIRE( r.is_divisible()==(row_y-row_x>row_grain||col_y-col_x>col_grain) );
92 if( r.is_divisible() ) {
93 range_type r2(r,oneapi::tbb::split());
94 if( GetValueOf(r2.rows().begin())==GetValueOf(r.rows().begin()) ) {
95 REQUIRE( GetValueOf(r2.rows().end())==GetValueOf(r.rows().end()) );
96 REQUIRE( GetValueOf(r2.cols().begin())==GetValueOf(r.cols().end()) );
97 } else {
98 REQUIRE( GetValueOf(r2.cols().end())==GetValueOf(r.cols().end()) );
99 REQUIRE( GetValueOf(r2.rows().begin())==GetValueOf(r.rows().end()) );
100 }
101 }
102 }
103 }
104 }
105 }
106 }
107 }
108 }
109
110 const int N = 1<<10;
111
112 unsigned char Array[N][N];
113
114 struct Striker {
115 // Note: we use <int> here instead of <long> in order to test for problems similar to Quad 407676
operator ()Striker116 void operator()( const oneapi::tbb::blocked_range2d<int>& r ) const {
117 for( oneapi::tbb::blocked_range<int>::const_iterator i=r.rows().begin(); i!=r.rows().end(); ++i )
118 for( oneapi::tbb::blocked_range<int>::const_iterator j=r.cols().begin(); j!=r.cols().end(); ++j )
119 ++Array[i][j];
120 }
121 };
122
ParallelTest()123 void ParallelTest() {
124 for( int i=0; i<N; i=i<3 ? i+1 : i*3 ) {
125 for( int j=0; j<N; j=j<3 ? j+1 : j*3 ) {
126 const oneapi::tbb::blocked_range2d<int> r( 0, i, 7, 0, j, 5 );
127 oneapi::tbb::parallel_for( r, Striker() );
128 for( int k=0; k<N; ++k ) {
129 for( int l=0; l<N; ++l ) {
130 if( Array[k][l] != (k<i && l<j) ) REQUIRE(false);
131 Array[k][l] = 0;
132 }
133 }
134 }
135 }
136 }
137
138 //! Testing blocked_range2d interface
139 //! \brief \ref interface \ref requirement
140 TEST_CASE("Serial test") {
141 SerialTest();
142 }
143
144 //! Testing blocked_range2d interface with parallel_for
145 //! \brief \ref requirement
146 TEST_CASE("Parallel test") {
147 for ( auto concurrency_level : utils::concurrency_range() ) {
148 oneapi::tbb::global_control control(oneapi::tbb::global_control::max_allowed_parallelism, concurrency_level);
149 ParallelTest();
150 }
151 }
152
153 //! Testing blocked_range2d with proportional splitting
154 //! \brief \ref interface \ref requirement
155 TEST_CASE("blocked_range2d proportional splitting") {
156 oneapi::tbb::blocked_range2d<int> original(0, 100, 0, 100);
157 oneapi::tbb::blocked_range2d<int> first(original);
158 oneapi::tbb::proportional_split ps(3, 1);
159 oneapi::tbb::blocked_range2d<int> second(first, ps);
160
161 int expected_first_end = static_cast<int>(
162 original.rows().begin() + ps.left() * (original.rows().end() - original.rows().begin()) / (ps.left() + ps.right())
163 );
164 if (first.rows().size() == second.rows().size()) {
165 // Splitting was made by cols
166 utils::check_range_bounds_after_splitting(original.cols(), first.cols(), second.cols(), expected_first_end);
167 } else {
168 // Splitting was made by rows
169 utils::check_range_bounds_after_splitting(original.rows(), first.rows(), second.rows(), expected_first_end);
170 }
171 }
172
173 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
174 //! Testing blocked_range2d deduction guides
175 //! \brief \ref interface
176 TEST_CASE("Deduction guides") {
177 std::vector<const unsigned long *> v;
178 std::vector<double> v2;
179
180 // check blocked_range2d(RowValue, RowValue, size_t, ColValue, ColValue, size_t)
181 oneapi::tbb::blocked_range2d r1(v.begin(), v.end(), 2, v2.begin(), v2.end(), 2);
182 static_assert(std::is_same<decltype(r1), oneapi::tbb::blocked_range2d<decltype(v)::iterator, decltype(v2)::iterator>>::value);
183
184 // check blocked_range2d(blocked_range2d &)
185 oneapi::tbb::blocked_range2d r2(r1);
186 static_assert(std::is_same<decltype(r2), decltype(r1)>::value);
187
188 // check blocked_range2d(blocked_range2d &&)
189 oneapi::tbb::blocked_range2d r3(std::move(r1));
190 static_assert(std::is_same<decltype(r3), decltype(r1)>::value);
191 }
192 #endif
193
194