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_range3d.h"
2349e08aacStbbdev #include "oneapi/tbb/parallel_for.h"
2449e08aacStbbdev #include "oneapi/tbb/global_control.h"
2551c0b2f7Stbbdev 
2651c0b2f7Stbbdev #include <vector>
2751c0b2f7Stbbdev 
2851c0b2f7Stbbdev //! \file conformance_blocked_range3d.cpp
2951c0b2f7Stbbdev //! \brief Test for [algorithms.blocked_range3d] specification
3051c0b2f7Stbbdev 
3151c0b2f7Stbbdev template<typename Tag>
3251c0b2f7Stbbdev class AbstractValueType {
AbstractValueType()3351c0b2f7Stbbdev     AbstractValueType() {}
3451c0b2f7Stbbdev     int value;
3551c0b2f7Stbbdev public:
3651c0b2f7Stbbdev     template<typename OtherTag>
3751c0b2f7Stbbdev     friend AbstractValueType<OtherTag> MakeAbstractValueType( int i );
3851c0b2f7Stbbdev 
3951c0b2f7Stbbdev     template<typename OtherTag>
4051c0b2f7Stbbdev     friend int GetValueOf( const AbstractValueType<OtherTag>& v ) ;
4151c0b2f7Stbbdev };
4251c0b2f7Stbbdev 
4351c0b2f7Stbbdev template<typename Tag>
MakeAbstractValueType(int i)4451c0b2f7Stbbdev AbstractValueType<Tag> MakeAbstractValueType( int i ) {
4551c0b2f7Stbbdev     AbstractValueType<Tag> x;
4651c0b2f7Stbbdev     x.value = i;
4751c0b2f7Stbbdev     return x;
4851c0b2f7Stbbdev }
4951c0b2f7Stbbdev 
5051c0b2f7Stbbdev template<typename Tag>
GetValueOf(const AbstractValueType<Tag> & v)5151c0b2f7Stbbdev int GetValueOf( const AbstractValueType<Tag>& v ) {return v.value;}
5251c0b2f7Stbbdev 
5351c0b2f7Stbbdev template<typename Tag>
operator <(const AbstractValueType<Tag> & u,const AbstractValueType<Tag> & v)5451c0b2f7Stbbdev bool operator<( const AbstractValueType<Tag>& u, const AbstractValueType<Tag>& v ) {
5551c0b2f7Stbbdev     return GetValueOf(u)<GetValueOf(v);
5651c0b2f7Stbbdev }
5751c0b2f7Stbbdev 
5851c0b2f7Stbbdev template<typename Tag>
operator -(const AbstractValueType<Tag> & u,const AbstractValueType<Tag> & v)5951c0b2f7Stbbdev std::size_t operator-( const AbstractValueType<Tag>& u, const AbstractValueType<Tag>& v ) {
6051c0b2f7Stbbdev     return GetValueOf(u)-GetValueOf(v);
6151c0b2f7Stbbdev }
6251c0b2f7Stbbdev 
6351c0b2f7Stbbdev template<typename Tag>
operator +(const AbstractValueType<Tag> & u,std::size_t offset)6451c0b2f7Stbbdev AbstractValueType<Tag> operator+( const AbstractValueType<Tag>& u, std::size_t offset ) {
6551c0b2f7Stbbdev     return MakeAbstractValueType<Tag>(GetValueOf(u)+int(offset));
6651c0b2f7Stbbdev }
6751c0b2f7Stbbdev 
6851c0b2f7Stbbdev struct PageTag {};
6951c0b2f7Stbbdev struct RowTag {};
7051c0b2f7Stbbdev struct ColTag {};
7151c0b2f7Stbbdev 
SerialTest()7251c0b2f7Stbbdev static void SerialTest() {
7351c0b2f7Stbbdev     typedef AbstractValueType<PageTag> page_type;
7451c0b2f7Stbbdev     typedef AbstractValueType<RowTag> row_type;
7551c0b2f7Stbbdev     typedef AbstractValueType<ColTag> col_type;
7649e08aacStbbdev     typedef oneapi::tbb::blocked_range3d<page_type,row_type,col_type> range_type;
7751c0b2f7Stbbdev     for( int page_x=-4; page_x<4; ++page_x ) {
7851c0b2f7Stbbdev         for( int page_y=page_x; page_y<4; ++page_y ) {
7951c0b2f7Stbbdev             page_type page_i = MakeAbstractValueType<PageTag>(page_x);
8051c0b2f7Stbbdev             page_type page_j = MakeAbstractValueType<PageTag>(page_y);
8151c0b2f7Stbbdev             for( int page_grain=1; page_grain<4; ++page_grain ) {
8251c0b2f7Stbbdev                 for( int row_x=-4; row_x<4; ++row_x ) {
8351c0b2f7Stbbdev                     for( int row_y=row_x; row_y<4; ++row_y ) {
8451c0b2f7Stbbdev                         row_type row_i = MakeAbstractValueType<RowTag>(row_x);
8551c0b2f7Stbbdev                         row_type row_j = MakeAbstractValueType<RowTag>(row_y);
8651c0b2f7Stbbdev                         for( int row_grain=1; row_grain<4; ++row_grain ) {
8751c0b2f7Stbbdev                             for( int col_x=-4; col_x<4; ++col_x ) {
8851c0b2f7Stbbdev                                 for( int col_y=col_x; col_y<4; ++col_y ) {
8951c0b2f7Stbbdev                                     col_type col_i = MakeAbstractValueType<ColTag>(col_x);
9051c0b2f7Stbbdev                                     col_type col_j = MakeAbstractValueType<ColTag>(col_y);
9151c0b2f7Stbbdev                                     for( int col_grain=1; col_grain<4; ++col_grain ) {
9251c0b2f7Stbbdev                                         range_type r( page_i, page_j, page_grain, row_i, row_j, row_grain, col_i, col_j, col_grain );
9351c0b2f7Stbbdev                                         utils::AssertSameType( r.is_divisible(), true );
9451c0b2f7Stbbdev 
9551c0b2f7Stbbdev                                         utils::AssertSameType( r.empty(), true );
9651c0b2f7Stbbdev 
9757f524caSIlya Isaev                                         utils::AssertSameType( static_cast<range_type::page_range_type::const_iterator*>(nullptr), static_cast<page_type*>(nullptr) );
9857f524caSIlya Isaev                                         utils::AssertSameType( static_cast<range_type::row_range_type::const_iterator*>(nullptr), static_cast<row_type*>(nullptr) );
9957f524caSIlya Isaev                                         utils::AssertSameType( static_cast<range_type::col_range_type::const_iterator*>(nullptr), static_cast<col_type*>(nullptr) );
10051c0b2f7Stbbdev 
10149e08aacStbbdev                                         utils::AssertSameType( r.pages(), oneapi::tbb::blocked_range<page_type>( page_i, page_j, 1 ));
10249e08aacStbbdev                                         utils::AssertSameType( r.rows(), oneapi::tbb::blocked_range<row_type>( row_i, row_j, 1 ));
10349e08aacStbbdev                                         utils::AssertSameType( r.cols(), oneapi::tbb::blocked_range<col_type>( col_i, col_j, 1 ));
10451c0b2f7Stbbdev 
10551c0b2f7Stbbdev                                         REQUIRE( r.empty()==(page_x==page_y||row_x==row_y||col_x==col_y) );
10651c0b2f7Stbbdev 
10751c0b2f7Stbbdev                                         REQUIRE( r.is_divisible()==(page_y-page_x>page_grain||row_y-row_x>row_grain||col_y-col_x>col_grain) );
10851c0b2f7Stbbdev 
10951c0b2f7Stbbdev                                         if( r.is_divisible() ) {
11049e08aacStbbdev                                             range_type r2(r,oneapi::tbb::split());
11151c0b2f7Stbbdev                                             if( (GetValueOf(r2.pages().begin())==GetValueOf(r.pages().begin())) && (GetValueOf(r2.rows().begin())==GetValueOf(r.rows().begin())) ) {
11251c0b2f7Stbbdev                                                 REQUIRE( GetValueOf(r2.pages().end())==GetValueOf(r.pages().end()) );
11351c0b2f7Stbbdev                                                 REQUIRE( GetValueOf(r2.rows().end())==GetValueOf(r.rows().end()) );
11451c0b2f7Stbbdev                                                 REQUIRE( GetValueOf(r2.cols().begin())==GetValueOf(r.cols().end()) );
11551c0b2f7Stbbdev                                             } else {
11651c0b2f7Stbbdev                                                 if ( (GetValueOf(r2.pages().begin())==GetValueOf(r.pages().begin())) && (GetValueOf(r2.cols().begin())==GetValueOf(r.cols().begin())) ) {
11751c0b2f7Stbbdev                                                     REQUIRE( GetValueOf(r2.pages().end())==GetValueOf(r.pages().end()) );
11851c0b2f7Stbbdev                                                     REQUIRE( GetValueOf(r2.cols().end())==GetValueOf(r.cols().end()) );
11951c0b2f7Stbbdev                                                     REQUIRE( GetValueOf(r2.rows().begin())==GetValueOf(r.rows().end()) );
12051c0b2f7Stbbdev                                                 } else {
12151c0b2f7Stbbdev                                                     REQUIRE( GetValueOf(r2.rows().end())==GetValueOf(r.rows().end()) );
12251c0b2f7Stbbdev                                                     REQUIRE( GetValueOf(r2.cols().end())==GetValueOf(r.cols().end()) );
12351c0b2f7Stbbdev                                                     REQUIRE( GetValueOf(r2.pages().begin())==GetValueOf(r.pages().end()) );
12451c0b2f7Stbbdev                                                 }
12551c0b2f7Stbbdev                                             }
12651c0b2f7Stbbdev                                         }
12751c0b2f7Stbbdev                                     }
12851c0b2f7Stbbdev                                 }
12951c0b2f7Stbbdev                             }
13051c0b2f7Stbbdev                         }
13151c0b2f7Stbbdev                     }
13251c0b2f7Stbbdev                 }
13351c0b2f7Stbbdev             }
13451c0b2f7Stbbdev         }
13551c0b2f7Stbbdev     }
13651c0b2f7Stbbdev }
13751c0b2f7Stbbdev 
13851c0b2f7Stbbdev const int N = 1<<5;
13951c0b2f7Stbbdev 
14051c0b2f7Stbbdev unsigned char Array[N][N][N];
14151c0b2f7Stbbdev 
14251c0b2f7Stbbdev struct Striker {
14351c0b2f7Stbbdev    // Note: we use <int> here instead of <long> in order to test for problems similar to Quad 407676
operator ()Striker14449e08aacStbbdev     void operator()( const oneapi::tbb::blocked_range3d<int>& r ) const {
14549e08aacStbbdev         for( oneapi::tbb::blocked_range<int>::const_iterator i=r.pages().begin(); i!=r.pages().end(); ++i )
14649e08aacStbbdev             for( oneapi::tbb::blocked_range<int>::const_iterator j=r.rows().begin(); j!=r.rows().end(); ++j )
14749e08aacStbbdev                 for( oneapi::tbb::blocked_range<int>::const_iterator k=r.cols().begin(); k!=r.cols().end(); ++k )
14851c0b2f7Stbbdev                     ++Array[i][j][k];
14951c0b2f7Stbbdev     }
15051c0b2f7Stbbdev };
15151c0b2f7Stbbdev 
ParallelTest()15251c0b2f7Stbbdev void ParallelTest() {
15351c0b2f7Stbbdev     for( int i=0; i<N; i=i<3 ? i+1 : i*3 ) {
15451c0b2f7Stbbdev         for( int j=0; j<N; j=j<3 ? j+1 : j*3 ) {
15551c0b2f7Stbbdev             for( int k=0; k<N; k=k<3 ? k+1 : k*3 ) {
15649e08aacStbbdev                 const oneapi::tbb::blocked_range3d<int> r( 0, i, 5, 0, j, 3, 0, k, 1 );
15749e08aacStbbdev                 oneapi::tbb::parallel_for( r, Striker() );
15851c0b2f7Stbbdev                 for( int l=0; l<N; ++l ) {
15951c0b2f7Stbbdev                     for( int m=0; m<N; ++m ) {
16051c0b2f7Stbbdev                         for( int n=0; n<N; ++n ) {
16151c0b2f7Stbbdev                              if( Array[l][m][n] != (l<i && m<j && n<k) ) REQUIRE(false);
16251c0b2f7Stbbdev                              Array[l][m][n] = 0;
16351c0b2f7Stbbdev                         }
16451c0b2f7Stbbdev                     }
16551c0b2f7Stbbdev                 }
16651c0b2f7Stbbdev             }
16751c0b2f7Stbbdev         }
16851c0b2f7Stbbdev     }
16951c0b2f7Stbbdev }
17051c0b2f7Stbbdev 
17151c0b2f7Stbbdev //! Testing blocked_range3d interface
17251c0b2f7Stbbdev //! \brief \ref interface \ref requirement
17351c0b2f7Stbbdev TEST_CASE("Serial test") {
17451c0b2f7Stbbdev     SerialTest();
17551c0b2f7Stbbdev }
17651c0b2f7Stbbdev 
17751c0b2f7Stbbdev //! Testing blocked_range3d interface with parallel_for
17851c0b2f7Stbbdev //! \brief \ref requirement
17951c0b2f7Stbbdev TEST_CASE("Parallel test") {
18051c0b2f7Stbbdev     for ( auto concurrency_level : utils::concurrency_range() ) {
18149e08aacStbbdev         oneapi::tbb::global_control control(oneapi::tbb::global_control::max_allowed_parallelism, concurrency_level);
18251c0b2f7Stbbdev         ParallelTest();
18351c0b2f7Stbbdev     }
18451c0b2f7Stbbdev }
18551c0b2f7Stbbdev 
18651c0b2f7Stbbdev //! Testing blocked_range3d with proportional splitting
18751c0b2f7Stbbdev //! \brief \ref interface \ref requirement
18851c0b2f7Stbbdev TEST_CASE("blocked_range3d proportional splitting") {
18949e08aacStbbdev     oneapi::tbb::blocked_range3d<int> original(0, 100, 0, 100, 0, 100);
19049e08aacStbbdev     oneapi::tbb::blocked_range3d<int> first(original);
19149e08aacStbbdev     oneapi::tbb::proportional_split ps(3, 1);
19249e08aacStbbdev     oneapi::tbb::blocked_range3d<int> second(first, ps);
19351c0b2f7Stbbdev 
19455f9b178SIvan Kochin     int expected_first_end = static_cast<int>(
19555f9b178SIvan Kochin         original.rows().begin() + ps.left() * (original.rows().end() - original.rows().begin()) / (ps.left() + ps.right())
19655f9b178SIvan Kochin     );
19751c0b2f7Stbbdev     if (first.rows().size() == second.rows().size()) {
19851c0b2f7Stbbdev         if (first.cols().size() == second.cols().size()) {
19951c0b2f7Stbbdev             // Splitting was made by pages
20051c0b2f7Stbbdev             utils::check_range_bounds_after_splitting(original.pages(), first.pages(), second.pages(), expected_first_end);
20151c0b2f7Stbbdev         } else {
20251c0b2f7Stbbdev             // Splitting was made by cols
20351c0b2f7Stbbdev             utils::check_range_bounds_after_splitting(original.cols(), first.cols(), second.cols(), expected_first_end);
20451c0b2f7Stbbdev         }
20551c0b2f7Stbbdev     } else {
20651c0b2f7Stbbdev         // Splitting was made by rows
20751c0b2f7Stbbdev         utils::check_range_bounds_after_splitting(original.rows(), first.rows(), second.rows(), expected_first_end);
20851c0b2f7Stbbdev     }
20951c0b2f7Stbbdev }
21051c0b2f7Stbbdev 
21151c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
21251c0b2f7Stbbdev //! Testing blocked_range3d deduction guides
21351c0b2f7Stbbdev //! \brief \ref interface
21451c0b2f7Stbbdev TEST_CASE("Deduction guides") {
21551c0b2f7Stbbdev     std::vector<const unsigned long *> v;
21651c0b2f7Stbbdev     std::vector<double> v2;
21751c0b2f7Stbbdev     std::vector<std::vector<int>> v3;
21851c0b2f7Stbbdev 
21951c0b2f7Stbbdev     // check blocked_range2d(PageValue, PageValue, size_t, RowValue, RowValue, size_t, ColValue, ColValue, size_t)
22049e08aacStbbdev     oneapi::tbb::blocked_range3d r1(v.begin(), v.end(), 2, v2.begin(), v2.end(), 2, v3.begin(), v3.end(), 6);
22151c0b2f7Stbbdev     static_assert(std::is_same<decltype(r1),
22249e08aacStbbdev         oneapi::tbb::blocked_range3d<decltype(v)::iterator, decltype(v2)::iterator, decltype(v3)::iterator>>::value);
22351c0b2f7Stbbdev 
22451c0b2f7Stbbdev     // check blocked_range2d(blocked_range3d &)
22549e08aacStbbdev     oneapi::tbb::blocked_range3d r2(r1);
22651c0b2f7Stbbdev     static_assert(std::is_same<decltype(r2), decltype(r1)>::value);
22751c0b2f7Stbbdev 
22851c0b2f7Stbbdev     // check blocked_range2d(blocked_range3d &&)
22949e08aacStbbdev     oneapi::tbb::blocked_range3d r3(std::move(r1));
230b15aabb3Stbbdev     static_assert(std::is_same<decltype(r3), decltype(r1)>::value);
23151c0b2f7Stbbdev }
23251c0b2f7Stbbdev #endif
23351c0b2f7Stbbdev 
234