151c0b2f7Stbbdev /* 2b15aabb3Stbbdev Copyright (c) 2020-2021 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 #ifndef __TBB_test_common_parallel_invoke_common_H 1851c0b2f7Stbbdev #define __TBB_test_common_parallel_invoke_common_H 1951c0b2f7Stbbdev 20*478de5b1Stbbdev #include "config.h" 21*478de5b1Stbbdev 2251c0b2f7Stbbdev #include <cstddef> 2351c0b2f7Stbbdev #include <tuple> 2451c0b2f7Stbbdev 2549e08aacStbbdev #include "oneapi/tbb/parallel_invoke.h" 2649e08aacStbbdev #include "oneapi/tbb/global_control.h" 2751c0b2f7Stbbdev 28b15aabb3Stbbdev #include "dummy_body.h" 29b15aabb3Stbbdev 3051c0b2f7Stbbdev // Helps generate a tuple of functional objects 3151c0b2f7Stbbdev template<std::size_t Counter, template <std::size_t> class Functor, class Generator, typename... Fs> 3251c0b2f7Stbbdev struct generate_tuple_impl : 3351c0b2f7Stbbdev public generate_tuple_impl<Counter - 1, Functor, Generator, typename Generator::template type<Functor, Counter - 1>, Fs...> {}; 3451c0b2f7Stbbdev 3551c0b2f7Stbbdev template<template <std::size_t> class Functor, class Generator, typename... Fs> 3651c0b2f7Stbbdev struct generate_tuple_impl <0, Functor, Generator, Fs...> { 3751c0b2f7Stbbdev using type = std::tuple<Fs...>; 3851c0b2f7Stbbdev }; 3951c0b2f7Stbbdev 4051c0b2f7Stbbdev template<std::size_t Size, template <std::size_t> class Functor, class Generator> 4151c0b2f7Stbbdev using generate_tuple = typename generate_tuple_impl<Size, Functor, Generator>::type; 4251c0b2f7Stbbdev 4351c0b2f7Stbbdev // Defines how generate_tuple should propagate Counter to the tuple members 4451c0b2f7Stbbdev struct generator { 4551c0b2f7Stbbdev template <template <std::size_t> class Functor, std::size_t NonTypeArg> 4651c0b2f7Stbbdev using type = Functor<NonTypeArg>; 4751c0b2f7Stbbdev }; 4851c0b2f7Stbbdev 4951c0b2f7Stbbdev template <std::size_t Fixed> 5051c0b2f7Stbbdev struct fixed_generator { 5151c0b2f7Stbbdev template <template <std::size_t> class Functor, std::size_t NonTypeArg> 5251c0b2f7Stbbdev using type = Functor<Fixed>; 5351c0b2f7Stbbdev }; 5451c0b2f7Stbbdev 5551c0b2f7Stbbdev template<std::size_t LevelTaskCount, std::size_t MaxDepth, std::size_t WorkSize> 5651c0b2f7Stbbdev struct invoke_tree { 5751c0b2f7Stbbdev struct invoke_tree_leaf { 5851c0b2f7Stbbdev static constexpr std::size_t size = WorkSize; 59b15aabb3Stbbdev void operator()() const { utils::doDummyWork(size); } 6051c0b2f7Stbbdev }; 6151c0b2f7Stbbdev 6251c0b2f7Stbbdev // Make invoke_tree_leaf composable with generate_tuple interface 6351c0b2f7Stbbdev template <std::size_t NonTypeArg> 6451c0b2f7Stbbdev using generating_leaf_functor = invoke_tree_leaf; 6551c0b2f7Stbbdev 6651c0b2f7Stbbdev template<std::size_t CurrentDepth> 6751c0b2f7Stbbdev struct invoke_tree_node { 6851c0b2f7Stbbdev template<typename... Fs> 6951c0b2f7Stbbdev void invoker(const std::tuple<Fs...>&) const { 7051c0b2f7Stbbdev tbb::parallel_invoke(Fs()...); 7151c0b2f7Stbbdev } 7251c0b2f7Stbbdev 7351c0b2f7Stbbdev // Template alias to workaround the strange Visual Studio issue 7451c0b2f7Stbbdev template<std::size_t Depth> 7551c0b2f7Stbbdev using generating_node_functor = invoke_tree_node<Depth>; 7651c0b2f7Stbbdev 7751c0b2f7Stbbdev void create_level(/*is_final_level*/std::false_type) const { 7851c0b2f7Stbbdev invoker(generate_tuple<LevelTaskCount, generating_node_functor, fixed_generator<CurrentDepth + 1>>{}); 7951c0b2f7Stbbdev } 8051c0b2f7Stbbdev 8151c0b2f7Stbbdev void create_level(/*is_final_level*/std::true_type) const { 8251c0b2f7Stbbdev invoker(generate_tuple<LevelTaskCount, generating_leaf_functor, generator>()); 8351c0b2f7Stbbdev } 8451c0b2f7Stbbdev 8551c0b2f7Stbbdev void operator()() const { 8651c0b2f7Stbbdev create_level(/*is_final_level*/std::integral_constant<bool, CurrentDepth == MaxDepth>()); 8751c0b2f7Stbbdev } 8851c0b2f7Stbbdev }; 8951c0b2f7Stbbdev 9051c0b2f7Stbbdev static void generate_and_run() { 9151c0b2f7Stbbdev invoke_tree_node<1> tree_root; 9251c0b2f7Stbbdev tree_root(); 9351c0b2f7Stbbdev } 9451c0b2f7Stbbdev }; 9551c0b2f7Stbbdev 9651c0b2f7Stbbdev template<std::size_t TaskCount, template<std::size_t> class Functor> 9751c0b2f7Stbbdev class parallel_invoke_call { 9851c0b2f7Stbbdev template<typename... Fs> 9951c0b2f7Stbbdev static void invoke_tuple_args(tbb::task_group_context* context_ptr, const std::tuple<Fs...>&) { 10051c0b2f7Stbbdev if (context_ptr != nullptr) { 10151c0b2f7Stbbdev tbb::parallel_invoke(Fs()..., *context_ptr); 10251c0b2f7Stbbdev } else { 10351c0b2f7Stbbdev tbb::parallel_invoke(Fs()...); 10451c0b2f7Stbbdev } 10551c0b2f7Stbbdev } 10651c0b2f7Stbbdev 10751c0b2f7Stbbdev public: 10851c0b2f7Stbbdev static void perform(tbb::task_group_context* context_ptr = nullptr) { 10951c0b2f7Stbbdev invoke_tuple_args(context_ptr, generate_tuple<TaskCount, Functor, generator>{}); 11051c0b2f7Stbbdev } 11151c0b2f7Stbbdev }; 11251c0b2f7Stbbdev 11351c0b2f7Stbbdev #endif // __TBB_test_common_parallel_invoke_common_H 114