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