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_range2d.h"
2349e08aacStbbdev #include "oneapi/tbb/parallel_for.h"
2449e08aacStbbdev #include "oneapi/tbb/global_control.h"
2551c0b2f7Stbbdev
2651c0b2f7Stbbdev //! \file conformance_blocked_range2d.cpp
2751c0b2f7Stbbdev //! \brief Test for [algorithms.blocked_range2d] specification
2851c0b2f7Stbbdev
2951c0b2f7Stbbdev template<typename Tag>
3051c0b2f7Stbbdev class AbstractValueType {
AbstractValueType()3151c0b2f7Stbbdev AbstractValueType() {}
3251c0b2f7Stbbdev int value;
3351c0b2f7Stbbdev public:
3451c0b2f7Stbbdev template<typename OtherTag>
3551c0b2f7Stbbdev friend AbstractValueType<OtherTag> MakeAbstractValueType( int i );
3651c0b2f7Stbbdev
3751c0b2f7Stbbdev template<typename OtherTag>
3851c0b2f7Stbbdev friend int GetValueOf( const AbstractValueType<OtherTag>& v ) ;
3951c0b2f7Stbbdev };
4051c0b2f7Stbbdev
4151c0b2f7Stbbdev template<typename Tag>
MakeAbstractValueType(int i)4251c0b2f7Stbbdev AbstractValueType<Tag> MakeAbstractValueType( int i ) {
4351c0b2f7Stbbdev AbstractValueType<Tag> x;
4451c0b2f7Stbbdev x.value = i;
4551c0b2f7Stbbdev return x;
4651c0b2f7Stbbdev }
4751c0b2f7Stbbdev
4851c0b2f7Stbbdev template<typename Tag>
GetValueOf(const AbstractValueType<Tag> & v)4951c0b2f7Stbbdev int GetValueOf( const AbstractValueType<Tag>& v ) {return v.value;}
5051c0b2f7Stbbdev
5151c0b2f7Stbbdev template<typename Tag>
operator <(const AbstractValueType<Tag> & u,const AbstractValueType<Tag> & v)5251c0b2f7Stbbdev bool operator<( const AbstractValueType<Tag>& u, const AbstractValueType<Tag>& v ) {
5351c0b2f7Stbbdev return GetValueOf(u)<GetValueOf(v);
5451c0b2f7Stbbdev }
5551c0b2f7Stbbdev
5651c0b2f7Stbbdev template<typename Tag>
operator -(const AbstractValueType<Tag> & u,const AbstractValueType<Tag> & v)5751c0b2f7Stbbdev std::size_t operator-( const AbstractValueType<Tag>& u, const AbstractValueType<Tag>& v ) {
5851c0b2f7Stbbdev return GetValueOf(u)-GetValueOf(v);
5951c0b2f7Stbbdev }
6051c0b2f7Stbbdev
6151c0b2f7Stbbdev template<typename Tag>
operator +(const AbstractValueType<Tag> & u,std::size_t offset)6251c0b2f7Stbbdev AbstractValueType<Tag> operator+( const AbstractValueType<Tag>& u, std::size_t offset ) {
6351c0b2f7Stbbdev return MakeAbstractValueType<Tag>(GetValueOf(u)+int(offset));
6451c0b2f7Stbbdev }
6551c0b2f7Stbbdev
6651c0b2f7Stbbdev struct RowTag {};
6751c0b2f7Stbbdev struct ColTag {};
6851c0b2f7Stbbdev
SerialTest()6951c0b2f7Stbbdev static void SerialTest() {
7051c0b2f7Stbbdev typedef AbstractValueType<RowTag> row_type;
7151c0b2f7Stbbdev typedef AbstractValueType<ColTag> col_type;
7249e08aacStbbdev typedef oneapi::tbb::blocked_range2d<row_type,col_type> range_type;
7351c0b2f7Stbbdev for( int row_x=-10; row_x<10; ++row_x ) {
7451c0b2f7Stbbdev for( int row_y=row_x; row_y<10; ++row_y ) {
7551c0b2f7Stbbdev row_type row_i = MakeAbstractValueType<RowTag>(row_x);
7651c0b2f7Stbbdev row_type row_j = MakeAbstractValueType<RowTag>(row_y);
7751c0b2f7Stbbdev for( int row_grain=1; row_grain<10; ++row_grain ) {
7851c0b2f7Stbbdev for( int col_x=-10; col_x<10; ++col_x ) {
7951c0b2f7Stbbdev for( int col_y=col_x; col_y<10; ++col_y ) {
8051c0b2f7Stbbdev col_type col_i = MakeAbstractValueType<ColTag>(col_x);
8151c0b2f7Stbbdev col_type col_j = MakeAbstractValueType<ColTag>(col_y);
8251c0b2f7Stbbdev for( int col_grain=1; col_grain<10; ++col_grain ) {
8351c0b2f7Stbbdev range_type r( row_i, row_j, row_grain, col_i, col_j, col_grain );
8451c0b2f7Stbbdev utils::AssertSameType( r.is_divisible(), true );
8551c0b2f7Stbbdev utils::AssertSameType( r.empty(), true );
8657f524caSIlya Isaev utils::AssertSameType( static_cast<range_type::row_range_type::const_iterator*>(nullptr), static_cast<row_type*>(nullptr) );
8757f524caSIlya Isaev utils::AssertSameType( static_cast<range_type::col_range_type::const_iterator*>(nullptr), static_cast<col_type*>(nullptr) );
8849e08aacStbbdev utils::AssertSameType( r.rows(), oneapi::tbb::blocked_range<row_type>( row_i, row_j, 1 ));
8949e08aacStbbdev utils::AssertSameType( r.cols(), oneapi::tbb::blocked_range<col_type>( col_i, col_j, 1 ));
9051c0b2f7Stbbdev REQUIRE( r.empty()==(row_x==row_y||col_x==col_y) );
9151c0b2f7Stbbdev REQUIRE( r.is_divisible()==(row_y-row_x>row_grain||col_y-col_x>col_grain) );
9251c0b2f7Stbbdev if( r.is_divisible() ) {
9349e08aacStbbdev range_type r2(r,oneapi::tbb::split());
9451c0b2f7Stbbdev if( GetValueOf(r2.rows().begin())==GetValueOf(r.rows().begin()) ) {
9551c0b2f7Stbbdev REQUIRE( GetValueOf(r2.rows().end())==GetValueOf(r.rows().end()) );
9651c0b2f7Stbbdev REQUIRE( GetValueOf(r2.cols().begin())==GetValueOf(r.cols().end()) );
9751c0b2f7Stbbdev } else {
9851c0b2f7Stbbdev REQUIRE( GetValueOf(r2.cols().end())==GetValueOf(r.cols().end()) );
9951c0b2f7Stbbdev REQUIRE( GetValueOf(r2.rows().begin())==GetValueOf(r.rows().end()) );
10051c0b2f7Stbbdev }
10151c0b2f7Stbbdev }
10251c0b2f7Stbbdev }
10351c0b2f7Stbbdev }
10451c0b2f7Stbbdev }
10551c0b2f7Stbbdev }
10651c0b2f7Stbbdev }
10751c0b2f7Stbbdev }
10851c0b2f7Stbbdev }
10951c0b2f7Stbbdev
11051c0b2f7Stbbdev const int N = 1<<10;
11151c0b2f7Stbbdev
11251c0b2f7Stbbdev unsigned char Array[N][N];
11351c0b2f7Stbbdev
11451c0b2f7Stbbdev struct Striker {
11551c0b2f7Stbbdev // Note: we use <int> here instead of <long> in order to test for problems similar to Quad 407676
operator ()Striker11649e08aacStbbdev void operator()( const oneapi::tbb::blocked_range2d<int>& r ) const {
11749e08aacStbbdev for( oneapi::tbb::blocked_range<int>::const_iterator i=r.rows().begin(); i!=r.rows().end(); ++i )
11849e08aacStbbdev for( oneapi::tbb::blocked_range<int>::const_iterator j=r.cols().begin(); j!=r.cols().end(); ++j )
11951c0b2f7Stbbdev ++Array[i][j];
12051c0b2f7Stbbdev }
12151c0b2f7Stbbdev };
12251c0b2f7Stbbdev
ParallelTest()12351c0b2f7Stbbdev void ParallelTest() {
12451c0b2f7Stbbdev for( int i=0; i<N; i=i<3 ? i+1 : i*3 ) {
12551c0b2f7Stbbdev for( int j=0; j<N; j=j<3 ? j+1 : j*3 ) {
12649e08aacStbbdev const oneapi::tbb::blocked_range2d<int> r( 0, i, 7, 0, j, 5 );
12749e08aacStbbdev oneapi::tbb::parallel_for( r, Striker() );
12851c0b2f7Stbbdev for( int k=0; k<N; ++k ) {
12951c0b2f7Stbbdev for( int l=0; l<N; ++l ) {
13051c0b2f7Stbbdev if( Array[k][l] != (k<i && l<j) ) REQUIRE(false);
13151c0b2f7Stbbdev Array[k][l] = 0;
13251c0b2f7Stbbdev }
13351c0b2f7Stbbdev }
13451c0b2f7Stbbdev }
13551c0b2f7Stbbdev }
13651c0b2f7Stbbdev }
13751c0b2f7Stbbdev
13851c0b2f7Stbbdev //! Testing blocked_range2d interface
13951c0b2f7Stbbdev //! \brief \ref interface \ref requirement
14051c0b2f7Stbbdev TEST_CASE("Serial test") {
14151c0b2f7Stbbdev SerialTest();
14251c0b2f7Stbbdev }
14351c0b2f7Stbbdev
14451c0b2f7Stbbdev //! Testing blocked_range2d interface with parallel_for
14551c0b2f7Stbbdev //! \brief \ref requirement
14651c0b2f7Stbbdev TEST_CASE("Parallel test") {
14751c0b2f7Stbbdev for ( auto concurrency_level : utils::concurrency_range() ) {
14849e08aacStbbdev oneapi::tbb::global_control control(oneapi::tbb::global_control::max_allowed_parallelism, concurrency_level);
14951c0b2f7Stbbdev ParallelTest();
15051c0b2f7Stbbdev }
15151c0b2f7Stbbdev }
15251c0b2f7Stbbdev
15351c0b2f7Stbbdev //! Testing blocked_range2d with proportional splitting
15451c0b2f7Stbbdev //! \brief \ref interface \ref requirement
15551c0b2f7Stbbdev TEST_CASE("blocked_range2d proportional splitting") {
15649e08aacStbbdev oneapi::tbb::blocked_range2d<int> original(0, 100, 0, 100);
15749e08aacStbbdev oneapi::tbb::blocked_range2d<int> first(original);
15849e08aacStbbdev oneapi::tbb::proportional_split ps(3, 1);
15949e08aacStbbdev oneapi::tbb::blocked_range2d<int> second(first, ps);
16051c0b2f7Stbbdev
16155f9b178SIvan Kochin int expected_first_end = static_cast<int>(
16255f9b178SIvan Kochin original.rows().begin() + ps.left() * (original.rows().end() - original.rows().begin()) / (ps.left() + ps.right())
16355f9b178SIvan Kochin );
16451c0b2f7Stbbdev if (first.rows().size() == second.rows().size()) {
16551c0b2f7Stbbdev // Splitting was made by cols
16651c0b2f7Stbbdev utils::check_range_bounds_after_splitting(original.cols(), first.cols(), second.cols(), expected_first_end);
16751c0b2f7Stbbdev } else {
16851c0b2f7Stbbdev // Splitting was made by rows
16951c0b2f7Stbbdev utils::check_range_bounds_after_splitting(original.rows(), first.rows(), second.rows(), expected_first_end);
17051c0b2f7Stbbdev }
17151c0b2f7Stbbdev }
17251c0b2f7Stbbdev
17351c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
17451c0b2f7Stbbdev //! Testing blocked_range2d deduction guides
17551c0b2f7Stbbdev //! \brief \ref interface
17651c0b2f7Stbbdev TEST_CASE("Deduction guides") {
17751c0b2f7Stbbdev std::vector<const unsigned long *> v;
17851c0b2f7Stbbdev std::vector<double> v2;
17951c0b2f7Stbbdev
18051c0b2f7Stbbdev // check blocked_range2d(RowValue, RowValue, size_t, ColValue, ColValue, size_t)
18149e08aacStbbdev oneapi::tbb::blocked_range2d r1(v.begin(), v.end(), 2, v2.begin(), v2.end(), 2);
18249e08aacStbbdev static_assert(std::is_same<decltype(r1), oneapi::tbb::blocked_range2d<decltype(v)::iterator, decltype(v2)::iterator>>::value);
18351c0b2f7Stbbdev
18451c0b2f7Stbbdev // check blocked_range2d(blocked_range2d &)
18549e08aacStbbdev oneapi::tbb::blocked_range2d r2(r1);
18651c0b2f7Stbbdev static_assert(std::is_same<decltype(r2), decltype(r1)>::value);
18751c0b2f7Stbbdev
18851c0b2f7Stbbdev // check blocked_range2d(blocked_range2d &&)
18949e08aacStbbdev oneapi::tbb::blocked_range2d r3(std::move(r1));
19051c0b2f7Stbbdev static_assert(std::is_same<decltype(r3), decltype(r1)>::value);
19151c0b2f7Stbbdev }
19251c0b2f7Stbbdev #endif
19351c0b2f7Stbbdev
194