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