1 /* 2 Copyright (c) 2005-2020 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 { 32 AbstractValueType() {} 33 int value; 34 public: 35 friend AbstractValueType MakeAbstractValueType( int i ); 36 friend int GetValueOf( const AbstractValueType& v ) {return v.value;} 37 }; 38 39 AbstractValueType MakeAbstractValueType( int i ) { 40 AbstractValueType x; 41 x.value = i; 42 return x; 43 } 44 45 std::size_t operator-( const AbstractValueType& u, const AbstractValueType& v ) { 46 return GetValueOf(u) - GetValueOf(v); 47 } 48 49 bool operator<( const AbstractValueType& u, const AbstractValueType& v ) { 50 return GetValueOf(u) < GetValueOf(v); 51 } 52 53 AbstractValueType operator+( const AbstractValueType& u, std::size_t offset ) { 54 return MakeAbstractValueType(GetValueOf(u) + int(offset)); 55 } 56 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*>(0), static_cast<AbstractValueType*>(0) ); 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 { 94 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 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 = original.begin() + ps.left() * (original.end() - original.begin()) / (ps.left() + ps.right()); 143 utils::check_range_bounds_after_splitting(original, first, second, expected_first_end); 144 } 145 146 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 147 //! Testing blocked_range deduction guides 148 //! \brief \ref interface 149 TEST_CASE("Deduction guides") { 150 std::vector<const int *> v; 151 152 // check blocked_range(Value, Value, size_t) 153 oneapi::tbb::blocked_range r1(v.begin(), v.end()); 154 static_assert(std::is_same<decltype(r1), oneapi::tbb::blocked_range<decltype(v)::iterator>>::value); 155 156 // check blocked_range(blocked_range &) 157 oneapi::tbb::blocked_range r2(r1); 158 static_assert(std::is_same<decltype(r2), decltype(r1)>::value); 159 160 // check blocked_range(blocked_range &&) 161 oneapi::tbb::blocked_range r3(std::move(r1)); 162 static_assert(std::is_same<decltype(r3), decltype(r1)>::value); 163 } 164 #endif 165 166