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