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