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 <atomic>
1851c0b2f7Stbbdev
1951c0b2f7Stbbdev #include "common/parallel_reduce_common.h"
2051c0b2f7Stbbdev #include "common/cpu_usertime.h"
2151c0b2f7Stbbdev #include "common/exception_handling.h"
22478de5b1Stbbdev #include "common/concepts_common.h"
2351c0b2f7Stbbdev
2451c0b2f7Stbbdev //! \file test_parallel_reduce.cpp
2551c0b2f7Stbbdev //! \brief Test for [algorithms.parallel_reduce algorithms.parallel_deterministic_reduce] specification
2651c0b2f7Stbbdev
2755f9b178SIvan Kochin #if _MSC_VER
2855f9b178SIvan Kochin #pragma warning (push)
2955f9b178SIvan Kochin // Suppress conditional expression is constant
3055f9b178SIvan Kochin #pragma warning (disable: 4127)
3155f9b178SIvan Kochin #endif //#if _MSC_VER
3255f9b178SIvan Kochin
3351c0b2f7Stbbdev using ValueType = uint64_t;
3451c0b2f7Stbbdev
3551c0b2f7Stbbdev struct Sum {
3651c0b2f7Stbbdev template<typename T>
operator ()Sum3751c0b2f7Stbbdev T operator() ( const T& v1, const T& v2 ) const {
3851c0b2f7Stbbdev return v1 + v2;
3951c0b2f7Stbbdev }
4051c0b2f7Stbbdev };
4151c0b2f7Stbbdev
4251c0b2f7Stbbdev struct Accumulator {
operator ()Accumulator4351c0b2f7Stbbdev ValueType operator() ( const tbb::blocked_range<ValueType*>& r, ValueType value ) const {
4451c0b2f7Stbbdev for ( ValueType* pv = r.begin(); pv != r.end(); ++pv )
4551c0b2f7Stbbdev value += *pv;
4651c0b2f7Stbbdev return value;
4751c0b2f7Stbbdev }
4851c0b2f7Stbbdev };
4951c0b2f7Stbbdev
5051c0b2f7Stbbdev class ParallelSumTester {
5151c0b2f7Stbbdev public:
5251c0b2f7Stbbdev ParallelSumTester( const ParallelSumTester& ) = default;
5351c0b2f7Stbbdev void operator=( const ParallelSumTester& ) = delete;
5451c0b2f7Stbbdev
ParallelSumTester()5551c0b2f7Stbbdev ParallelSumTester() : m_range(nullptr, nullptr) {
5651c0b2f7Stbbdev m_array = new ValueType[unsigned(count)];
5751c0b2f7Stbbdev for ( ValueType i = 0; i < count; ++i )
5851c0b2f7Stbbdev m_array[i] = i + 1;
5951c0b2f7Stbbdev m_range = tbb::blocked_range<ValueType*>( m_array, m_array + count );
6051c0b2f7Stbbdev }
~ParallelSumTester()6151c0b2f7Stbbdev ~ParallelSumTester() { delete[] m_array; }
6251c0b2f7Stbbdev
6351c0b2f7Stbbdev template<typename Partitioner>
CheckParallelReduce()6451c0b2f7Stbbdev void CheckParallelReduce() {
6551c0b2f7Stbbdev Partitioner partitioner;
6651c0b2f7Stbbdev ValueType result1 = reduce_invoker<ValueType>( m_range, Accumulator(), Sum(), partitioner );
6751c0b2f7Stbbdev REQUIRE_MESSAGE( result1 == expected, "Wrong parallel summation result" );
6851c0b2f7Stbbdev ValueType result2 = reduce_invoker<ValueType>( m_range,
6951c0b2f7Stbbdev [](const tbb::blocked_range<ValueType*>& r, ValueType value) -> ValueType {
7051c0b2f7Stbbdev for ( const ValueType* pv = r.begin(); pv != r.end(); ++pv )
7151c0b2f7Stbbdev value += *pv;
7251c0b2f7Stbbdev return value;
7351c0b2f7Stbbdev },
7451c0b2f7Stbbdev Sum(),
7551c0b2f7Stbbdev partitioner
7651c0b2f7Stbbdev );
7751c0b2f7Stbbdev REQUIRE_MESSAGE( result2 == expected, "Wrong parallel summation result" );
7851c0b2f7Stbbdev }
7951c0b2f7Stbbdev private:
8051c0b2f7Stbbdev ValueType* m_array;
8151c0b2f7Stbbdev tbb::blocked_range<ValueType*> m_range;
8251c0b2f7Stbbdev static const ValueType count, expected;
8351c0b2f7Stbbdev };
8451c0b2f7Stbbdev
8551c0b2f7Stbbdev const ValueType ParallelSumTester::count = 1000000;
8651c0b2f7Stbbdev const ValueType ParallelSumTester::expected = count * (count + 1) / 2;
8751c0b2f7Stbbdev
8851c0b2f7Stbbdev namespace test_cancellation {
8951c0b2f7Stbbdev
9051c0b2f7Stbbdev struct ReduceToCancel {
operator ()test_cancellation::ReduceToCancel9151c0b2f7Stbbdev std::size_t operator()( const tbb::blocked_range<std::size_t>&, std::size_t ) const {
9251c0b2f7Stbbdev ++g_CurExecuted;
9351c0b2f7Stbbdev Cancellator::WaitUntilReady();
9451c0b2f7Stbbdev return 1;
9551c0b2f7Stbbdev }
9651c0b2f7Stbbdev }; // struct ReduceToCancel
9751c0b2f7Stbbdev
9851c0b2f7Stbbdev struct JoinToCancel {
operator ()test_cancellation::JoinToCancel9951c0b2f7Stbbdev std::size_t operator()( std::size_t, std::size_t ) const {
10051c0b2f7Stbbdev ++g_CurExecuted;
10151c0b2f7Stbbdev Cancellator::WaitUntilReady();
10251c0b2f7Stbbdev return 1;
10351c0b2f7Stbbdev }
10451c0b2f7Stbbdev }; // struct Join
10551c0b2f7Stbbdev
10651c0b2f7Stbbdev struct ReduceFunctorToCancel {
10751c0b2f7Stbbdev std::size_t result;
10851c0b2f7Stbbdev
ReduceFunctorToCanceltest_cancellation::ReduceFunctorToCancel10951c0b2f7Stbbdev ReduceFunctorToCancel() : result(0) {}
ReduceFunctorToCanceltest_cancellation::ReduceFunctorToCancel11051c0b2f7Stbbdev ReduceFunctorToCancel( ReduceFunctorToCancel&, tbb::split ) : result(0) {}
11151c0b2f7Stbbdev
operator ()test_cancellation::ReduceFunctorToCancel11251c0b2f7Stbbdev void operator()( const tbb::blocked_range<std::size_t>& br ) {
11351c0b2f7Stbbdev result = ReduceToCancel{}(br, result);
11451c0b2f7Stbbdev }
11551c0b2f7Stbbdev
jointest_cancellation::ReduceFunctorToCancel11651c0b2f7Stbbdev void join( ReduceFunctorToCancel& rhs ) {
11751c0b2f7Stbbdev result = JoinToCancel{}(result, rhs.result);
11851c0b2f7Stbbdev }
11951c0b2f7Stbbdev }; // struct ReduceFunctorToCancel
12051c0b2f7Stbbdev
12151c0b2f7Stbbdev static constexpr std::size_t buffer_test_size = 1024;
12251c0b2f7Stbbdev static constexpr std::size_t maxParallelReduceRunnerMode = 9;
12351c0b2f7Stbbdev
12451c0b2f7Stbbdev template <std::size_t Mode>
12551c0b2f7Stbbdev class ParallelReduceRunner {
12651c0b2f7Stbbdev tbb::task_group_context& my_ctx;
12751c0b2f7Stbbdev
12851c0b2f7Stbbdev static_assert(Mode >= 0 && Mode <= maxParallelReduceRunnerMode, "Incorrect mode for ParallelReduceTask");
12951c0b2f7Stbbdev
13051c0b2f7Stbbdev template <typename... Args>
run_parallel_reduce(Args &&...args) const13151c0b2f7Stbbdev void run_parallel_reduce( Args&&... args ) const {
13251c0b2f7Stbbdev switch(Mode % 5) {
13351c0b2f7Stbbdev case 0 : {
13451c0b2f7Stbbdev tbb::parallel_reduce(std::forward<Args>(args)..., my_ctx);
13551c0b2f7Stbbdev break;
13651c0b2f7Stbbdev }
13751c0b2f7Stbbdev case 1 : {
13851c0b2f7Stbbdev tbb::parallel_reduce(std::forward<Args>(args)..., tbb::simple_partitioner{}, my_ctx);
13951c0b2f7Stbbdev break;
14051c0b2f7Stbbdev }
14151c0b2f7Stbbdev case 2 : {
14251c0b2f7Stbbdev tbb::parallel_reduce(std::forward<Args>(args)..., tbb::auto_partitioner{}, my_ctx);
14351c0b2f7Stbbdev break;
14451c0b2f7Stbbdev }
14551c0b2f7Stbbdev case 3 : {
14651c0b2f7Stbbdev tbb::parallel_reduce(std::forward<Args>(args)..., tbb::static_partitioner{}, my_ctx);
14751c0b2f7Stbbdev break;
14851c0b2f7Stbbdev }
14951c0b2f7Stbbdev case 4 : {
15051c0b2f7Stbbdev tbb::affinity_partitioner aff;
15151c0b2f7Stbbdev tbb::parallel_reduce(std::forward<Args>(args)..., aff, my_ctx);
15251c0b2f7Stbbdev break;
15351c0b2f7Stbbdev }
15451c0b2f7Stbbdev }
15551c0b2f7Stbbdev }
15651c0b2f7Stbbdev
15751c0b2f7Stbbdev public:
ParallelReduceRunner(tbb::task_group_context & ctx)15851c0b2f7Stbbdev ParallelReduceRunner( tbb::task_group_context& ctx )
15951c0b2f7Stbbdev : my_ctx(ctx) {}
16051c0b2f7Stbbdev
operator ()() const16151c0b2f7Stbbdev void operator()() const {
16251c0b2f7Stbbdev tbb::blocked_range<std::size_t> br(0, buffer_test_size);
16351c0b2f7Stbbdev if (Mode < 5) {
16451c0b2f7Stbbdev ReduceFunctorToCancel functor;
16551c0b2f7Stbbdev run_parallel_reduce(br, functor);
16651c0b2f7Stbbdev } else {
167478de5b1Stbbdev run_parallel_reduce(br, std::size_t(0), ReduceToCancel{}, JoinToCancel{});
16851c0b2f7Stbbdev }
16951c0b2f7Stbbdev }
17051c0b2f7Stbbdev }; // class ParallelReduceRunner
17151c0b2f7Stbbdev
17251c0b2f7Stbbdev static constexpr std::size_t maxParallelDeterministicReduceRunnerMode = 5;
17351c0b2f7Stbbdev
17451c0b2f7Stbbdev // TODO: unify with ParallelReduceRunner
17551c0b2f7Stbbdev template <std::size_t Mode>
17651c0b2f7Stbbdev class ParallelDeterministicReduceRunner {
17751c0b2f7Stbbdev tbb::task_group_context& my_ctx;
17851c0b2f7Stbbdev
17951c0b2f7Stbbdev static_assert(Mode >= 0 && Mode <= maxParallelDeterministicReduceRunnerMode, "Incorrect Mode for deterministic_reduce task");
18051c0b2f7Stbbdev
18151c0b2f7Stbbdev template <typename... Args>
run_parallel_deterministic_reduce(Args &&...args) const18251c0b2f7Stbbdev void run_parallel_deterministic_reduce( Args&&... args ) const {
18351c0b2f7Stbbdev switch(Mode % 3) {
18451c0b2f7Stbbdev case 0 : {
18551c0b2f7Stbbdev tbb::parallel_deterministic_reduce(std::forward<Args>(args)..., my_ctx);
18651c0b2f7Stbbdev break;
18751c0b2f7Stbbdev }
18851c0b2f7Stbbdev case 1 : {
18951c0b2f7Stbbdev tbb::parallel_deterministic_reduce(std::forward<Args>(args)..., tbb::simple_partitioner{}, my_ctx);
19051c0b2f7Stbbdev break;
19151c0b2f7Stbbdev }
19251c0b2f7Stbbdev case 2 : {
19351c0b2f7Stbbdev tbb::parallel_deterministic_reduce(std::forward<Args>(args)..., tbb::static_partitioner{}, my_ctx);
19451c0b2f7Stbbdev break;
19551c0b2f7Stbbdev }
19651c0b2f7Stbbdev }
19751c0b2f7Stbbdev }
19851c0b2f7Stbbdev
19951c0b2f7Stbbdev public:
ParallelDeterministicReduceRunner(tbb::task_group_context & ctx)20051c0b2f7Stbbdev ParallelDeterministicReduceRunner( tbb::task_group_context& ctx )
20151c0b2f7Stbbdev : my_ctx(ctx) {}
20251c0b2f7Stbbdev
operator ()() const20351c0b2f7Stbbdev void operator()() const {
20451c0b2f7Stbbdev tbb::blocked_range<std::size_t> br(0, buffer_test_size);
20551c0b2f7Stbbdev if (Mode < 3) {
20651c0b2f7Stbbdev ReduceFunctorToCancel functor;
20751c0b2f7Stbbdev run_parallel_deterministic_reduce(br, functor);
20851c0b2f7Stbbdev } else {
209478de5b1Stbbdev run_parallel_deterministic_reduce(br, std::size_t(0), ReduceToCancel{}, JoinToCancel{});
21051c0b2f7Stbbdev }
21151c0b2f7Stbbdev }
21251c0b2f7Stbbdev }; // class ParallelDeterministicReduceRunner
21351c0b2f7Stbbdev
21451c0b2f7Stbbdev template <std::size_t Mode>
run_parallel_reduce_cancellation_test()21551c0b2f7Stbbdev void run_parallel_reduce_cancellation_test() {
21651c0b2f7Stbbdev for ( auto concurrency_level : utils::concurrency_range() ) {
21751c0b2f7Stbbdev if (concurrency_level < 2) continue;
21851c0b2f7Stbbdev
21951c0b2f7Stbbdev tbb::global_control gc(tbb::global_control::max_allowed_parallelism, concurrency_level);
22051c0b2f7Stbbdev ResetEhGlobals();
22151c0b2f7Stbbdev RunCancellationTest<ParallelReduceRunner<Mode>, Cancellator>();
22251c0b2f7Stbbdev }
22351c0b2f7Stbbdev }
22451c0b2f7Stbbdev
22551c0b2f7Stbbdev template <std::size_t Mode>
run_parallel_deterministic_reduce_cancellation_test()22651c0b2f7Stbbdev void run_parallel_deterministic_reduce_cancellation_test() {
22751c0b2f7Stbbdev for ( auto concurrency_level : utils::concurrency_range() ) {
22851c0b2f7Stbbdev if (concurrency_level < 2) continue;
22951c0b2f7Stbbdev
23051c0b2f7Stbbdev tbb::global_control gc(tbb::global_control::max_allowed_parallelism, concurrency_level);
23151c0b2f7Stbbdev ResetEhGlobals();
23251c0b2f7Stbbdev RunCancellationTest<ParallelDeterministicReduceRunner<Mode>, Cancellator>();
23351c0b2f7Stbbdev }
23451c0b2f7Stbbdev }
23551c0b2f7Stbbdev
23651c0b2f7Stbbdev template <std::size_t Mode>
23751c0b2f7Stbbdev struct ParallelReduceTestRunner {
runtest_cancellation::ParallelReduceTestRunner23851c0b2f7Stbbdev static void run() {
23951c0b2f7Stbbdev run_parallel_reduce_cancellation_test<Mode>();
24051c0b2f7Stbbdev ParallelReduceTestRunner<Mode + 1>::run();
24151c0b2f7Stbbdev }
24251c0b2f7Stbbdev }; // struct ParallelReduceTestRunner
24351c0b2f7Stbbdev
24451c0b2f7Stbbdev template <>
24551c0b2f7Stbbdev struct ParallelReduceTestRunner<maxParallelReduceRunnerMode> {
runtest_cancellation::ParallelReduceTestRunner24651c0b2f7Stbbdev static void run() {
24751c0b2f7Stbbdev run_parallel_reduce_cancellation_test<maxParallelReduceRunnerMode>();
24851c0b2f7Stbbdev }
24951c0b2f7Stbbdev }; // struct ParallelReduceTestRunner<maxParallelReduceRunnerMode>
25051c0b2f7Stbbdev
25151c0b2f7Stbbdev template <std::size_t Mode>
25251c0b2f7Stbbdev struct ParallelDeterministicReduceTestRunner {
runtest_cancellation::ParallelDeterministicReduceTestRunner25351c0b2f7Stbbdev static void run() {
25451c0b2f7Stbbdev run_parallel_deterministic_reduce_cancellation_test<Mode>();
25551c0b2f7Stbbdev ParallelDeterministicReduceTestRunner<Mode + 1>::run();
25651c0b2f7Stbbdev }
25751c0b2f7Stbbdev }; // struct ParallelDeterministicReduceTestRunner
25851c0b2f7Stbbdev
25951c0b2f7Stbbdev template <>
26051c0b2f7Stbbdev struct ParallelDeterministicReduceTestRunner<maxParallelDeterministicReduceRunnerMode> {
runtest_cancellation::ParallelDeterministicReduceTestRunner26151c0b2f7Stbbdev static void run() {
26251c0b2f7Stbbdev run_parallel_deterministic_reduce_cancellation_test<maxParallelDeterministicReduceRunnerMode>();
26351c0b2f7Stbbdev }
26451c0b2f7Stbbdev }; // struct ParallelDeterministicReduceTestRunner<maxParallelDeterministicReduceRunnerMode>
26551c0b2f7Stbbdev
26651c0b2f7Stbbdev } // namespace test_cancellation
26751c0b2f7Stbbdev
268478de5b1Stbbdev #if __TBB_CPP20_CONCEPTS_PRESENT
269478de5b1Stbbdev template <typename... Args>
270478de5b1Stbbdev concept can_call_parallel_reduce_basic = requires( Args&&... args ) {
271478de5b1Stbbdev tbb::parallel_reduce(std::forward<Args>(args)...);
272478de5b1Stbbdev };
273478de5b1Stbbdev
274478de5b1Stbbdev template <typename... Args>
275478de5b1Stbbdev concept can_call_parallel_deterministic_reduce_basic = requires ( Args&&... args ) {
276478de5b1Stbbdev tbb::parallel_deterministic_reduce(std::forward<Args>(args)...);
277478de5b1Stbbdev };
278478de5b1Stbbdev
279478de5b1Stbbdev template <typename... Args>
280478de5b1Stbbdev concept can_call_preduce_helper = can_call_parallel_reduce_basic<Args...> &&
281478de5b1Stbbdev can_call_parallel_reduce_basic<Args..., tbb::task_group_context&>;
282478de5b1Stbbdev
283478de5b1Stbbdev template <typename... Args>
284478de5b1Stbbdev concept can_call_pdet_reduce_helper = can_call_parallel_deterministic_reduce_basic<Args...> &&
285478de5b1Stbbdev can_call_parallel_deterministic_reduce_basic<Args..., tbb::task_group_context&>;
286478de5b1Stbbdev
287478de5b1Stbbdev template <typename... Args>
288478de5b1Stbbdev concept can_call_preduce_with_partitioner = can_call_preduce_helper<Args...> &&
289478de5b1Stbbdev can_call_preduce_helper<Args..., const tbb::simple_partitioner&> &&
290478de5b1Stbbdev can_call_preduce_helper<Args..., const tbb::auto_partitioner&> &&
291478de5b1Stbbdev can_call_preduce_helper<Args..., const tbb::static_partitioner&> &&
292478de5b1Stbbdev can_call_preduce_helper<Args..., tbb::affinity_partitioner&>;
293478de5b1Stbbdev
294478de5b1Stbbdev template <typename... Args>
295478de5b1Stbbdev concept can_call_pdet_reduce_with_partitioner = can_call_pdet_reduce_helper<Args...> &&
296478de5b1Stbbdev can_call_pdet_reduce_helper<Args..., const tbb::simple_partitioner&> &&
297478de5b1Stbbdev can_call_pdet_reduce_helper<Args..., const tbb::static_partitioner&>;
298478de5b1Stbbdev
299478de5b1Stbbdev template <typename Range, typename Body>
300478de5b1Stbbdev concept can_call_imperative_preduce = can_call_preduce_with_partitioner<const Range&, Body&>;
301478de5b1Stbbdev
302478de5b1Stbbdev template <typename Range, typename Body>
303478de5b1Stbbdev concept can_call_imperative_pdet_reduce = can_call_pdet_reduce_with_partitioner<const Range&, Body&>;
304478de5b1Stbbdev
305478de5b1Stbbdev template <typename Range, typename Value, typename RealBody, typename Reduction>
306478de5b1Stbbdev concept can_call_functional_preduce = can_call_preduce_with_partitioner<const Range&, const Value&,
307478de5b1Stbbdev const RealBody&, const Reduction&>;
308478de5b1Stbbdev
309478de5b1Stbbdev template <typename Range, typename Value, typename RealBody, typename Reduction>
310478de5b1Stbbdev concept can_call_functional_pdet_reduce = can_call_pdet_reduce_with_partitioner<const Range&, const Value&,
311478de5b1Stbbdev const RealBody&, const Reduction&>;
312478de5b1Stbbdev
313478de5b1Stbbdev template <typename Range>
314478de5b1Stbbdev using CorrectBody = test_concepts::parallel_reduce_body::Correct<Range>;
315478de5b1Stbbdev
316478de5b1Stbbdev template <typename Range>
317478de5b1Stbbdev using CorrectFunc = test_concepts::parallel_reduce_function::Correct<Range>;
318478de5b1Stbbdev
319478de5b1Stbbdev using CorrectReduction = test_concepts::parallel_reduce_combine::Correct<int>;
320478de5b1Stbbdev using CorrectRange = test_concepts::range::Correct;
321478de5b1Stbbdev
test_preduce_range_constraints()322478de5b1Stbbdev void test_preduce_range_constraints() {
323478de5b1Stbbdev using namespace test_concepts::range;
324478de5b1Stbbdev static_assert(can_call_imperative_preduce<Correct, CorrectBody<Correct>>);
325478de5b1Stbbdev static_assert(!can_call_imperative_preduce<NonCopyable, CorrectBody<NonCopyable>>);
326478de5b1Stbbdev static_assert(!can_call_imperative_preduce<NonDestructible, CorrectBody<NonDestructible>>);
327478de5b1Stbbdev static_assert(!can_call_imperative_preduce<NonSplittable, CorrectBody<NonSplittable>>);
328478de5b1Stbbdev static_assert(!can_call_imperative_preduce<NoEmpty, CorrectBody<NoEmpty>>);
329478de5b1Stbbdev static_assert(!can_call_imperative_preduce<EmptyNonConst, CorrectBody<EmptyNonConst>>);
330478de5b1Stbbdev static_assert(!can_call_imperative_preduce<WrongReturnEmpty, CorrectBody<WrongReturnEmpty>>);
331478de5b1Stbbdev static_assert(!can_call_imperative_preduce<NoIsDivisible, CorrectBody<NoIsDivisible>>);
332478de5b1Stbbdev static_assert(!can_call_imperative_preduce<IsDivisibleNonConst, CorrectBody<NoIsDivisible>>);
333478de5b1Stbbdev static_assert(!can_call_imperative_preduce<WrongReturnIsDivisible, CorrectBody<WrongReturnIsDivisible>>);
334478de5b1Stbbdev
335478de5b1Stbbdev static_assert(can_call_functional_preduce<Correct, int, CorrectFunc<Correct>, CorrectReduction>);
336478de5b1Stbbdev static_assert(!can_call_functional_preduce<NonCopyable, int, CorrectFunc<NonCopyable>, CorrectReduction>);
337478de5b1Stbbdev static_assert(!can_call_functional_preduce<NonDestructible, int, CorrectFunc<NonDestructible>, CorrectReduction>);
338478de5b1Stbbdev static_assert(!can_call_functional_preduce<NonSplittable, int, CorrectFunc<NonSplittable>, CorrectReduction>);
339478de5b1Stbbdev static_assert(!can_call_functional_preduce<NoEmpty, int, CorrectFunc<NoEmpty>, CorrectReduction>);
340478de5b1Stbbdev static_assert(!can_call_functional_preduce<EmptyNonConst, int, CorrectFunc<EmptyNonConst>, CorrectReduction>);
341478de5b1Stbbdev static_assert(!can_call_functional_preduce<WrongReturnEmpty, int, CorrectFunc<WrongReturnEmpty>, CorrectReduction>);
342478de5b1Stbbdev static_assert(!can_call_functional_preduce<NoIsDivisible, int, CorrectFunc<NoIsDivisible>, CorrectReduction>);
343478de5b1Stbbdev static_assert(!can_call_functional_preduce<IsDivisibleNonConst, int, CorrectFunc<IsDivisibleNonConst>, CorrectReduction>);
344478de5b1Stbbdev static_assert(!can_call_functional_preduce<WrongReturnIsDivisible, int, CorrectFunc<WrongReturnIsDivisible>, CorrectReduction>);
345478de5b1Stbbdev }
346478de5b1Stbbdev
test_preduce_body_constraints()347478de5b1Stbbdev void test_preduce_body_constraints() {
348478de5b1Stbbdev using namespace test_concepts::parallel_reduce_body;
349478de5b1Stbbdev static_assert(can_call_imperative_preduce<CorrectRange, Correct<CorrectRange>>);
350478de5b1Stbbdev static_assert(!can_call_imperative_preduce<CorrectRange, NonSplittable<CorrectRange>>);
351478de5b1Stbbdev static_assert(!can_call_imperative_preduce<CorrectRange, NonDestructible<CorrectRange>>);
352478de5b1Stbbdev static_assert(!can_call_imperative_preduce<CorrectRange, NoOperatorRoundBrackets<CorrectRange>>);
353478de5b1Stbbdev static_assert(!can_call_imperative_preduce<CorrectRange, WrongInputOperatorRoundBrackets<CorrectRange>>);
354478de5b1Stbbdev static_assert(!can_call_imperative_preduce<CorrectRange, NoJoin<CorrectRange>>);
355478de5b1Stbbdev static_assert(!can_call_imperative_preduce<CorrectRange, WrongInputJoin<CorrectRange>>);
356478de5b1Stbbdev }
357478de5b1Stbbdev
test_preduce_func_constraints()358478de5b1Stbbdev void test_preduce_func_constraints() {
359478de5b1Stbbdev using namespace test_concepts::parallel_reduce_function;
360478de5b1Stbbdev static_assert(can_call_functional_preduce<CorrectRange, int, Correct<CorrectRange>, CorrectReduction>);
361478de5b1Stbbdev static_assert(!can_call_functional_preduce<CorrectRange, int, NoOperatorRoundBrackets<CorrectRange>, CorrectReduction>);
362478de5b1Stbbdev static_assert(!can_call_functional_preduce<CorrectRange, int, OperatorRoundBracketsNonConst<CorrectRange>, CorrectReduction>);
363478de5b1Stbbdev static_assert(!can_call_functional_preduce<CorrectRange, int, WrongFirstInputOperatorRoundBrackets<CorrectRange>, CorrectReduction>);
364478de5b1Stbbdev static_assert(!can_call_functional_preduce<CorrectRange, int, WrongSecondInputOperatorRoundBrackets<CorrectRange>, CorrectReduction>);
365478de5b1Stbbdev static_assert(!can_call_functional_preduce<CorrectRange, int, WrongReturnOperatorRoundBrackets<CorrectRange>, CorrectReduction>);
366478de5b1Stbbdev }
367478de5b1Stbbdev
test_preduce_combine_constraints()368478de5b1Stbbdev void test_preduce_combine_constraints() {
369478de5b1Stbbdev using namespace test_concepts::parallel_reduce_combine;
370478de5b1Stbbdev static_assert(can_call_functional_preduce<CorrectRange, int, CorrectFunc<CorrectRange>, Correct<int>>);
371478de5b1Stbbdev static_assert(!can_call_functional_preduce<CorrectRange, int, CorrectFunc<CorrectRange>, NoOperatorRoundBrackets<int>>);
372478de5b1Stbbdev static_assert(!can_call_functional_preduce<CorrectRange, int, CorrectFunc<CorrectRange>, OperatorRoundBracketsNonConst<int>>);
373478de5b1Stbbdev static_assert(!can_call_functional_preduce<CorrectRange, int, CorrectFunc<CorrectRange>, WrongFirstInputOperatorRoundBrackets<int>>);
374478de5b1Stbbdev static_assert(!can_call_functional_preduce<CorrectRange, int, CorrectFunc<CorrectRange>, WrongSecondInputOperatorRoundBrackets<int>>);
375478de5b1Stbbdev static_assert(!can_call_functional_preduce<CorrectRange, int, CorrectFunc<CorrectRange>, WrongReturnOperatorRoundBrackets<int>>);
376478de5b1Stbbdev }
377478de5b1Stbbdev
test_pdet_reduce_range_constraints()378478de5b1Stbbdev void test_pdet_reduce_range_constraints() {
379478de5b1Stbbdev using namespace test_concepts::range;
380478de5b1Stbbdev static_assert(can_call_imperative_pdet_reduce<Correct, CorrectBody<Correct>>);
381478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<NonCopyable, CorrectBody<NonCopyable>>);
382478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<NonDestructible, CorrectBody<NonDestructible>>);
383478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<NonSplittable, CorrectBody<NonSplittable>>);
384478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<NoEmpty, CorrectBody<NoEmpty>>);
385478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<EmptyNonConst, CorrectBody<EmptyNonConst>>);
386478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<WrongReturnEmpty, CorrectBody<WrongReturnEmpty>>);
387478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<NoIsDivisible, CorrectBody<NoIsDivisible>>);
388478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<IsDivisibleNonConst, CorrectBody<NoIsDivisible>>);
389478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<WrongReturnIsDivisible, CorrectBody<WrongReturnIsDivisible>>);
390478de5b1Stbbdev
391478de5b1Stbbdev static_assert(can_call_functional_pdet_reduce<Correct, int, CorrectFunc<Correct>, CorrectReduction>);
392478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<NonCopyable, int, CorrectFunc<NonCopyable>, CorrectReduction>);
393478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<NonDestructible, int, CorrectFunc<NonDestructible>, CorrectReduction>);
394478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<NonSplittable, int, CorrectFunc<NonSplittable>, CorrectReduction>);
395478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<NoEmpty, int, CorrectFunc<NoEmpty>, CorrectReduction>);
396478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<EmptyNonConst, int, CorrectFunc<EmptyNonConst>, CorrectReduction>);
397478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<WrongReturnEmpty, int, CorrectFunc<WrongReturnEmpty>, CorrectReduction>);
398478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<NoIsDivisible, int, CorrectFunc<NoIsDivisible>, CorrectReduction>);
399478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<IsDivisibleNonConst, int, CorrectFunc<IsDivisibleNonConst>, CorrectReduction>);
400478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<WrongReturnIsDivisible, int, CorrectFunc<WrongReturnIsDivisible>, CorrectReduction>);
401478de5b1Stbbdev }
402478de5b1Stbbdev
test_pdet_reduce_body_constraints()403478de5b1Stbbdev void test_pdet_reduce_body_constraints() {
404478de5b1Stbbdev using namespace test_concepts::parallel_reduce_body;
405478de5b1Stbbdev static_assert(can_call_imperative_pdet_reduce<CorrectRange, Correct<CorrectRange>>);
406478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<CorrectRange, NonSplittable<CorrectRange>>);
407478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<CorrectRange, NonDestructible<CorrectRange>>);
408478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<CorrectRange, NoOperatorRoundBrackets<CorrectRange>>);
409478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<CorrectRange, WrongInputOperatorRoundBrackets<CorrectRange>>);
410478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<CorrectRange, NoJoin<CorrectRange>>);
411478de5b1Stbbdev static_assert(!can_call_imperative_pdet_reduce<CorrectRange, WrongInputJoin<CorrectRange>>);
412478de5b1Stbbdev }
413478de5b1Stbbdev
test_pdet_reduce_func_constraints()414478de5b1Stbbdev void test_pdet_reduce_func_constraints() {
415478de5b1Stbbdev using namespace test_concepts::parallel_reduce_function;
416478de5b1Stbbdev static_assert(can_call_functional_pdet_reduce<CorrectRange, int, Correct<CorrectRange>, CorrectReduction>);
417478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<CorrectRange, int, NoOperatorRoundBrackets<CorrectRange>, CorrectReduction>);
418478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<CorrectRange, int, OperatorRoundBracketsNonConst<CorrectRange>, CorrectReduction>);
419478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<CorrectRange, int, WrongFirstInputOperatorRoundBrackets<CorrectRange>, CorrectReduction>);
420478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<CorrectRange, int, WrongSecondInputOperatorRoundBrackets<CorrectRange>, CorrectReduction>);
421478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<CorrectRange, int, WrongReturnOperatorRoundBrackets<CorrectRange>, CorrectReduction>);
422478de5b1Stbbdev }
423478de5b1Stbbdev
test_pdet_reduce_combine_constraints()424478de5b1Stbbdev void test_pdet_reduce_combine_constraints() {
425478de5b1Stbbdev using namespace test_concepts::parallel_reduce_combine;
426478de5b1Stbbdev static_assert(can_call_functional_pdet_reduce<CorrectRange, int, CorrectFunc<CorrectRange>, Correct<int>>);
427478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<CorrectRange, int, CorrectFunc<CorrectRange>, NoOperatorRoundBrackets<int>>);
428478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<CorrectRange, int, CorrectFunc<CorrectRange>, OperatorRoundBracketsNonConst<int>>);
429478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<CorrectRange, int, CorrectFunc<CorrectRange>, WrongFirstInputOperatorRoundBrackets<int>>);
430478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<CorrectRange, int, CorrectFunc<CorrectRange>, WrongSecondInputOperatorRoundBrackets<int>>);
431478de5b1Stbbdev static_assert(!can_call_functional_pdet_reduce<CorrectRange, int, CorrectFunc<CorrectRange>, WrongReturnOperatorRoundBrackets<int>>);
432478de5b1Stbbdev }
433478de5b1Stbbdev #endif // __TBB_CPP20_CONCEPTS_PRESENT
434478de5b1Stbbdev
43551c0b2f7Stbbdev //! Test parallel summation correctness
43651c0b2f7Stbbdev //! \brief \ref stress
43751c0b2f7Stbbdev TEST_CASE("Test parallel summation correctness") {
43851c0b2f7Stbbdev ParallelSumTester pst;
43951c0b2f7Stbbdev pst.CheckParallelReduce<utils_default_partitioner>();
44051c0b2f7Stbbdev pst.CheckParallelReduce<tbb::simple_partitioner>();
44151c0b2f7Stbbdev pst.CheckParallelReduce<tbb::auto_partitioner>();
44251c0b2f7Stbbdev pst.CheckParallelReduce<tbb::affinity_partitioner>();
44351c0b2f7Stbbdev pst.CheckParallelReduce<tbb::static_partitioner>();
44451c0b2f7Stbbdev }
44551c0b2f7Stbbdev
44651c0b2f7Stbbdev static std::atomic<long> ForkCount;
44751c0b2f7Stbbdev static std::atomic<long> FooBodyCount;
44851c0b2f7Stbbdev
44951c0b2f7Stbbdev //! Class with public interface that is exactly minimal requirements for Range concept
45051c0b2f7Stbbdev class MinimalRange {
45151c0b2f7Stbbdev size_t begin, end;
45251c0b2f7Stbbdev friend class FooBody;
MinimalRange(size_t i)45351c0b2f7Stbbdev explicit MinimalRange( size_t i ) : begin(0), end(i) {}
45451c0b2f7Stbbdev template <typename Partitioner_> friend void TestSplitting( std::size_t nthread );
45551c0b2f7Stbbdev public:
MinimalRange(MinimalRange & r,tbb::split)45651c0b2f7Stbbdev MinimalRange( MinimalRange& r, tbb::split ) : end(r.end) {
45751c0b2f7Stbbdev begin = r.end = (r.begin+r.end)/2;
45851c0b2f7Stbbdev }
is_divisible() const45951c0b2f7Stbbdev bool is_divisible() const {return end-begin>=2;}
empty() const46051c0b2f7Stbbdev bool empty() const {return begin==end;}
46151c0b2f7Stbbdev };
46251c0b2f7Stbbdev
46351c0b2f7Stbbdev //! Class with public interface that is exactly minimal requirements for Body of a parallel_reduce
46451c0b2f7Stbbdev class FooBody {
46551c0b2f7Stbbdev private:
46651c0b2f7Stbbdev FooBody( const FooBody& ); // Deny access
46751c0b2f7Stbbdev void operator=( const FooBody& ); // Deny access
46851c0b2f7Stbbdev template <typename Partitioner_> friend void TestSplitting( std::size_t nthread );
46957f524caSIlya Isaev //! Parent that created this body via split operation. nullptr if original body.
47051c0b2f7Stbbdev FooBody* parent;
47151c0b2f7Stbbdev //! Total number of index values processed by body and its children.
47251c0b2f7Stbbdev size_t sum;
47351c0b2f7Stbbdev //! Range that has been processed so far by this body and its children.
47451c0b2f7Stbbdev size_t begin, end;
47551c0b2f7Stbbdev //! True if body has not yet been processed at least once by operator().
47651c0b2f7Stbbdev bool is_new;
47751c0b2f7Stbbdev //! 1 if body was created by split; 0 if original body.
47851c0b2f7Stbbdev int forked;
FooBody()47951c0b2f7Stbbdev FooBody() {++FooBodyCount;}
48051c0b2f7Stbbdev public:
~FooBody()48151c0b2f7Stbbdev ~FooBody() {
48251c0b2f7Stbbdev forked = 0xDEADBEEF;
48351c0b2f7Stbbdev sum=0xDEADBEEF;
48451c0b2f7Stbbdev --FooBodyCount;
48551c0b2f7Stbbdev }
FooBody(FooBody & other,tbb::split)48651c0b2f7Stbbdev FooBody( FooBody& other, tbb::split ) {
48751c0b2f7Stbbdev ++FooBodyCount;
48851c0b2f7Stbbdev ++ForkCount;
48951c0b2f7Stbbdev sum = 0;
49051c0b2f7Stbbdev parent = &other;
49151c0b2f7Stbbdev is_new = true;
49251c0b2f7Stbbdev forked = 1;
49351c0b2f7Stbbdev }
49451c0b2f7Stbbdev
init()49551c0b2f7Stbbdev void init() {
49651c0b2f7Stbbdev sum = 0;
49751c0b2f7Stbbdev parent = nullptr;
49851c0b2f7Stbbdev is_new = true;
49951c0b2f7Stbbdev forked = 0;
50051c0b2f7Stbbdev begin = ~size_t(0);
50151c0b2f7Stbbdev end = ~size_t(0);
50251c0b2f7Stbbdev }
50351c0b2f7Stbbdev
join(FooBody & s)50451c0b2f7Stbbdev void join( FooBody& s ) {
50551c0b2f7Stbbdev REQUIRE( s.forked==1 );
50651c0b2f7Stbbdev REQUIRE( this!=&s );
50751c0b2f7Stbbdev REQUIRE( this==s.parent );
50851c0b2f7Stbbdev REQUIRE( end==s.begin );
50951c0b2f7Stbbdev end = s.end;
51051c0b2f7Stbbdev sum += s.sum;
51151c0b2f7Stbbdev s.forked = 2;
51251c0b2f7Stbbdev }
operator ()(const MinimalRange & r)51351c0b2f7Stbbdev void operator()( const MinimalRange& r ) {
51451c0b2f7Stbbdev for( size_t k=r.begin; k<r.end; ++k )
51551c0b2f7Stbbdev ++sum;
51651c0b2f7Stbbdev if( is_new ) {
51751c0b2f7Stbbdev is_new = false;
51851c0b2f7Stbbdev begin = r.begin;
51951c0b2f7Stbbdev } else
52051c0b2f7Stbbdev REQUIRE( end==r.begin );
52151c0b2f7Stbbdev end = r.end;
52251c0b2f7Stbbdev }
52351c0b2f7Stbbdev };
52451c0b2f7Stbbdev
52551c0b2f7Stbbdev template<typename Partitioner>
TestSplitting(std::size_t nthread)52651c0b2f7Stbbdev void TestSplitting( std::size_t nthread ) {
52751c0b2f7Stbbdev ForkCount = 0;
52851c0b2f7Stbbdev Partitioner partitioner;
52951c0b2f7Stbbdev for( size_t i=0; i<=1000; ++i ) {
53051c0b2f7Stbbdev FooBody f;
53151c0b2f7Stbbdev f.init();
53251c0b2f7Stbbdev REQUIRE_MESSAGE( FooBodyCount==1, "Wrong initial BodyCount value" );
53351c0b2f7Stbbdev reduce_invoker(MinimalRange(i), f, partitioner);
53451c0b2f7Stbbdev
53551c0b2f7Stbbdev if (nthread == 1) REQUIRE_MESSAGE(ForkCount==0, "Body was split during 1 thread execution");
53651c0b2f7Stbbdev
53751c0b2f7Stbbdev REQUIRE_MESSAGE( FooBodyCount==1, "Some copies of FooBody was not removed after reduction");
53851c0b2f7Stbbdev REQUIRE_MESSAGE( f.sum==i, "Incorrect reduction" );
53951c0b2f7Stbbdev REQUIRE_MESSAGE( f.begin==(i==0 ? ~size_t(0) : 0), "Incorrect range borders" );
54051c0b2f7Stbbdev REQUIRE_MESSAGE( f.end==(i==0 ? ~size_t(0) : i), "Incorrect range borders" );
54151c0b2f7Stbbdev }
54251c0b2f7Stbbdev }
54351c0b2f7Stbbdev
54451c0b2f7Stbbdev //! Test splitting range and body during reduction, test that all workers sleep when no work
54551c0b2f7Stbbdev //! \brief \ref resource_usage \ref error_guessing
54651c0b2f7Stbbdev TEST_CASE("Test splitting range and body during reduction, test that all workers sleep when no work") {
54751c0b2f7Stbbdev for ( auto concurrency_level : utils::concurrency_range() ) {
54851c0b2f7Stbbdev tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level);
54951c0b2f7Stbbdev
55051c0b2f7Stbbdev TestSplitting<tbb::simple_partitioner>(concurrency_level);
55151c0b2f7Stbbdev TestSplitting<tbb::static_partitioner>(concurrency_level);
55251c0b2f7Stbbdev TestSplitting<tbb::auto_partitioner>(concurrency_level);
55351c0b2f7Stbbdev TestSplitting<tbb::affinity_partitioner>(concurrency_level);
55451c0b2f7Stbbdev TestSplitting<utils_default_partitioner>(concurrency_level);
55551c0b2f7Stbbdev
55651c0b2f7Stbbdev // Test that all workers sleep when no work
55751c0b2f7Stbbdev TestCPUUserTime(concurrency_level);
55851c0b2f7Stbbdev }
55951c0b2f7Stbbdev }
56051c0b2f7Stbbdev
56151c0b2f7Stbbdev //! Define overloads of parallel_deterministic_reduce that accept "undesired" types of partitioners
56251c0b2f7Stbbdev namespace unsupported {
56351c0b2f7Stbbdev template<typename Range, typename Body>
parallel_deterministic_reduce(const Range &,Body &,const tbb::auto_partitioner &)56451c0b2f7Stbbdev void parallel_deterministic_reduce(const Range&, Body&, const tbb::auto_partitioner&) { }
56551c0b2f7Stbbdev template<typename Range, typename Body>
parallel_deterministic_reduce(const Range &,Body &,tbb::affinity_partitioner &)56651c0b2f7Stbbdev void parallel_deterministic_reduce(const Range&, Body&, tbb::affinity_partitioner&) { }
56751c0b2f7Stbbdev
56851c0b2f7Stbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
parallel_deterministic_reduce(const Range &,const Value & identity,const RealBody &,const Reduction &,const tbb::auto_partitioner &)56951c0b2f7Stbbdev Value parallel_deterministic_reduce(const Range& , const Value& identity, const RealBody& , const Reduction& , const tbb::auto_partitioner&) {
57051c0b2f7Stbbdev return identity;
57151c0b2f7Stbbdev }
57251c0b2f7Stbbdev template<typename Range, typename Value, typename RealBody, typename Reduction>
parallel_deterministic_reduce(const Range &,const Value & identity,const RealBody &,const Reduction &,tbb::affinity_partitioner &)57351c0b2f7Stbbdev Value parallel_deterministic_reduce(const Range& , const Value& identity, const RealBody& , const Reduction& , tbb::affinity_partitioner&) {
57451c0b2f7Stbbdev return identity;
57551c0b2f7Stbbdev }
57651c0b2f7Stbbdev }
57751c0b2f7Stbbdev
57851c0b2f7Stbbdev struct Body {
57951c0b2f7Stbbdev float value;
BodyBody58051c0b2f7Stbbdev Body() : value(0) {}
BodyBody58151c0b2f7Stbbdev Body(Body&, tbb::split) { value = 0; }
operator ()Body58251c0b2f7Stbbdev void operator()(const tbb::blocked_range<int>&) {}
joinBody58351c0b2f7Stbbdev void join(Body&) {}
58451c0b2f7Stbbdev };
58551c0b2f7Stbbdev
58651c0b2f7Stbbdev //! Check that other types of partitioners are not supported (auto, affinity)
58751c0b2f7Stbbdev //! In the case of "unsupported" API unexpectedly sneaking into namespace tbb,
58851c0b2f7Stbbdev //! this test should result in a compilation error due to overload resolution ambiguity
58951c0b2f7Stbbdev //! \brief \ref negative \ref error_guessing
59051c0b2f7Stbbdev TEST_CASE("Test Unsupported Partitioners") {
59151c0b2f7Stbbdev using namespace tbb;
59251c0b2f7Stbbdev using namespace unsupported;
59351c0b2f7Stbbdev Body body;
59451c0b2f7Stbbdev parallel_deterministic_reduce(blocked_range<int>(0, 10), body, tbb::auto_partitioner());
59551c0b2f7Stbbdev
59651c0b2f7Stbbdev tbb::affinity_partitioner ap;
59751c0b2f7Stbbdev parallel_deterministic_reduce(blocked_range<int>(0, 10), body, ap);
59851c0b2f7Stbbdev
59951c0b2f7Stbbdev parallel_deterministic_reduce(
60051c0b2f7Stbbdev blocked_range<int>(0, 10),
60151c0b2f7Stbbdev 0,
__anon6ca08c0e0202(const blocked_range<int>&, int init)60251c0b2f7Stbbdev [](const blocked_range<int>&, int init)->int {
60351c0b2f7Stbbdev return init;
60451c0b2f7Stbbdev },
__anon6ca08c0e0302(int x, int y)60551c0b2f7Stbbdev [](int x, int y)->int {
60651c0b2f7Stbbdev return x + y;
60751c0b2f7Stbbdev },
60851c0b2f7Stbbdev tbb::auto_partitioner()
60951c0b2f7Stbbdev );
61051c0b2f7Stbbdev parallel_deterministic_reduce(
61151c0b2f7Stbbdev blocked_range<int>(0, 10),
61251c0b2f7Stbbdev 0,
__anon6ca08c0e0402(const blocked_range<int>&, int init)61351c0b2f7Stbbdev [](const blocked_range<int>&, int init)->int {
61451c0b2f7Stbbdev return init;
61551c0b2f7Stbbdev },
__anon6ca08c0e0502(int x, int y)61651c0b2f7Stbbdev [](int x, int y)->int {
61751c0b2f7Stbbdev return x + y;
61851c0b2f7Stbbdev },
61951c0b2f7Stbbdev ap
62051c0b2f7Stbbdev );
62151c0b2f7Stbbdev }
62251c0b2f7Stbbdev
62351c0b2f7Stbbdev //! Testing tbb::parallel_reduce with tbb::task_group_context
62451c0b2f7Stbbdev //! \brief \ref interface \ref error_guessing
62551c0b2f7Stbbdev TEST_CASE("cancellation test for tbb::parallel_reduce") {
62651c0b2f7Stbbdev test_cancellation::ParallelReduceTestRunner</*First mode = */0>::run();
62751c0b2f7Stbbdev }
62851c0b2f7Stbbdev
62951c0b2f7Stbbdev //! Testing tbb::parallel_deterministic_reduce with tbb::task_group_context
63051c0b2f7Stbbdev //! \brief \ref interface \ref error_guessing
63151c0b2f7Stbbdev TEST_CASE("cancellation test for tbb::parallel_deterministic_reduce") {
63251c0b2f7Stbbdev test_cancellation::ParallelDeterministicReduceTestRunner</*First mode = */0>::run();
63351c0b2f7Stbbdev }
634478de5b1Stbbdev
635478de5b1Stbbdev #if __TBB_CPP20_CONCEPTS_PRESENT
636478de5b1Stbbdev //! \brief \ref error_guessing
637478de5b1Stbbdev TEST_CASE("parallel_reduce constraints") {
638478de5b1Stbbdev test_preduce_range_constraints();
639478de5b1Stbbdev test_preduce_body_constraints();
640478de5b1Stbbdev test_preduce_func_constraints();
641478de5b1Stbbdev test_preduce_combine_constraints();
642478de5b1Stbbdev }
643478de5b1Stbbdev
644478de5b1Stbbdev //! \brief \ref error_guessing
645478de5b1Stbbdev TEST_CASE("parallel_deterministic_reduce constraints") {
646478de5b1Stbbdev test_pdet_reduce_range_constraints();
647478de5b1Stbbdev test_pdet_reduce_body_constraints();
648478de5b1Stbbdev test_pdet_reduce_func_constraints();
649478de5b1Stbbdev test_pdet_reduce_combine_constraints();
650478de5b1Stbbdev }
651478de5b1Stbbdev #endif
65255f9b178SIvan Kochin
65355f9b178SIvan Kochin #if _MSC_VER
65455f9b178SIvan Kochin #pragma warning (pop)
65555f9b178SIvan Kochin #endif
656