151c0b2f7Stbbdev /*
2*c21e688aSSergey Zheltov Copyright (c) 2005-2022 Intel Corporation
351c0b2f7Stbbdev
451c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev you may not use this file except in compliance with the License.
651c0b2f7Stbbdev You may obtain a copy of the License at
751c0b2f7Stbbdev
851c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev
1051c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev See the License for the specific language governing permissions and
1451c0b2f7Stbbdev limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev
1751c0b2f7Stbbdev #include "common/test.h"
1851c0b2f7Stbbdev #include "common/utils.h"
1951c0b2f7Stbbdev #include "common/utils_assert.h"
2051c0b2f7Stbbdev #include "common/utils_concurrency_limit.h"
2151c0b2f7Stbbdev
2249e08aacStbbdev #include "oneapi/tbb/blocked_range.h"
2349e08aacStbbdev #include "oneapi/tbb/parallel_for.h"
2449e08aacStbbdev #include "oneapi/tbb/global_control.h"
2551c0b2f7Stbbdev
2651c0b2f7Stbbdev #include <vector>
2751c0b2f7Stbbdev
2851c0b2f7Stbbdev //! \file conformance_blocked_range.cpp
2951c0b2f7Stbbdev //! \brief Test for [algorithms.blocked_range] specification
3051c0b2f7Stbbdev
3151c0b2f7Stbbdev class AbstractValueType {
AbstractValueType()3251c0b2f7Stbbdev AbstractValueType() {}
3351c0b2f7Stbbdev int value;
3451c0b2f7Stbbdev public:
3551c0b2f7Stbbdev friend AbstractValueType MakeAbstractValueType( int i );
GetValueOf(const AbstractValueType & v)3651c0b2f7Stbbdev friend int GetValueOf( const AbstractValueType& v ) {return v.value;}
3751c0b2f7Stbbdev };
3851c0b2f7Stbbdev
MakeAbstractValueType(int i)3951c0b2f7Stbbdev AbstractValueType MakeAbstractValueType( int i ) {
4051c0b2f7Stbbdev AbstractValueType x;
4151c0b2f7Stbbdev x.value = i;
4251c0b2f7Stbbdev return x;
4351c0b2f7Stbbdev }
4451c0b2f7Stbbdev
operator -(const AbstractValueType & u,const AbstractValueType & v)4551c0b2f7Stbbdev std::size_t operator-( const AbstractValueType& u, const AbstractValueType& v ) {
4651c0b2f7Stbbdev return GetValueOf(u) - GetValueOf(v);
4751c0b2f7Stbbdev }
4851c0b2f7Stbbdev
operator <(const AbstractValueType & u,const AbstractValueType & v)4951c0b2f7Stbbdev bool operator<( const AbstractValueType& u, const AbstractValueType& v ) {
5051c0b2f7Stbbdev return GetValueOf(u) < GetValueOf(v);
5151c0b2f7Stbbdev }
5251c0b2f7Stbbdev
operator +(const AbstractValueType & u,std::size_t offset)5351c0b2f7Stbbdev AbstractValueType operator+( const AbstractValueType& u, std::size_t offset ) {
5451c0b2f7Stbbdev return MakeAbstractValueType(GetValueOf(u) + int(offset));
5551c0b2f7Stbbdev }
5651c0b2f7Stbbdev
SerialTest()5751c0b2f7Stbbdev static void SerialTest() {
5851c0b2f7Stbbdev for( int x=-10; x<10; ++x ) {
5951c0b2f7Stbbdev for( int y=-10; y<10; ++y ) {
6051c0b2f7Stbbdev AbstractValueType i = MakeAbstractValueType(x);
6151c0b2f7Stbbdev AbstractValueType j = MakeAbstractValueType(y);
6251c0b2f7Stbbdev for( std::size_t k=1; k<10; ++k ) {
6349e08aacStbbdev typedef oneapi::tbb::blocked_range<AbstractValueType> range_type;
6451c0b2f7Stbbdev range_type r( i, j, k );
6551c0b2f7Stbbdev utils::AssertSameType( r.empty(), true );
6651c0b2f7Stbbdev utils::AssertSameType( range_type::size_type(), std::size_t() );
6757f524caSIlya Isaev utils::AssertSameType( static_cast<range_type::const_iterator*>(nullptr), static_cast<AbstractValueType*>(nullptr) );
6851c0b2f7Stbbdev utils::AssertSameType( r.begin(), MakeAbstractValueType(0) );
6951c0b2f7Stbbdev utils::AssertSameType( r.end(), MakeAbstractValueType(0) );
7051c0b2f7Stbbdev CHECK( r.empty()==(y<=x));
7151c0b2f7Stbbdev CHECK( r.grainsize()==k);
7251c0b2f7Stbbdev if( x<=y ) {
7351c0b2f7Stbbdev utils::AssertSameType( r.is_divisible(), true );
7451c0b2f7Stbbdev CHECK( r.is_divisible()==(std::size_t(y-x)>k) );
7551c0b2f7Stbbdev CHECK( r.size()==std::size_t(y-x) );
7651c0b2f7Stbbdev if( r.is_divisible() ) {
7749e08aacStbbdev oneapi::tbb::blocked_range<AbstractValueType> r2(r,oneapi::tbb::split());
7851c0b2f7Stbbdev CHECK( GetValueOf(r.begin())==x );
7951c0b2f7Stbbdev CHECK( GetValueOf(r.end())==GetValueOf(r2.begin()) );
8051c0b2f7Stbbdev CHECK( GetValueOf(r2.end())==y );
8151c0b2f7Stbbdev CHECK( r.grainsize()==k );
8251c0b2f7Stbbdev CHECK( r2.grainsize()==k );
8351c0b2f7Stbbdev }
8451c0b2f7Stbbdev }
8551c0b2f7Stbbdev }
8651c0b2f7Stbbdev }
8751c0b2f7Stbbdev }
8851c0b2f7Stbbdev }
8951c0b2f7Stbbdev
9051c0b2f7Stbbdev const int N = 1<<22;
9151c0b2f7Stbbdev unsigned char Array[N];
9251c0b2f7Stbbdev
9351c0b2f7Stbbdev struct Striker {
operator ()Striker9449e08aacStbbdev void operator()( const oneapi::tbb::blocked_range<int>& r ) const {
9549e08aacStbbdev for( oneapi::tbb::blocked_range<int>::const_iterator i=r.begin(); i!=r.end(); ++i )
9651c0b2f7Stbbdev ++Array[i];
9751c0b2f7Stbbdev }
9851c0b2f7Stbbdev };
9951c0b2f7Stbbdev
ParallelTest()10051c0b2f7Stbbdev void ParallelTest() {
10151c0b2f7Stbbdev for (int i=0; i<N; i=i<3 ? i+1 : i*3) {
10249e08aacStbbdev const oneapi::tbb::blocked_range<int> r( 0, i, 10 );
10349e08aacStbbdev oneapi::tbb::parallel_for( r, Striker() );
10451c0b2f7Stbbdev for (int k=0; k<N; ++k) {
10551c0b2f7Stbbdev if (Array[k] != (k<i)) CHECK(false);
10651c0b2f7Stbbdev Array[k] = 0;
10751c0b2f7Stbbdev }
10851c0b2f7Stbbdev }
10951c0b2f7Stbbdev }
11051c0b2f7Stbbdev
11151c0b2f7Stbbdev //! Testing blocked_range interface
11251c0b2f7Stbbdev //! \brief \ref interface \ref requirement
11351c0b2f7Stbbdev TEST_CASE("Basic serial") {
11451c0b2f7Stbbdev SerialTest();
11551c0b2f7Stbbdev }
11651c0b2f7Stbbdev
11751c0b2f7Stbbdev //! Testing blocked_range interface with parallel_for
11851c0b2f7Stbbdev //! \brief \ref requirement
11951c0b2f7Stbbdev TEST_CASE("Basic parallel") {
12051c0b2f7Stbbdev for ( auto concurrency_level : utils::concurrency_range() ) {
12149e08aacStbbdev oneapi::tbb::global_control control(oneapi::tbb::global_control::max_allowed_parallelism, concurrency_level);
12251c0b2f7Stbbdev ParallelTest();
12351c0b2f7Stbbdev }
12451c0b2f7Stbbdev }
12551c0b2f7Stbbdev
12651c0b2f7Stbbdev //! Testing blocked_range with proportional splitting
12751c0b2f7Stbbdev //! \brief \ref interface \ref requirement
12851c0b2f7Stbbdev TEST_CASE("blocked_range proportional splitting") {
12949e08aacStbbdev oneapi::tbb::blocked_range<int> original(0, 100);
13049e08aacStbbdev oneapi::tbb::blocked_range<int> first(original);
13149e08aacStbbdev oneapi::tbb::proportional_split ps(3, 1);
13249e08aacStbbdev oneapi::tbb::blocked_range<int> second(first, ps);
13351c0b2f7Stbbdev
13451c0b2f7Stbbdev // Test proportional_split -> split conversion
13549e08aacStbbdev oneapi::tbb::blocked_range<int> copy(original);
13649e08aacStbbdev oneapi::tbb::split s = oneapi::tbb::split(ps);
13749e08aacStbbdev oneapi::tbb::blocked_range<int> splitted_copy(copy, s);
13851c0b2f7Stbbdev CHECK(copy.size() == original.size() / 2);
13951c0b2f7Stbbdev CHECK(splitted_copy.size() == copy.size());
14051c0b2f7Stbbdev
14151c0b2f7Stbbdev
14255f9b178SIvan Kochin int expected_first_end = static_cast<int>(
14355f9b178SIvan Kochin original.begin() + ps.left() * (original.end() - original.begin()) / (ps.left() + ps.right())
14455f9b178SIvan Kochin );
14551c0b2f7Stbbdev utils::check_range_bounds_after_splitting(original, first, second, expected_first_end);
14651c0b2f7Stbbdev }
14751c0b2f7Stbbdev
14851c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
14951c0b2f7Stbbdev //! Testing blocked_range deduction guides
15051c0b2f7Stbbdev //! \brief \ref interface
15151c0b2f7Stbbdev TEST_CASE("Deduction guides") {
15251c0b2f7Stbbdev std::vector<const int *> v;
15351c0b2f7Stbbdev
15451c0b2f7Stbbdev // check blocked_range(Value, Value, size_t)
15549e08aacStbbdev oneapi::tbb::blocked_range r1(v.begin(), v.end());
15649e08aacStbbdev static_assert(std::is_same<decltype(r1), oneapi::tbb::blocked_range<decltype(v)::iterator>>::value);
15751c0b2f7Stbbdev
15851c0b2f7Stbbdev // check blocked_range(blocked_range &)
15949e08aacStbbdev oneapi::tbb::blocked_range r2(r1);
16051c0b2f7Stbbdev static_assert(std::is_same<decltype(r2), decltype(r1)>::value);
16151c0b2f7Stbbdev
16251c0b2f7Stbbdev // check blocked_range(blocked_range &&)
16349e08aacStbbdev oneapi::tbb::blocked_range r3(std::move(r1));
16451c0b2f7Stbbdev static_assert(std::is_same<decltype(r3), decltype(r1)>::value);
16551c0b2f7Stbbdev }
16651c0b2f7Stbbdev #endif
16751c0b2f7Stbbdev
168