151c0b2f7Stbbdev /*
2*a088cfa0SKonstantin Boyarinov     Copyright (c) 2005-2023 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 #define DOCTEST_CONFIG_SUPER_FAST_ASSERTS
1851c0b2f7Stbbdev #include "common/test.h"
1951c0b2f7Stbbdev #include "common/utils.h"
2051c0b2f7Stbbdev #include "common/utils_report.h"
21*a088cfa0SKonstantin Boyarinov #include "common/test_invoke.h"
2251c0b2f7Stbbdev 
2349e08aacStbbdev #include "oneapi/tbb/parallel_for.h"
2449e08aacStbbdev #include "oneapi/tbb/tick_count.h"
2551c0b2f7Stbbdev 
2651c0b2f7Stbbdev #include "../tbb/test_partitioner.h"
2751c0b2f7Stbbdev 
2851c0b2f7Stbbdev #include <atomic>
2951c0b2f7Stbbdev 
3051c0b2f7Stbbdev //! \file conformance_parallel_for.cpp
3151c0b2f7Stbbdev //! \brief Test for [algorithms.parallel_for algorithms.auto_partitioner algorithms.simple_partitioner algorithms.static_partitioner algorithms.affinity_partitioner] specification
3251c0b2f7Stbbdev 
3351c0b2f7Stbbdev static const int N = 500;
3451c0b2f7Stbbdev static std::atomic<int> Array[N];
3551c0b2f7Stbbdev 
3651c0b2f7Stbbdev struct parallel_tag {};
3751c0b2f7Stbbdev struct empty_partitioner_tag {};
3851c0b2f7Stbbdev 
3951c0b2f7Stbbdev // Testing parallel_for with step support
4051c0b2f7Stbbdev const std::size_t PFOR_BUFFER_TEST_SIZE = 1024;
4151c0b2f7Stbbdev // test_buffer has some extra items beyond its right bound
4251c0b2f7Stbbdev const std::size_t PFOR_BUFFER_ACTUAL_SIZE = PFOR_BUFFER_TEST_SIZE + 1024;
4351c0b2f7Stbbdev size_t pfor_buffer[PFOR_BUFFER_ACTUAL_SIZE];
4451c0b2f7Stbbdev 
4551c0b2f7Stbbdev template<typename T>
4651c0b2f7Stbbdev class TestFunctor{
4751c0b2f7Stbbdev public:
operator ()(T index) const4851c0b2f7Stbbdev     void operator ()(T index) const {
4951c0b2f7Stbbdev         pfor_buffer[index]++;
5051c0b2f7Stbbdev     }
5151c0b2f7Stbbdev };
5251c0b2f7Stbbdev 
5351c0b2f7Stbbdev static std::atomic<int> FooBodyCount;
5451c0b2f7Stbbdev 
5551c0b2f7Stbbdev // A range object whose only public members are those required by the Range concept.
5651c0b2f7Stbbdev template<size_t Pad>
5751c0b2f7Stbbdev class FooRange {
5851c0b2f7Stbbdev     // Start of range
5951c0b2f7Stbbdev     int start;
6051c0b2f7Stbbdev 
6151c0b2f7Stbbdev     // Size of range
6251c0b2f7Stbbdev     int size;
FooRange(int start_,int size_)6351c0b2f7Stbbdev     FooRange( int start_, int size_ ) : start(start_), size(size_) {
6451c0b2f7Stbbdev         utils::zero_fill<char>(pad, Pad);
6551c0b2f7Stbbdev         pad[Pad-1] = 'x';
6651c0b2f7Stbbdev     }
6751c0b2f7Stbbdev     template<typename Flavor_, std::size_t Pad_> friend void Flog( );
6851c0b2f7Stbbdev     template<size_t Pad_> friend class FooBody;
6951c0b2f7Stbbdev     void operator&();
7051c0b2f7Stbbdev 
7151c0b2f7Stbbdev     char pad[Pad];
7251c0b2f7Stbbdev public:
empty() const7351c0b2f7Stbbdev     bool empty() const {return size==0;}
is_divisible() const7451c0b2f7Stbbdev     bool is_divisible() const {return size>1;}
FooRange(FooRange & original,oneapi::tbb::split)7549e08aacStbbdev     FooRange( FooRange& original, oneapi::tbb::split ) : size(original.size/2) {
7651c0b2f7Stbbdev         original.size -= size;
7751c0b2f7Stbbdev         start = original.start+original.size;
788e7f9e14SAlex         CHECK_FAST( original.pad[Pad-1]=='x');
7951c0b2f7Stbbdev         pad[Pad-1] = 'x';
8051c0b2f7Stbbdev     }
8151c0b2f7Stbbdev };
8251c0b2f7Stbbdev 
8351c0b2f7Stbbdev // A range object whose only public members are those required by the parallel_for.h body concept.
8451c0b2f7Stbbdev template<size_t Pad>
8551c0b2f7Stbbdev class FooBody {
8651c0b2f7Stbbdev public:
~FooBody()8751c0b2f7Stbbdev     ~FooBody() {
8851c0b2f7Stbbdev         --FooBodyCount;
8951c0b2f7Stbbdev         for( std::size_t i=0; i<sizeof(*this); ++i )
9051c0b2f7Stbbdev             reinterpret_cast<char*>(this)[i] = -1;
9151c0b2f7Stbbdev     }
9251c0b2f7Stbbdev     // Copy constructor
FooBody(const FooBody & other)9351c0b2f7Stbbdev     FooBody( const FooBody& other ) : array(other.array), state(other.state) {
9451c0b2f7Stbbdev         ++FooBodyCount;
958e7f9e14SAlex         CHECK_FAST(state == LIVE);
9651c0b2f7Stbbdev     }
operator ()(FooRange<Pad> & r) const9751c0b2f7Stbbdev     void operator()( FooRange<Pad>& r ) const {
988e7f9e14SAlex         for (int k = r.start; k < r.start + r.size; ++k) {
998e7f9e14SAlex             CHECK_FAST(array[k].load(std::memory_order_relaxed) == 0);
1008e7f9e14SAlex             array[k].store(1, std::memory_order_relaxed);
10151c0b2f7Stbbdev         }
10251c0b2f7Stbbdev     }
10351c0b2f7Stbbdev private:
10451c0b2f7Stbbdev     const int LIVE = 0x1234;
10551c0b2f7Stbbdev     std::atomic<int>* array;
10651c0b2f7Stbbdev     int state;
10751c0b2f7Stbbdev     friend class FooRange<Pad>;
10851c0b2f7Stbbdev     template<typename Flavor_, std::size_t Pad_> friend void Flog( );
FooBody(std::atomic<int> * array_)10951c0b2f7Stbbdev     FooBody( std::atomic<int>* array_ ) : array(array_), state(LIVE) {}
11051c0b2f7Stbbdev };
11151c0b2f7Stbbdev 
11251c0b2f7Stbbdev template <typename Flavor, typename Partitioner, typename Range, typename Body>
11351c0b2f7Stbbdev struct Invoker;
11451c0b2f7Stbbdev 
11551c0b2f7Stbbdev template <typename Range, typename Body>
11651c0b2f7Stbbdev struct Invoker<parallel_tag, empty_partitioner_tag, Range, Body> {
operator ()Invoker11751c0b2f7Stbbdev     void operator()( const Range& r, const Body& body, empty_partitioner_tag& ) {
11849e08aacStbbdev         oneapi::tbb::parallel_for( r, body );
11951c0b2f7Stbbdev     }
12051c0b2f7Stbbdev };
12151c0b2f7Stbbdev 
12251c0b2f7Stbbdev template <typename Partitioner, typename Range, typename Body>
12351c0b2f7Stbbdev struct Invoker<parallel_tag, Partitioner, Range, Body> {
operator ()Invoker12451c0b2f7Stbbdev     void operator()( const Range& r, const Body& body, Partitioner& p ) {
12549e08aacStbbdev         oneapi::tbb::parallel_for( r, body, p );
12651c0b2f7Stbbdev     }
12751c0b2f7Stbbdev };
12851c0b2f7Stbbdev 
12951c0b2f7Stbbdev template <typename Flavor, typename Partitioner, typename T, typename Body>
13051c0b2f7Stbbdev struct InvokerStep;
13151c0b2f7Stbbdev 
13251c0b2f7Stbbdev template <typename T, typename Body>
13351c0b2f7Stbbdev struct InvokerStep<parallel_tag, empty_partitioner_tag, T, Body> {
operator ()InvokerStep13451c0b2f7Stbbdev     void operator()( const T& first, const T& last, const Body& f, empty_partitioner_tag& ) {
13549e08aacStbbdev         oneapi::tbb::parallel_for( first, last, f );
13651c0b2f7Stbbdev     }
operator ()InvokerStep13751c0b2f7Stbbdev     void operator()( const T& first, const T& last, const T& step, const Body& f, empty_partitioner_tag& ) {
13849e08aacStbbdev         oneapi::tbb::parallel_for( first, last, step, f );
13951c0b2f7Stbbdev     }
14051c0b2f7Stbbdev };
14151c0b2f7Stbbdev 
14251c0b2f7Stbbdev template <typename Partitioner, typename T, typename Body>
14351c0b2f7Stbbdev struct InvokerStep<parallel_tag, Partitioner, T, Body> {
operator ()InvokerStep14451c0b2f7Stbbdev     void operator()( const T& first, const T& last, const Body& f, Partitioner& p ) {
14549e08aacStbbdev         oneapi::tbb::parallel_for( first, last, f, p );
14651c0b2f7Stbbdev     }
operator ()InvokerStep14751c0b2f7Stbbdev     void operator()( const T& first, const T& last, const T& step, const Body& f, Partitioner& p ) {
14849e08aacStbbdev         oneapi::tbb::parallel_for( first, last, step, f, p );
14951c0b2f7Stbbdev     }
15051c0b2f7Stbbdev };
15151c0b2f7Stbbdev 
15251c0b2f7Stbbdev template<typename Flavor, std::size_t Pad>
Flog()15351c0b2f7Stbbdev void Flog() {
15451c0b2f7Stbbdev     for ( int i=0; i<N; ++i ) {
15551c0b2f7Stbbdev         for ( int mode = 0; mode < 4; ++mode) {
15651c0b2f7Stbbdev             FooRange<Pad> r( 0, i );
15751c0b2f7Stbbdev             const FooRange<Pad> rc = r;
15851c0b2f7Stbbdev             FooBody<Pad> f( Array );
15951c0b2f7Stbbdev             const FooBody<Pad> fc = f;
16051c0b2f7Stbbdev             for (int a_i = 0; a_i < N; a_i++) {
16151c0b2f7Stbbdev                 Array[a_i].store(0, std::memory_order_relaxed);
16251c0b2f7Stbbdev             }
16351c0b2f7Stbbdev             FooBodyCount = 1;
16451c0b2f7Stbbdev             switch (mode) {
16551c0b2f7Stbbdev             case 0: {
16651c0b2f7Stbbdev                 empty_partitioner_tag p;
16751c0b2f7Stbbdev                 Invoker< Flavor, empty_partitioner_tag, FooRange<Pad>, FooBody<Pad> > invoke_for;
16851c0b2f7Stbbdev                 invoke_for( rc, fc, p );
16951c0b2f7Stbbdev             }
17051c0b2f7Stbbdev                 break;
17151c0b2f7Stbbdev             case 1: {
17249e08aacStbbdev                 Invoker< Flavor, const oneapi::tbb::simple_partitioner, FooRange<Pad>, FooBody<Pad> > invoke_for;
17349e08aacStbbdev                 invoke_for( rc, fc, oneapi::tbb::simple_partitioner() );
17451c0b2f7Stbbdev             }
17551c0b2f7Stbbdev                 break;
17651c0b2f7Stbbdev             case 2: {
17749e08aacStbbdev                 Invoker< Flavor, const oneapi::tbb::auto_partitioner, FooRange<Pad>, FooBody<Pad> > invoke_for;
17849e08aacStbbdev                 invoke_for( rc, fc, oneapi::tbb::auto_partitioner() );
17951c0b2f7Stbbdev             }
18051c0b2f7Stbbdev                 break;
18151c0b2f7Stbbdev             case 3: {
18249e08aacStbbdev                 static oneapi::tbb::affinity_partitioner affinity;
18349e08aacStbbdev                 Invoker< Flavor, oneapi::tbb::affinity_partitioner, FooRange<Pad>, FooBody<Pad> > invoke_for;
18451c0b2f7Stbbdev                 invoke_for( rc, fc, affinity );
18551c0b2f7Stbbdev             }
18651c0b2f7Stbbdev                 break;
18751c0b2f7Stbbdev             }
1888e7f9e14SAlex             CHECK(std::find_if_not(Array, Array + i, [](const std::atomic<int>& v) { return v.load(std::memory_order_relaxed) == 1; }) == Array + i);
1898e7f9e14SAlex             CHECK(std::find_if_not(Array + i, Array + N, [](const std::atomic<int>& v) { return v.load(std::memory_order_relaxed) == 0; }) == Array + N);
19051c0b2f7Stbbdev             CHECK(FooBodyCount == 1);
19151c0b2f7Stbbdev         }
19251c0b2f7Stbbdev     }
19351c0b2f7Stbbdev }
19451c0b2f7Stbbdev 
19551c0b2f7Stbbdev #include <stdexcept> // std::invalid_argument
19651c0b2f7Stbbdev 
19751c0b2f7Stbbdev template <typename Flavor, typename T, typename Partitioner>
TestParallelForWithStepSupportHelper(Partitioner & p)19851c0b2f7Stbbdev void TestParallelForWithStepSupportHelper(Partitioner& p) {
19951c0b2f7Stbbdev     const T pfor_buffer_test_size = static_cast<T>(PFOR_BUFFER_TEST_SIZE);
20051c0b2f7Stbbdev     const T pfor_buffer_actual_size = static_cast<T>(PFOR_BUFFER_ACTUAL_SIZE);
20151c0b2f7Stbbdev     // Testing parallel_for with different step values
20251c0b2f7Stbbdev     InvokerStep< Flavor, Partitioner, T, TestFunctor<T> > invoke_for;
20351c0b2f7Stbbdev     for (T begin = 0; begin < pfor_buffer_test_size - 1; begin += pfor_buffer_test_size / 10 + 1) {
20451c0b2f7Stbbdev         T step;
20551c0b2f7Stbbdev         for (step = 1; step < pfor_buffer_test_size; step++) {
20651c0b2f7Stbbdev             std::memset(pfor_buffer, 0, pfor_buffer_actual_size * sizeof(std::size_t));
20751c0b2f7Stbbdev             if (step == 1){
20851c0b2f7Stbbdev                 invoke_for(begin, pfor_buffer_test_size, TestFunctor<T>(), p);
20951c0b2f7Stbbdev             } else {
21051c0b2f7Stbbdev                 invoke_for(begin, pfor_buffer_test_size, step, TestFunctor<T>(), p);
21151c0b2f7Stbbdev             }
21251c0b2f7Stbbdev             // Verifying that parallel_for processed all items it should
21351c0b2f7Stbbdev             for (T i = begin; i < pfor_buffer_test_size; i = i + step) {
21451c0b2f7Stbbdev                 if (pfor_buffer[i] != 1) {
21551c0b2f7Stbbdev                     CHECK_MESSAGE(false, "parallel_for didn't process all required elements");
21651c0b2f7Stbbdev                 }
21751c0b2f7Stbbdev                 pfor_buffer[i] = 0;
21851c0b2f7Stbbdev             }
21951c0b2f7Stbbdev             // Verifying that no extra items were processed and right bound of array wasn't crossed
22051c0b2f7Stbbdev             for (T i = 0; i < pfor_buffer_actual_size; i++) {
22151c0b2f7Stbbdev                 if (pfor_buffer[i] != 0) {
22251c0b2f7Stbbdev                     CHECK_MESSAGE(false, "parallel_for processed an extra element");
22351c0b2f7Stbbdev                 }
22451c0b2f7Stbbdev             }
22551c0b2f7Stbbdev         }
22651c0b2f7Stbbdev     }
22751c0b2f7Stbbdev }
22851c0b2f7Stbbdev 
22951c0b2f7Stbbdev template <typename Flavor, typename T>
TestParallelForWithStepSupport()23051c0b2f7Stbbdev void TestParallelForWithStepSupport() {
23149e08aacStbbdev     static oneapi::tbb::affinity_partitioner affinity_p;
23249e08aacStbbdev     oneapi::tbb::auto_partitioner auto_p;
23349e08aacStbbdev     oneapi::tbb::simple_partitioner simple_p;
23449e08aacStbbdev     oneapi::tbb::static_partitioner static_p;
23551c0b2f7Stbbdev     empty_partitioner_tag p;
23651c0b2f7Stbbdev 
23751c0b2f7Stbbdev     // Try out all partitioner combinations
23851c0b2f7Stbbdev     TestParallelForWithStepSupportHelper< Flavor,T,empty_partitioner_tag >(p);
23949e08aacStbbdev     TestParallelForWithStepSupportHelper< Flavor,T,const oneapi::tbb::auto_partitioner >(auto_p);
24049e08aacStbbdev     TestParallelForWithStepSupportHelper< Flavor,T,const oneapi::tbb::simple_partitioner >(simple_p);
24149e08aacStbbdev     TestParallelForWithStepSupportHelper< Flavor,T,oneapi::tbb::affinity_partitioner >(affinity_p);
24249e08aacStbbdev     TestParallelForWithStepSupportHelper< Flavor,T,oneapi::tbb::static_partitioner >(static_p);
24351c0b2f7Stbbdev 
24451c0b2f7Stbbdev     // Testing some corner cases
24549e08aacStbbdev     oneapi::tbb::parallel_for(static_cast<T>(2), static_cast<T>(1), static_cast<T>(1), TestFunctor<T>());
24651c0b2f7Stbbdev }
24751c0b2f7Stbbdev 
248*a088cfa0SKonstantin Boyarinov #if __TBB_CPP17_INVOKE_PRESENT
249*a088cfa0SKonstantin Boyarinov class SmartIndex {
250*a088cfa0SKonstantin Boyarinov public:
SmartIndex(std::size_t ri)251*a088cfa0SKonstantin Boyarinov     SmartIndex(std::size_t ri) : real_index(ri), change_vector(nullptr) {}
SmartIndex(std::size_t ri,std::vector<std::size_t> & cv)252*a088cfa0SKonstantin Boyarinov     SmartIndex(std::size_t ri, std::vector<std::size_t>& cv)
253*a088cfa0SKonstantin Boyarinov         : real_index(ri), change_vector(&cv) {}
SmartIndex(const SmartIndex & other)254*a088cfa0SKonstantin Boyarinov     SmartIndex(const SmartIndex& other) : real_index(other.real_index),
255*a088cfa0SKonstantin Boyarinov                                           change_vector(other.change_vector) {}
256*a088cfa0SKonstantin Boyarinov     ~SmartIndex() = default;
257*a088cfa0SKonstantin Boyarinov 
operator =(const SmartIndex & other)258*a088cfa0SKonstantin Boyarinov     SmartIndex& operator=(const SmartIndex& other) {
259*a088cfa0SKonstantin Boyarinov         real_index = other.real_index;
260*a088cfa0SKonstantin Boyarinov         change_vector = other.change_vector;
261*a088cfa0SKonstantin Boyarinov         return *this;
262*a088cfa0SKonstantin Boyarinov     }
263*a088cfa0SKonstantin Boyarinov 
operator <(const SmartIndex & other) const264*a088cfa0SKonstantin Boyarinov     bool operator<(const SmartIndex& other) const {
265*a088cfa0SKonstantin Boyarinov         return real_index < other.real_index;
266*a088cfa0SKonstantin Boyarinov     }
267*a088cfa0SKonstantin Boyarinov 
operator <=(const SmartIndex & other) const268*a088cfa0SKonstantin Boyarinov     bool operator<=(const SmartIndex& other) const {
269*a088cfa0SKonstantin Boyarinov         return real_index <= other.real_index;
270*a088cfa0SKonstantin Boyarinov     }
271*a088cfa0SKonstantin Boyarinov 
operator /(const SmartIndex & other) const272*a088cfa0SKonstantin Boyarinov     SmartIndex operator/(const SmartIndex& other) const {
273*a088cfa0SKonstantin Boyarinov         return {real_index / other.real_index, *change_vector};
274*a088cfa0SKonstantin Boyarinov     }
275*a088cfa0SKonstantin Boyarinov 
operator *(const SmartIndex & other) const276*a088cfa0SKonstantin Boyarinov     SmartIndex operator*(const SmartIndex& other) const {
277*a088cfa0SKonstantin Boyarinov         return {real_index * other.real_index, *change_vector};
278*a088cfa0SKonstantin Boyarinov     }
279*a088cfa0SKonstantin Boyarinov 
operator +(const SmartIndex & other) const280*a088cfa0SKonstantin Boyarinov     SmartIndex operator+(const SmartIndex& other) const {
281*a088cfa0SKonstantin Boyarinov         return {real_index + other.real_index, *change_vector};
282*a088cfa0SKonstantin Boyarinov     }
283*a088cfa0SKonstantin Boyarinov 
operator +=(const SmartIndex & other)284*a088cfa0SKonstantin Boyarinov     SmartIndex& operator+=(const SmartIndex& other) {
285*a088cfa0SKonstantin Boyarinov         real_index += other.real_index;
286*a088cfa0SKonstantin Boyarinov         return *this;
287*a088cfa0SKonstantin Boyarinov     }
288*a088cfa0SKonstantin Boyarinov 
operator ++()289*a088cfa0SKonstantin Boyarinov     SmartIndex& operator++() { ++real_index; return *this; }
290*a088cfa0SKonstantin Boyarinov 
operator -(const SmartIndex & other) const291*a088cfa0SKonstantin Boyarinov     std::size_t operator-(const SmartIndex& other) const {
292*a088cfa0SKonstantin Boyarinov         return real_index - other.real_index;
293*a088cfa0SKonstantin Boyarinov     }
294*a088cfa0SKonstantin Boyarinov 
operator +(std::size_t k)295*a088cfa0SKonstantin Boyarinov     SmartIndex operator+(std::size_t k) {
296*a088cfa0SKonstantin Boyarinov         return {real_index + k, *change_vector};
297*a088cfa0SKonstantin Boyarinov     }
298*a088cfa0SKonstantin Boyarinov 
increase() const299*a088cfa0SKonstantin Boyarinov     void increase() const {
300*a088cfa0SKonstantin Boyarinov         CHECK(change_vector);
301*a088cfa0SKonstantin Boyarinov         ++(*change_vector)[real_index];
302*a088cfa0SKonstantin Boyarinov     }
303*a088cfa0SKonstantin Boyarinov private:
304*a088cfa0SKonstantin Boyarinov     std::size_t real_index;
305*a088cfa0SKonstantin Boyarinov     std::vector<std::size_t>* change_vector;
306*a088cfa0SKonstantin Boyarinov };
307*a088cfa0SKonstantin Boyarinov 
test_pfor_body_invoke()308*a088cfa0SKonstantin Boyarinov void test_pfor_body_invoke() {
309*a088cfa0SKonstantin Boyarinov     const std::size_t number_of_overloads = 5;
310*a088cfa0SKonstantin Boyarinov     const std::size_t iterations = 100000;
311*a088cfa0SKonstantin Boyarinov 
312*a088cfa0SKonstantin Boyarinov     using range_type = test_invoke::SmartRange<std::size_t>;
313*a088cfa0SKonstantin Boyarinov     std::vector<std::size_t> change_vector(iterations, 0);
314*a088cfa0SKonstantin Boyarinov     range_type range{0, iterations, change_vector};
315*a088cfa0SKonstantin Boyarinov 
316*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(range, &range_type::increase);
317*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(range, &range_type::increase, oneapi::tbb::simple_partitioner());
318*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(range, &range_type::increase, oneapi::tbb::auto_partitioner());
319*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(range, &range_type::increase, oneapi::tbb::static_partitioner());
320*a088cfa0SKonstantin Boyarinov     oneapi::tbb::affinity_partitioner aff;
321*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(range, &range_type::increase, aff);
322*a088cfa0SKonstantin Boyarinov 
323*a088cfa0SKonstantin Boyarinov     for (std::size_t item : change_vector) {
324*a088cfa0SKonstantin Boyarinov         CHECK(item == number_of_overloads);
325*a088cfa0SKonstantin Boyarinov     }
326*a088cfa0SKonstantin Boyarinov }
327*a088cfa0SKonstantin Boyarinov 
328*a088cfa0SKonstantin Boyarinov 
test_pfor_func_invoke()329*a088cfa0SKonstantin Boyarinov void test_pfor_func_invoke() {
330*a088cfa0SKonstantin Boyarinov     const std::size_t number_of_overloads = 5;
331*a088cfa0SKonstantin Boyarinov     const std::size_t iterations = 100000;
332*a088cfa0SKonstantin Boyarinov 
333*a088cfa0SKonstantin Boyarinov     std::vector<std::size_t> change_vector(iterations, 0);
334*a088cfa0SKonstantin Boyarinov     SmartIndex first{0, change_vector};
335*a088cfa0SKonstantin Boyarinov     SmartIndex last{iterations, change_vector};
336*a088cfa0SKonstantin Boyarinov     SmartIndex stride{2};
337*a088cfa0SKonstantin Boyarinov 
338*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(first, last, &SmartIndex::increase);
339*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(first, last, &SmartIndex::increase, oneapi::tbb::simple_partitioner());
340*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(first, last, &SmartIndex::increase, oneapi::tbb::auto_partitioner());
341*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(first, last, &SmartIndex::increase, oneapi::tbb::static_partitioner());
342*a088cfa0SKonstantin Boyarinov     oneapi::tbb::affinity_partitioner aff;
343*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(first, last, &SmartIndex::increase, aff);
344*a088cfa0SKonstantin Boyarinov 
345*a088cfa0SKonstantin Boyarinov     for (std::size_t& item : change_vector) {
346*a088cfa0SKonstantin Boyarinov         CHECK(item == number_of_overloads);
347*a088cfa0SKonstantin Boyarinov         item = 0;
348*a088cfa0SKonstantin Boyarinov     }
349*a088cfa0SKonstantin Boyarinov 
350*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(first, last, stride, &SmartIndex::increase);
351*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(first, last, stride, &SmartIndex::increase, oneapi::tbb::simple_partitioner());
352*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(first, last, stride, &SmartIndex::increase, oneapi::tbb::auto_partitioner());
353*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(first, last, stride, &SmartIndex::increase, oneapi::tbb::static_partitioner());
354*a088cfa0SKonstantin Boyarinov     oneapi::tbb::parallel_for(first, last, stride, &SmartIndex::increase, aff);
355*a088cfa0SKonstantin Boyarinov 
356*a088cfa0SKonstantin Boyarinov     CHECK(change_vector[0] == number_of_overloads);
357*a088cfa0SKonstantin Boyarinov     for (std::size_t i = 1; i < iterations; ++i) {
358*a088cfa0SKonstantin Boyarinov         std::size_t expected = change_vector[i - 1] == 0 ? number_of_overloads : 0;
359*a088cfa0SKonstantin Boyarinov         CHECK(change_vector[i] == expected);
360*a088cfa0SKonstantin Boyarinov     }
361*a088cfa0SKonstantin Boyarinov }
362*a088cfa0SKonstantin Boyarinov #endif // __TBB_CPP17_INVOKE_PRESENT
363*a088cfa0SKonstantin Boyarinov 
36451c0b2f7Stbbdev //! Test simple parallel_for with different partitioners
36551c0b2f7Stbbdev //! \brief \ref interface \ref requirement
36651c0b2f7Stbbdev TEST_CASE("Basic parallel_for") {
36751c0b2f7Stbbdev     std::atomic<unsigned long> counter{};
36851c0b2f7Stbbdev     const std::size_t number_of_partitioners = 5;
36951c0b2f7Stbbdev     const std::size_t iterations = 100000;
37051c0b2f7Stbbdev 
__anondcc278fb0302(std::size_t) 37149e08aacStbbdev     oneapi::tbb::parallel_for(std::size_t(0), iterations, [&](std::size_t) {
37251c0b2f7Stbbdev         counter++;
37351c0b2f7Stbbdev     });
37451c0b2f7Stbbdev 
__anondcc278fb0402(std::size_t) 37549e08aacStbbdev     oneapi::tbb::parallel_for(std::size_t(0), iterations, [&](std::size_t) {
37651c0b2f7Stbbdev         counter++;
37749e08aacStbbdev     }, oneapi::tbb::simple_partitioner());
37851c0b2f7Stbbdev 
__anondcc278fb0502(std::size_t) 37949e08aacStbbdev     oneapi::tbb::parallel_for(std::size_t(0), iterations, [&](std::size_t) {
38051c0b2f7Stbbdev         counter++;
38149e08aacStbbdev     }, oneapi::tbb::auto_partitioner());
38251c0b2f7Stbbdev 
__anondcc278fb0602(std::size_t) 38349e08aacStbbdev     oneapi::tbb::parallel_for(std::size_t(0), iterations, [&](std::size_t) {
38451c0b2f7Stbbdev         counter++;
38549e08aacStbbdev     }, oneapi::tbb::static_partitioner());
38651c0b2f7Stbbdev 
38749e08aacStbbdev     oneapi::tbb::affinity_partitioner aff;
__anondcc278fb0702(std::size_t) 38849e08aacStbbdev     oneapi::tbb::parallel_for(std::size_t(0), iterations, [&](std::size_t) {
38951c0b2f7Stbbdev         counter++;
39051c0b2f7Stbbdev     }, aff);
39151c0b2f7Stbbdev 
39251c0b2f7Stbbdev     CHECK_EQ(counter.load(std::memory_order_relaxed), iterations * number_of_partitioners);
39351c0b2f7Stbbdev }
39451c0b2f7Stbbdev 
39551c0b2f7Stbbdev //! Testing parallel for with different partitioners and ranges ranges
39651c0b2f7Stbbdev //! \brief \ref interface \ref requirement \ref stress
39751c0b2f7Stbbdev TEST_CASE("Flog test") {
39851c0b2f7Stbbdev     Flog<parallel_tag, 1>();
39951c0b2f7Stbbdev     Flog<parallel_tag, 10>();
40051c0b2f7Stbbdev     Flog<parallel_tag, 100>();
40151c0b2f7Stbbdev     Flog<parallel_tag, 1000>();
40251c0b2f7Stbbdev     Flog<parallel_tag, 10000>();
40351c0b2f7Stbbdev }
40451c0b2f7Stbbdev 
40551c0b2f7Stbbdev //! Testing parallel for with different types and step
40651c0b2f7Stbbdev //! \brief \ref interface \ref requirement
40751c0b2f7Stbbdev TEST_CASE_TEMPLATE("parallel_for with step support", T, short, unsigned short, int, unsigned int,
40851c0b2f7Stbbdev                                     long, unsigned long, long long, unsigned long long, std::size_t) {
40951c0b2f7Stbbdev     // Testing with different integer types
41051c0b2f7Stbbdev     TestParallelForWithStepSupport<parallel_tag, T>();
41151c0b2f7Stbbdev }
41251c0b2f7Stbbdev 
41351c0b2f7Stbbdev //! Testing with different types of ranges and partitioners
41451c0b2f7Stbbdev //! \brief \ref interface \ref requirement
41551c0b2f7Stbbdev TEST_CASE("Testing parallel_for with partitioners") {
41651c0b2f7Stbbdev     using namespace test_partitioner_utils::interaction_with_range_and_partitioner;
41751c0b2f7Stbbdev 
41851c0b2f7Stbbdev     test_partitioner_utils::SimpleBody b;
41949e08aacStbbdev     oneapi::tbb::affinity_partitioner ap;
42051c0b2f7Stbbdev 
42151c0b2f7Stbbdev     parallel_for(Range1(true, false), b, ap);
42251c0b2f7Stbbdev     parallel_for(Range6(false, true), b, ap);
42351c0b2f7Stbbdev 
42449e08aacStbbdev     parallel_for(Range1(false, true), b, oneapi::tbb::simple_partitioner());
42549e08aacStbbdev     parallel_for(Range6(false, true), b, oneapi::tbb::simple_partitioner());
42651c0b2f7Stbbdev 
42749e08aacStbbdev     parallel_for(Range1(false, true), b, oneapi::tbb::auto_partitioner());
42849e08aacStbbdev     parallel_for(Range6(false, true), b, oneapi::tbb::auto_partitioner());
42951c0b2f7Stbbdev 
43049e08aacStbbdev     parallel_for(Range1(true, false), b, oneapi::tbb::static_partitioner());
43149e08aacStbbdev     parallel_for(Range6(false, true), b, oneapi::tbb::static_partitioner());
43251c0b2f7Stbbdev }
433*a088cfa0SKonstantin Boyarinov 
434*a088cfa0SKonstantin Boyarinov #if __TBB_CPP17_INVOKE_PRESENT
435*a088cfa0SKonstantin Boyarinov //! Test that parallel_for uses std::invoke to run body and function
436*a088cfa0SKonstantin Boyarinov //! \brief \ref interface \ref requirement
437*a088cfa0SKonstantin Boyarinov TEST_CASE("parallel_for and std::invoke") {
438*a088cfa0SKonstantin Boyarinov     test_pfor_body_invoke();
439*a088cfa0SKonstantin Boyarinov     test_pfor_func_invoke();
440*a088cfa0SKonstantin Boyarinov }
441*a088cfa0SKonstantin Boyarinov #endif
442