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