151c0b2f7Stbbdev /* 2*b15aabb3Stbbdev Copyright (c) 2005-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 17*b15aabb3Stbbdev #if __INTEL_COMPILER && _MSC_VER 18*b15aabb3Stbbdev #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated 19*b15aabb3Stbbdev #endif 20*b15aabb3Stbbdev 2151c0b2f7Stbbdev #include "common/config.h" 2251c0b2f7Stbbdev 2351c0b2f7Stbbdev // TODO revamp: move parts dependent on __TBB_EXTRA_DEBUG into separate test(s) since having these 2451c0b2f7Stbbdev // parts in all of tests might make testing of the product, which is different from what is actually 2551c0b2f7Stbbdev // released. 2651c0b2f7Stbbdev #define __TBB_EXTRA_DEBUG 1 2751c0b2f7Stbbdev #include "tbb/flow_graph.h" 2851c0b2f7Stbbdev 2951c0b2f7Stbbdev #include "common/test.h" 3051c0b2f7Stbbdev #include "common/utils.h" 3151c0b2f7Stbbdev #include "common/graph_utils.h" 3251c0b2f7Stbbdev 3351c0b2f7Stbbdev #include <tuple> 3451c0b2f7Stbbdev #include <cmath> 3551c0b2f7Stbbdev #include <vector> 3651c0b2f7Stbbdev 3751c0b2f7Stbbdev 3851c0b2f7Stbbdev //! \file test_composite_node.cpp 3951c0b2f7Stbbdev //! \brief Test for [flow_graph.composite_node] specification 4051c0b2f7Stbbdev 4151c0b2f7Stbbdev 4251c0b2f7Stbbdev struct passthru_body { 4351c0b2f7Stbbdev int operator()( int i ) { 4451c0b2f7Stbbdev return i; 4551c0b2f7Stbbdev } 4651c0b2f7Stbbdev }; 4751c0b2f7Stbbdev 4851c0b2f7Stbbdev class my_input_body{ 4951c0b2f7Stbbdev int start; 5051c0b2f7Stbbdev int finish; 5151c0b2f7Stbbdev int step; 5251c0b2f7Stbbdev public: 5351c0b2f7Stbbdev my_input_body(int f, int s) : start(1), finish(f), step(s) {} 5451c0b2f7Stbbdev int operator()(tbb::flow_control& fc) { 5551c0b2f7Stbbdev int a = start; 5651c0b2f7Stbbdev if (start <= finish) { 5751c0b2f7Stbbdev a = start; 5851c0b2f7Stbbdev start+=step; 5951c0b2f7Stbbdev return a; 6051c0b2f7Stbbdev } 6151c0b2f7Stbbdev else { 6251c0b2f7Stbbdev fc.stop(); 6351c0b2f7Stbbdev return int(); 6451c0b2f7Stbbdev }; 6551c0b2f7Stbbdev } 6651c0b2f7Stbbdev }; 6751c0b2f7Stbbdev 6851c0b2f7Stbbdev struct m_fxn_body{ 6951c0b2f7Stbbdev void operator()(int, tbb::flow::multifunction_node<int, std::tuple<int,int> >::output_ports_type ) {} 7051c0b2f7Stbbdev }; 7151c0b2f7Stbbdev 7251c0b2f7Stbbdev struct ct_body { 7351c0b2f7Stbbdev ct_body(){} 7451c0b2f7Stbbdev void operator()(tbb::flow::continue_msg){} 7551c0b2f7Stbbdev }; 7651c0b2f7Stbbdev 7751c0b2f7Stbbdev struct seq_body { 7851c0b2f7Stbbdev int operator()(int i){return i;} 7951c0b2f7Stbbdev }; 8051c0b2f7Stbbdev 8151c0b2f7Stbbdev template<int N, typename T1, typename T2> 8251c0b2f7Stbbdev struct compare { 8351c0b2f7Stbbdev static void compare_refs(T1 tuple1, T2 tuple2) { 8451c0b2f7Stbbdev CHECK_MESSAGE( ( &std::get<N>(tuple1) == &std::get<N>(tuple2)), "ports not set correctly"); 8551c0b2f7Stbbdev compare<N-1, T1, T2>::compare_refs(tuple1, tuple2); 8651c0b2f7Stbbdev } 8751c0b2f7Stbbdev }; 8851c0b2f7Stbbdev 8951c0b2f7Stbbdev template<typename T1, typename T2> 9051c0b2f7Stbbdev struct compare<1, T1, T2> { 9151c0b2f7Stbbdev static void compare_refs(T1 tuple1, T2 tuple2) { 9251c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<0>(tuple1) == &std::get<0>(tuple2)), "port 0 not correctly set"); 9351c0b2f7Stbbdev } 9451c0b2f7Stbbdev }; 9551c0b2f7Stbbdev 9651c0b2f7Stbbdev void add_all_nodes (){ 9751c0b2f7Stbbdev tbb::flow::graph g; 9851c0b2f7Stbbdev 9951c0b2f7Stbbdev typedef std::tuple<tbb::flow::continue_msg, std::tuple<int, int>, int, int, int, int, 10051c0b2f7Stbbdev int, int, int, int, int, int, int, int > InputTupleType; 10151c0b2f7Stbbdev 10251c0b2f7Stbbdev typedef std::tuple<tbb::flow::continue_msg, std::tuple<int, int>, tbb::flow::tagged_msg<size_t, int, float>, 10351c0b2f7Stbbdev int, int, int, int, int, int, int, int, int, int, int, int > OutputTupleType; 10451c0b2f7Stbbdev 10551c0b2f7Stbbdev typedef std::tuple< > EmptyTupleType; 10651c0b2f7Stbbdev 10751c0b2f7Stbbdev typedef tbb::flow::composite_node<InputTupleType, OutputTupleType > input_output_type; 10851c0b2f7Stbbdev typedef tbb::flow::composite_node<InputTupleType, EmptyTupleType > input_only_type; 10951c0b2f7Stbbdev typedef tbb::flow::composite_node<EmptyTupleType, OutputTupleType > output_only_type; 11051c0b2f7Stbbdev 11151c0b2f7Stbbdev const size_t NUM_INPUTS = std::tuple_size<InputTupleType>::value; 11251c0b2f7Stbbdev const size_t NUM_OUTPUTS = std::tuple_size<OutputTupleType>::value; 11351c0b2f7Stbbdev 11451c0b2f7Stbbdev //node types 11551c0b2f7Stbbdev tbb::flow::continue_node<tbb::flow::continue_msg> ct(g, ct_body()); 11651c0b2f7Stbbdev tbb::flow::split_node< std::tuple<int, int> > s(g); 11751c0b2f7Stbbdev tbb::flow::input_node<int> src(g, my_input_body(20,5)); 11851c0b2f7Stbbdev tbb::flow::function_node<int, int> fxn(g, tbb::flow::unlimited, passthru_body()); 11951c0b2f7Stbbdev tbb::flow::multifunction_node<int, std::tuple<int, int> > m_fxn(g, tbb::flow::unlimited, m_fxn_body()); 12051c0b2f7Stbbdev tbb::flow::broadcast_node<int> bc(g); 12151c0b2f7Stbbdev tbb::flow::limiter_node<int> lim(g, 2); 12251c0b2f7Stbbdev tbb::flow::indexer_node<int, float> ind(g); 12351c0b2f7Stbbdev tbb::flow::join_node< std::tuple< int, int >, tbb::flow::queueing > j(g); 12451c0b2f7Stbbdev tbb::flow::queue_node<int> q(g); 12551c0b2f7Stbbdev tbb::flow::buffer_node<int> bf(g); 12651c0b2f7Stbbdev tbb::flow::priority_queue_node<int> pq(g); 12751c0b2f7Stbbdev tbb::flow::write_once_node<int> wo(g); 12851c0b2f7Stbbdev tbb::flow::overwrite_node<int> ovw(g); 12951c0b2f7Stbbdev tbb::flow::sequencer_node<int> seq(g, seq_body()); 13051c0b2f7Stbbdev 13151c0b2f7Stbbdev auto input_tuple = std::tie(ct, s, m_fxn, fxn, bc, tbb::flow::input_port<0>(j), lim, q, tbb::flow::input_port<0>(ind), 13251c0b2f7Stbbdev pq, ovw, wo, bf, seq); 13351c0b2f7Stbbdev auto output_tuple = std::tie(ct,j, ind, fxn, src, bc, tbb::flow::output_port<0>(s), lim, tbb::flow::output_port<0>(m_fxn), 13451c0b2f7Stbbdev q, pq, ovw, wo, bf, seq ); 13551c0b2f7Stbbdev 13651c0b2f7Stbbdev //composite_node with both input_ports and output_ports 13751c0b2f7Stbbdev input_output_type a_node(g); 13851c0b2f7Stbbdev a_node.set_external_ports(input_tuple, output_tuple); 13951c0b2f7Stbbdev 14051c0b2f7Stbbdev a_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq); 14151c0b2f7Stbbdev a_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq); 14251c0b2f7Stbbdev 14351c0b2f7Stbbdev auto a_node_input_ports_ptr = a_node.input_ports(); 14451c0b2f7Stbbdev compare<NUM_INPUTS-1, decltype(a_node_input_ports_ptr), decltype(input_tuple)>::compare_refs(a_node_input_ports_ptr, input_tuple); 14551c0b2f7Stbbdev CHECK_MESSAGE(NUM_INPUTS == std::tuple_size<decltype(a_node_input_ports_ptr)>::value, "not all declared input ports were bound to nodes"); 14651c0b2f7Stbbdev 14751c0b2f7Stbbdev auto a_node_output_ports_ptr = a_node.output_ports(); 14851c0b2f7Stbbdev compare<NUM_OUTPUTS-1, decltype(a_node_output_ports_ptr), decltype(output_tuple)>::compare_refs(a_node_output_ports_ptr, output_tuple); 14951c0b2f7Stbbdev CHECK_MESSAGE( (NUM_OUTPUTS == std::tuple_size<decltype(a_node_output_ports_ptr)>::value), "not all declared output ports were bound to nodes"); 15051c0b2f7Stbbdev 15151c0b2f7Stbbdev //composite_node with only input_ports 15251c0b2f7Stbbdev input_only_type b_node(g); 15351c0b2f7Stbbdev b_node.set_external_ports(input_tuple); 15451c0b2f7Stbbdev 15551c0b2f7Stbbdev b_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq); 15651c0b2f7Stbbdev b_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq); 15751c0b2f7Stbbdev 15851c0b2f7Stbbdev auto b_node_input_ports_ptr = b_node.input_ports(); 15951c0b2f7Stbbdev compare<NUM_INPUTS-1, decltype(b_node_input_ports_ptr), decltype(input_tuple)>::compare_refs(b_node_input_ports_ptr, input_tuple); 16051c0b2f7Stbbdev CHECK_MESSAGE(NUM_INPUTS == std::tuple_size<decltype(b_node_input_ports_ptr)>::value, "not all declared input ports were bound to nodes"); 16151c0b2f7Stbbdev 16251c0b2f7Stbbdev //composite_node with only output_ports 16351c0b2f7Stbbdev output_only_type c_node(g); 16451c0b2f7Stbbdev c_node.set_external_ports(output_tuple); 16551c0b2f7Stbbdev 16651c0b2f7Stbbdev // Reset is not suppose to do anything. Check that it can be called. 16751c0b2f7Stbbdev g.reset(); 16851c0b2f7Stbbdev 16951c0b2f7Stbbdev c_node.add_visible_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq); 17051c0b2f7Stbbdev 17151c0b2f7Stbbdev c_node.add_nodes(src, fxn, m_fxn, bc, lim, ind, s, ct, j, q, bf, pq, wo, ovw, seq); 17251c0b2f7Stbbdev 17351c0b2f7Stbbdev auto c_node_output_ports_ptr = c_node.output_ports(); 17451c0b2f7Stbbdev compare<NUM_OUTPUTS-1, decltype(c_node_output_ports_ptr), decltype(output_tuple)>::compare_refs(c_node_output_ports_ptr, output_tuple); 17551c0b2f7Stbbdev CHECK_MESSAGE(NUM_OUTPUTS == std::tuple_size<decltype(c_node_output_ports_ptr)>::value, "not all declared input ports were bound to nodes"); 17651c0b2f7Stbbdev } 17751c0b2f7Stbbdev 17851c0b2f7Stbbdev struct tiny_node : public tbb::flow::composite_node< std::tuple< int >, std::tuple< int > > { 17951c0b2f7Stbbdev tbb::flow::function_node< int, int > f1; 18051c0b2f7Stbbdev tbb::flow::function_node< int, int > f2; 18151c0b2f7Stbbdev typedef tbb::flow::composite_node< std::tuple< int >, std::tuple< int > > base_type; 18251c0b2f7Stbbdev 18351c0b2f7Stbbdev public: 18451c0b2f7Stbbdev tiny_node(tbb::flow::graph &g, bool hidden = false) : base_type(g), f1(g, tbb::flow::unlimited, passthru_body() ), f2(g, tbb::flow::unlimited, passthru_body() ) { 18551c0b2f7Stbbdev tbb::flow::make_edge( f1, f2 ); 18651c0b2f7Stbbdev 18751c0b2f7Stbbdev std::tuple<tbb::flow::function_node< int, int >& > input_tuple(f1); 18851c0b2f7Stbbdev std::tuple<tbb::flow::function_node< int, int >& > output_tuple(f2); 18951c0b2f7Stbbdev base_type::set_external_ports( input_tuple, output_tuple ); 19051c0b2f7Stbbdev 19151c0b2f7Stbbdev if(hidden) 19251c0b2f7Stbbdev base_type::add_nodes(f1, f2); 19351c0b2f7Stbbdev else 19451c0b2f7Stbbdev base_type::add_visible_nodes(f1, f2); 19551c0b2f7Stbbdev 19651c0b2f7Stbbdev } 19751c0b2f7Stbbdev }; 19851c0b2f7Stbbdev 19951c0b2f7Stbbdev int test_tiny(bool hidden = false) { 20051c0b2f7Stbbdev tbb::flow::graph g; 20151c0b2f7Stbbdev tbb::flow::function_node< int, int > f0( g, tbb::flow::unlimited, passthru_body() ); 20251c0b2f7Stbbdev tiny_node t(g, hidden); 20351c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::input_port<0>(t) == &t.f1), "f1 not bound to input port 0 in composite_node t"); 20451c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::output_port<0>(t) == &t.f2), "f2 not bound to output port 0 in composite_node t"); 20551c0b2f7Stbbdev 20651c0b2f7Stbbdev tiny_node t1(g, hidden); 20751c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<0>(t1.input_ports()) == &t1.f1), "f1 not bound to input port 0 in composite_node t1"); 20851c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<0>(t1.output_ports()) == &t1.f2), "f2 not bound to output port 0 in composite_node t1"); 20951c0b2f7Stbbdev 21051c0b2f7Stbbdev test_input_ports_return_ref(t1); 21151c0b2f7Stbbdev test_output_ports_return_ref(t1); 21251c0b2f7Stbbdev 21351c0b2f7Stbbdev tiny_node t2(g, hidden); 21451c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::input_port<0>(t2) == &t2.f1), "f1 not bound to input port 0 in composite_node t2"); 21551c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::output_port<0>(t2) == &t2.f2), "f2 not bound to output port 0 in composite_node t2"); 21651c0b2f7Stbbdev 21751c0b2f7Stbbdev tbb::flow::function_node< int, int > f3( g, tbb::flow::unlimited, passthru_body() ); 21851c0b2f7Stbbdev tbb::flow::make_edge( f0, t ); 21951c0b2f7Stbbdev tbb::flow::make_edge( t, t1 ); 22051c0b2f7Stbbdev tbb::flow::make_edge( t1, t2 ); 22151c0b2f7Stbbdev tbb::flow::make_edge( t2 , f3 ); 22251c0b2f7Stbbdev tbb::flow::queue_node<int> q(g); 22351c0b2f7Stbbdev tbb::flow::make_edge(f3, q); 22451c0b2f7Stbbdev f0.try_put(1); 22551c0b2f7Stbbdev g.wait_for_all(); 22651c0b2f7Stbbdev 22751c0b2f7Stbbdev int i, j =0; 22851c0b2f7Stbbdev q.try_get(i); 22951c0b2f7Stbbdev CHECK_MESSAGE( ( i == 1), "item did not go through graph"); 23051c0b2f7Stbbdev q.try_get(j); 23151c0b2f7Stbbdev CHECK_MESSAGE( ( !j), "unexpected item in graph"); 23251c0b2f7Stbbdev g.wait_for_all(); 23351c0b2f7Stbbdev 23451c0b2f7Stbbdev tbb::flow::remove_edge(f3, q); 23551c0b2f7Stbbdev tbb::flow::remove_edge(t2, f3); 23651c0b2f7Stbbdev tbb::flow::remove_edge(t1, t2); 23751c0b2f7Stbbdev 23851c0b2f7Stbbdev tbb::flow::make_edge( t1 , f3 ); 23951c0b2f7Stbbdev tbb::flow::make_edge(f3, q); 24051c0b2f7Stbbdev 24151c0b2f7Stbbdev f0.try_put(2); 24251c0b2f7Stbbdev g.wait_for_all(); 24351c0b2f7Stbbdev 24451c0b2f7Stbbdev q.try_get(i); 24551c0b2f7Stbbdev CHECK_MESSAGE( ( i == 2), "item did not go through graph after removal of edge"); 24651c0b2f7Stbbdev q.try_get(j); 24751c0b2f7Stbbdev CHECK_MESSAGE( ( !j), "unexpected item in graph after removal of edge"); 24851c0b2f7Stbbdev 24951c0b2f7Stbbdev return 0; 25051c0b2f7Stbbdev } 25151c0b2f7Stbbdev 25251c0b2f7Stbbdev class adder_node : public tbb::flow::composite_node< std::tuple< int, int >, std::tuple< int > > { 25351c0b2f7Stbbdev public: 25451c0b2f7Stbbdev tbb::flow::join_node< std::tuple< int, int >, tbb::flow::queueing > j; 25551c0b2f7Stbbdev tbb::flow::function_node< std::tuple< int, int >, int > f; 25651c0b2f7Stbbdev private: 25751c0b2f7Stbbdev typedef tbb::flow::composite_node< std::tuple< int, int >, std::tuple< int > > base_type; 25851c0b2f7Stbbdev 25951c0b2f7Stbbdev struct f_body { 26051c0b2f7Stbbdev int operator()( const std::tuple< int, int > &t ) { 26151c0b2f7Stbbdev return std::get<0>(t) + std::get<1>(t); 26251c0b2f7Stbbdev } 26351c0b2f7Stbbdev }; 26451c0b2f7Stbbdev 26551c0b2f7Stbbdev public: 26651c0b2f7Stbbdev adder_node(tbb::flow::graph &g, bool hidden = false) : base_type(g), j(g), f(g, tbb::flow::unlimited, f_body() ) { 26751c0b2f7Stbbdev tbb::flow::make_edge( j, f ); 26851c0b2f7Stbbdev 26951c0b2f7Stbbdev base_type::set_external_ports(base_type::input_ports_type(tbb::flow::input_port<0>(j), tbb::flow::input_port<1>(j)), base_type::output_ports_type(f)); 27051c0b2f7Stbbdev 27151c0b2f7Stbbdev if (hidden) 27251c0b2f7Stbbdev base_type::add_nodes(j, f); 27351c0b2f7Stbbdev else 27451c0b2f7Stbbdev base_type::add_visible_nodes(j, f); 27551c0b2f7Stbbdev 27651c0b2f7Stbbdev } 27751c0b2f7Stbbdev }; 27851c0b2f7Stbbdev 27951c0b2f7Stbbdev struct square_body { int operator()(int v) { return v*v; } }; 28051c0b2f7Stbbdev struct cube_body { int operator()(int v) { return v*v*v; } }; 28151c0b2f7Stbbdev int adder_sum(int i) { 28251c0b2f7Stbbdev return (int)(pow(3*pow(i,3) + pow(i, 2),2)); 28351c0b2f7Stbbdev } 28451c0b2f7Stbbdev int test_adder(bool hidden = false) { 28551c0b2f7Stbbdev tbb::flow::graph g; 28651c0b2f7Stbbdev tbb::flow::function_node<int,int> s(g, tbb::flow::unlimited, square_body()); 28751c0b2f7Stbbdev tbb::flow::function_node<int,int> c(g, tbb::flow::unlimited, cube_body()); 28851c0b2f7Stbbdev tbb::flow::function_node<int,int> p(g, tbb::flow::unlimited, passthru_body()); 28951c0b2f7Stbbdev 29051c0b2f7Stbbdev adder_node a0(g, hidden); 29151c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::input_port<0>(a0) == &tbb::flow::input_port<0>(a0.j)), "input_port 0 of j not bound to input port 0 in composite_node a0"); 29251c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::input_port<1>(a0) == &tbb::flow::input_port<1>(a0.j)), "input_port 1 of j not bound to input port 1 in composite_node a0"); 29351c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::output_port<0>(a0) == &a0.f), "f not bound to output port 0 in composite_node a0"); 29451c0b2f7Stbbdev 29551c0b2f7Stbbdev adder_node a1(g, hidden); 29651c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<0>(a0.input_ports()) == &tbb::flow::input_port<0>(a0.j)), "input_port 0 of j not bound to input port 0 in composite_node a1"); 29751c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<1>(a0.input_ports()) == &tbb::flow::input_port<1>(a0.j)), "input_port1 of j not bound to input port 1 in composite_node a1"); 29851c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<0>(a0.output_ports()) == &a0.f), "f not bound to output port 0 in composite_node a1"); 29951c0b2f7Stbbdev 30051c0b2f7Stbbdev adder_node a2(g, hidden); 30151c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::input_port<0>(a2) == &tbb::flow::input_port<0>(a2.j)), "input_port 0 of j not bound to input port 0 in composite_node a2"); 30251c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::input_port<1>(a2) == &tbb::flow::input_port<1>(a2.j)), "input_port 1 of j not bound to input port 1 in composite_node a2"); 30351c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::output_port<0>(a2) == &a2.f), "f not bound to output port 0 in composite_node a2"); 30451c0b2f7Stbbdev 30551c0b2f7Stbbdev adder_node a3(g, hidden); 30651c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<0>(a3.input_ports()) == &tbb::flow::input_port<0>(a3.j)), "input_port 0 of j not bound to input port 0 in composite_node a3"); 30751c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<1>(a3.input_ports()) == &tbb::flow::input_port<1>(a3.j)), "input_port1 of j not bound to input port 1 in composite_node a3"); 30851c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<0>(a3.output_ports()) == &a3.f), "f not bound to output port 0 in composite_node a3"); 30951c0b2f7Stbbdev 31051c0b2f7Stbbdev tbb::flow::function_node<int,int> s2(g, tbb::flow::unlimited, square_body()); 31151c0b2f7Stbbdev tbb::flow::queue_node<int> q(g); 31251c0b2f7Stbbdev 31351c0b2f7Stbbdev tbb::flow::make_edge( s, tbb::flow::input_port<0>(a0) ); 31451c0b2f7Stbbdev tbb::flow::make_edge( c, tbb::flow::input_port<1>(a0) ); 31551c0b2f7Stbbdev 31651c0b2f7Stbbdev tbb::flow::make_edge( c, tbb::flow::input_port<0>(a1) ); 31751c0b2f7Stbbdev tbb::flow::make_edge( c, tbb::flow::input_port<1>(a1) ); 31851c0b2f7Stbbdev 31951c0b2f7Stbbdev tbb::flow::make_edge( tbb::flow::output_port<0>(a0), tbb::flow::input_port<0>(a2) ); 32051c0b2f7Stbbdev tbb::flow::make_edge( tbb::flow::output_port<0>(a1), tbb::flow::input_port<1>(a2) ); 32151c0b2f7Stbbdev 32251c0b2f7Stbbdev tbb::flow::make_edge( tbb::flow::output_port<0>(a2), s2 ); 32351c0b2f7Stbbdev tbb::flow::make_edge( s2, q ); 32451c0b2f7Stbbdev 32551c0b2f7Stbbdev int sum_total=0; 32651c0b2f7Stbbdev int result=0; 32751c0b2f7Stbbdev for ( int i = 1; i < 4; ++i ) { 32851c0b2f7Stbbdev s.try_put(i); 32951c0b2f7Stbbdev c.try_put(i); 33051c0b2f7Stbbdev sum_total += adder_sum(i); 33151c0b2f7Stbbdev g.wait_for_all(); 33251c0b2f7Stbbdev } 33351c0b2f7Stbbdev 33451c0b2f7Stbbdev int j; 33551c0b2f7Stbbdev for ( int i = 1; i < 4; ++i ) { 33651c0b2f7Stbbdev q.try_get(j); 33751c0b2f7Stbbdev result += j; 33851c0b2f7Stbbdev } 33951c0b2f7Stbbdev g.wait_for_all(); 34051c0b2f7Stbbdev CHECK_MESSAGE( (result == sum_total), "the sum from the graph does not match the calculated value"); 34151c0b2f7Stbbdev 34251c0b2f7Stbbdev tbb::flow::remove_edge(s2, q); 34351c0b2f7Stbbdev tbb::flow::remove_edge( a2, s2 ); 34451c0b2f7Stbbdev tbb::flow::make_edge( a0, a3 ); 34551c0b2f7Stbbdev tbb::flow::make_edge( a1, tbb::flow::input_port<1>(a3) ); 34651c0b2f7Stbbdev tbb::flow::make_edge( a3, s2 ); 34751c0b2f7Stbbdev tbb::flow::make_edge( s2, q ); 34851c0b2f7Stbbdev 34951c0b2f7Stbbdev sum_total=0; 35051c0b2f7Stbbdev result=0; 35151c0b2f7Stbbdev for ( int i = 10; i < 20; ++i ) { 35251c0b2f7Stbbdev s.try_put(i); 35351c0b2f7Stbbdev c.try_put(i); 35451c0b2f7Stbbdev sum_total += adder_sum(i); 35551c0b2f7Stbbdev g.wait_for_all(); 35651c0b2f7Stbbdev } 35751c0b2f7Stbbdev 35851c0b2f7Stbbdev for ( int i = 10; i < 20; ++i ) { 35951c0b2f7Stbbdev q.try_get(j); 36051c0b2f7Stbbdev result += j; 36151c0b2f7Stbbdev } 36251c0b2f7Stbbdev g.wait_for_all(); 36351c0b2f7Stbbdev CHECK_MESSAGE( (result == sum_total), "the new sum after the replacement of the nodes does not match the calculated value"); 36451c0b2f7Stbbdev 36551c0b2f7Stbbdev return 0; 36651c0b2f7Stbbdev } 36751c0b2f7Stbbdev 36851c0b2f7Stbbdev /* 36951c0b2f7Stbbdev outer composite node (outer_node) 37051c0b2f7Stbbdev |-------------------------------------------------------------------| 37151c0b2f7Stbbdev | | 37251c0b2f7Stbbdev | |------------------| |------------------| |------------------| | 37351c0b2f7Stbbdev |---------------------| |--| inner composite | /| inner composite | /| inner composite | | |-------------------| 37451c0b2f7Stbbdev |broadcast node(input)|/| | node |/ | node |/ | node |-+-| queue node(output)| 37551c0b2f7Stbbdev |---------------------|\| |(inner_node1) |\ | (inner_node2) |\ | (inner_node3) | | |-------------------| 37651c0b2f7Stbbdev |--| | \| | \| | | 37751c0b2f7Stbbdev | |------------------| |------------------| |------------------| | 37851c0b2f7Stbbdev | | 37951c0b2f7Stbbdev |-------------------------------------------------------------------| 38051c0b2f7Stbbdev 38151c0b2f7Stbbdev */ 38251c0b2f7Stbbdev int test_nested_adder(bool hidden=false) { 38351c0b2f7Stbbdev tbb::flow::graph g; 38451c0b2f7Stbbdev tbb::flow::composite_node<std::tuple<int, int>, std::tuple<int> > outer_node(g); 38551c0b2f7Stbbdev typedef tbb::flow::composite_node<std::tuple<int, int>, std::tuple<int> > base_type; 38651c0b2f7Stbbdev tbb::flow::broadcast_node<int> input(g); 38751c0b2f7Stbbdev tbb::flow::queue_node<int> output(g); 38851c0b2f7Stbbdev 38951c0b2f7Stbbdev adder_node inner_node1(g, hidden); 39051c0b2f7Stbbdev adder_node inner_node2(g, hidden); 39151c0b2f7Stbbdev adder_node inner_node3(g, hidden); 39251c0b2f7Stbbdev 39351c0b2f7Stbbdev outer_node.set_external_ports(base_type::input_ports_type(tbb::flow::input_port<0>(inner_node1), tbb::flow::input_port<1>(inner_node1)), base_type::output_ports_type(tbb::flow::output_port<0>(inner_node3))); 39451c0b2f7Stbbdev 39551c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::input_port<0>(outer_node) == &tbb::flow::input_port<0>(inner_node1)), "input port 0 of inner_node1 not bound to input port 0 in outer_node"); 39651c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::input_port<1>(outer_node) == &tbb::flow::input_port<1>(inner_node1)), "input port 1 of inner_node1 not bound to input port 1 in outer_node"); 39751c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::output_port<0>(outer_node) == &tbb::flow::output_port<0>(inner_node3)), "output port 0 of inner_node3 not bound to output port 0 in outer_node"); 39851c0b2f7Stbbdev 39951c0b2f7Stbbdev tbb::flow::make_edge(input, tbb::flow::input_port<0>(outer_node)/*inner_node1*/); 40051c0b2f7Stbbdev tbb::flow::make_edge(input, tbb::flow::input_port<1>(outer_node)/*inner_node1*/); 40151c0b2f7Stbbdev 40251c0b2f7Stbbdev tbb::flow::make_edge(inner_node1, tbb::flow::input_port<0>(inner_node2)); 40351c0b2f7Stbbdev tbb::flow::make_edge(inner_node1, tbb::flow::input_port<1>(inner_node2)); 40451c0b2f7Stbbdev 40551c0b2f7Stbbdev tbb::flow::make_edge(inner_node2, tbb::flow::input_port<0>(inner_node3)); 40651c0b2f7Stbbdev tbb::flow::make_edge(inner_node2, tbb::flow::input_port<1>(inner_node3)); 40751c0b2f7Stbbdev 40851c0b2f7Stbbdev tbb::flow::make_edge(outer_node/*inner_node3*/, output); 40951c0b2f7Stbbdev 41051c0b2f7Stbbdev if(hidden) 41151c0b2f7Stbbdev outer_node.add_nodes(inner_node1, inner_node2, inner_node3); 41251c0b2f7Stbbdev else 41351c0b2f7Stbbdev outer_node.add_visible_nodes(inner_node1, inner_node2, inner_node3); 41451c0b2f7Stbbdev 41551c0b2f7Stbbdev int out; 41651c0b2f7Stbbdev for (int i = 1; i < 200000; ++i) { 41751c0b2f7Stbbdev input.try_put(i); 41851c0b2f7Stbbdev g.wait_for_all(); 41951c0b2f7Stbbdev output.try_get(out); 42051c0b2f7Stbbdev CHECK_MESSAGE( (tbb::flow::output_port<0>(outer_node).try_get(out) == output.try_get(out)), "output from outer_node does not match output from graph"); 42151c0b2f7Stbbdev CHECK_MESSAGE( (out == 8*i), "output from outer_node not correct"); 42251c0b2f7Stbbdev } 42351c0b2f7Stbbdev g.wait_for_all(); 42451c0b2f7Stbbdev 42551c0b2f7Stbbdev return 0; 42651c0b2f7Stbbdev } 42751c0b2f7Stbbdev 42851c0b2f7Stbbdev template< typename T > 42951c0b2f7Stbbdev class prefix_node : public tbb::flow::composite_node< std::tuple< T, T, T, T, T >, std::tuple< T, T, T, T, T > > { 43051c0b2f7Stbbdev typedef std::tuple< T, T, T, T, T > my_tuple_t; 43151c0b2f7Stbbdev public: 43251c0b2f7Stbbdev tbb::flow::join_node< my_tuple_t, tbb::flow::queueing > j; 43351c0b2f7Stbbdev tbb::flow::split_node< my_tuple_t > s; 43451c0b2f7Stbbdev private: 43551c0b2f7Stbbdev tbb::flow::function_node< my_tuple_t, my_tuple_t > f; 43651c0b2f7Stbbdev typedef tbb::flow::composite_node< my_tuple_t, my_tuple_t > base_type; 43751c0b2f7Stbbdev 43851c0b2f7Stbbdev struct f_body { 43951c0b2f7Stbbdev my_tuple_t operator()( const my_tuple_t &t ) { 44051c0b2f7Stbbdev return my_tuple_t( std::get<0>(t), 44151c0b2f7Stbbdev std::get<0>(t) + std::get<1>(t), 44251c0b2f7Stbbdev std::get<0>(t) + std::get<1>(t) + std::get<2>(t), 44351c0b2f7Stbbdev std::get<0>(t) + std::get<1>(t) + std::get<2>(t) + std::get<3>(t), 44451c0b2f7Stbbdev std::get<0>(t) + std::get<1>(t) + std::get<2>(t) + std::get<3>(t) + std::get<4>(t) ); 44551c0b2f7Stbbdev } 44651c0b2f7Stbbdev }; 44751c0b2f7Stbbdev 44851c0b2f7Stbbdev public: 44951c0b2f7Stbbdev prefix_node(tbb::flow::graph &g, bool hidden = false ) : base_type(g), j(g), s(g), f(g, tbb::flow::serial, f_body() ) { 45051c0b2f7Stbbdev tbb::flow::make_edge( j, f ); 45151c0b2f7Stbbdev tbb::flow::make_edge( f, s ); 45251c0b2f7Stbbdev 45351c0b2f7Stbbdev typename base_type::input_ports_type input_tuple(tbb::flow::input_port<0>(j), tbb::flow::input_port<1>(j), tbb::flow::input_port<2>(j), tbb::flow::input_port<3>(j), tbb::flow::input_port<4>(j)); 45451c0b2f7Stbbdev 45551c0b2f7Stbbdev typename base_type::output_ports_type output_tuple(tbb::flow::output_port<0>(s), tbb::flow::output_port<1>(s), tbb::flow::output_port<2>(s), tbb::flow::output_port<3>(s), tbb::flow::output_port<4>(s)); 45651c0b2f7Stbbdev 45751c0b2f7Stbbdev base_type::set_external_ports(input_tuple, output_tuple); 45851c0b2f7Stbbdev 45951c0b2f7Stbbdev if(hidden) 46051c0b2f7Stbbdev base_type::add_nodes(j,s,f); 46151c0b2f7Stbbdev else 46251c0b2f7Stbbdev base_type::add_visible_nodes(j,s,f); 46351c0b2f7Stbbdev 46451c0b2f7Stbbdev } 46551c0b2f7Stbbdev }; 46651c0b2f7Stbbdev 46751c0b2f7Stbbdev int test_prefix(bool hidden = false) { 46851c0b2f7Stbbdev tbb::flow::graph g; 46951c0b2f7Stbbdev prefix_node<double> p(g, hidden); 47051c0b2f7Stbbdev 47151c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<0>(p.input_ports()) == &tbb::flow::input_port<0>(p.j)), "input port 0 of j is not bound to input port 0 of composite node p"); 47251c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::input_port<1>(p.j) == &tbb::flow::input_port<1>(p.j)), "input port 1 of j is not bound to input port 1 of composite node p"); 47351c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<2>(p.input_ports()) == &tbb::flow::input_port<2>(p.j)), "input port 2 of j is not bound to input port 2 of composite node p"); 47451c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::input_port<3>(p.j) == &tbb::flow::input_port<3>(p.j)), "input port 3 of j is not bound to input port 3 of composite node p"); 47551c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<4>(p.input_ports()) == &tbb::flow::input_port<4>(p.j)), "input port 4 of j is not bound to input port 4 of composite node p"); 47651c0b2f7Stbbdev 47751c0b2f7Stbbdev 47851c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<0>(p.output_ports()) == &tbb::flow::output_port<0>(p.s)), "output port 0 of s is not bound to output port 0 of composite node p"); 47951c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::output_port<1>(p.s) == &tbb::flow::output_port<1>(p.s)), "output port 1 of s is not bound to output port 1 of composite node p"); 48051c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<2>(p.output_ports()) == &tbb::flow::output_port<2>(p.s)), "output port 2 of s is not bound to output port 2 of composite node p"); 48151c0b2f7Stbbdev CHECK_MESSAGE( (&tbb::flow::output_port<3>(p.s) == &tbb::flow::output_port<3>(p.s)), "output port 3 of s is not bound to output port 3 of composite node p"); 48251c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<4>(p.output_ports()) == &tbb::flow::output_port<4>(p.s)), "output port 4 of s is not bound to output port 4 of composite node p"); 48351c0b2f7Stbbdev 48451c0b2f7Stbbdev std::vector< tbb::flow::queue_node<double> > v( 5, tbb::flow::queue_node<double>(g) ); 48551c0b2f7Stbbdev tbb::flow::make_edge( tbb::flow::output_port<0>(p), v[0] ); 48651c0b2f7Stbbdev tbb::flow::make_edge( tbb::flow::output_port<1>(p), v[1] ); 48751c0b2f7Stbbdev tbb::flow::make_edge( tbb::flow::output_port<2>(p), v[2] ); 48851c0b2f7Stbbdev tbb::flow::make_edge( tbb::flow::output_port<3>(p), v[3] ); 48951c0b2f7Stbbdev tbb::flow::make_edge( tbb::flow::output_port<4>(p), v[4] ); 49051c0b2f7Stbbdev 49151c0b2f7Stbbdev for( double offset = 1; offset < 10000; offset *= 10 ) { 49251c0b2f7Stbbdev tbb::flow::input_port<0>(p).try_put( offset ); 49351c0b2f7Stbbdev tbb::flow::input_port<1>(p).try_put( offset + 1 ); 49451c0b2f7Stbbdev tbb::flow::input_port<2>(p).try_put( offset + 2 ); 49551c0b2f7Stbbdev tbb::flow::input_port<3>(p).try_put( offset + 3 ); 49651c0b2f7Stbbdev tbb::flow::input_port<4>(p).try_put( offset + 4 ); 49751c0b2f7Stbbdev } 49851c0b2f7Stbbdev g.wait_for_all(); 49951c0b2f7Stbbdev 50051c0b2f7Stbbdev double x; 50151c0b2f7Stbbdev while ( v[0].try_get(x) ) { 50251c0b2f7Stbbdev g.wait_for_all(); 50351c0b2f7Stbbdev for ( int i = 1; i < 5; ++i ) { 50451c0b2f7Stbbdev v[i].try_get(x); 50551c0b2f7Stbbdev g.wait_for_all(); 50651c0b2f7Stbbdev } 50751c0b2f7Stbbdev } 50851c0b2f7Stbbdev return 0; 50951c0b2f7Stbbdev } 51051c0b2f7Stbbdev 51151c0b2f7Stbbdev struct input_only_output_only_seq { 51251c0b2f7Stbbdev int operator()(int i){ return (i + 3) / 4 - 1;} 51351c0b2f7Stbbdev }; 51451c0b2f7Stbbdev 51551c0b2f7Stbbdev void input_only_output_only_composite(bool hidden) { 51651c0b2f7Stbbdev tbb::flow::graph g; 51751c0b2f7Stbbdev 51851c0b2f7Stbbdev tbb::flow::composite_node<std::tuple<int>, std::tuple<int> > input_output(g); 51951c0b2f7Stbbdev 52051c0b2f7Stbbdev typedef tbb::flow::composite_node<std::tuple<int>, std::tuple<> > input_only_composite; 52151c0b2f7Stbbdev typedef tbb::flow::composite_node<std::tuple<>, std::tuple<int> > output_only_composite; 52251c0b2f7Stbbdev 52351c0b2f7Stbbdev typedef tbb::flow::input_node<int> src_type; 52451c0b2f7Stbbdev typedef tbb::flow::queue_node<int> q_type; 52551c0b2f7Stbbdev typedef tbb::flow::function_node<int, int> f_type; 52651c0b2f7Stbbdev typedef tbb::flow::sequencer_node<int> sequencer_type; 52751c0b2f7Stbbdev 52851c0b2f7Stbbdev int num = 0; 52951c0b2f7Stbbdev int finish=1000; 53051c0b2f7Stbbdev int step = 4; 53151c0b2f7Stbbdev 53251c0b2f7Stbbdev input_only_composite a_in(g); 53351c0b2f7Stbbdev output_only_composite a_out(g); 53451c0b2f7Stbbdev 53551c0b2f7Stbbdev src_type src(g, my_input_body(finish, step)); 53651c0b2f7Stbbdev q_type que(g); 53751c0b2f7Stbbdev f_type f(g, 1, passthru_body()); 53851c0b2f7Stbbdev 53951c0b2f7Stbbdev // Sequencer_node is needed, because serial function_node guarantees only serial body execution, 54051c0b2f7Stbbdev // not a sequential order of messages dispatch 54151c0b2f7Stbbdev sequencer_type seq(g, input_only_output_only_seq()); 54251c0b2f7Stbbdev 54351c0b2f7Stbbdev std::tuple<f_type& > input_tuple(f); 54451c0b2f7Stbbdev a_in.set_external_ports(input_tuple); 54551c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<0>(a_in.input_ports()) == &f), "f not bound to input port 0 in composite_node a_in"); 54651c0b2f7Stbbdev 54751c0b2f7Stbbdev std::tuple<src_type&> output_tuple(src); 54851c0b2f7Stbbdev a_out.set_external_ports(output_tuple); 54951c0b2f7Stbbdev CHECK_MESSAGE( (&std::get<0>(a_out.output_ports()) == &src), "src not bound to output port 0 in composite_node a_out"); 55051c0b2f7Stbbdev 55151c0b2f7Stbbdev if(hidden) { 55251c0b2f7Stbbdev a_in.add_nodes(f, seq, que); 55351c0b2f7Stbbdev a_out.add_nodes(src); 55451c0b2f7Stbbdev } else { 55551c0b2f7Stbbdev a_in.add_visible_nodes(f, seq, que); 55651c0b2f7Stbbdev a_out.add_visible_nodes(src); 55751c0b2f7Stbbdev } 55851c0b2f7Stbbdev 55951c0b2f7Stbbdev tbb::flow::make_edge(a_out, a_in); 56051c0b2f7Stbbdev tbb::flow::make_edge(f, seq); 56151c0b2f7Stbbdev tbb::flow::make_edge(seq, que); 56251c0b2f7Stbbdev src.activate(); 56351c0b2f7Stbbdev g.wait_for_all(); 56451c0b2f7Stbbdev 56551c0b2f7Stbbdev for(int i = 1; i<finish/step; ++i) { 56651c0b2f7Stbbdev que.try_get(num); 56751c0b2f7Stbbdev CHECK_MESSAGE( (num == 4*i - 3), "number does not match position in sequence"); 56851c0b2f7Stbbdev } 56951c0b2f7Stbbdev g.wait_for_all(); 57051c0b2f7Stbbdev } 57151c0b2f7Stbbdev 57251c0b2f7Stbbdev //! Test all node types inside composite node 57351c0b2f7Stbbdev //! \brief \ref error_guessing 57451c0b2f7Stbbdev TEST_CASE("Add all nodes"){ 57551c0b2f7Stbbdev add_all_nodes(); 57651c0b2f7Stbbdev } 57751c0b2f7Stbbdev 57851c0b2f7Stbbdev //! Test single node inside composite nodes 57951c0b2f7Stbbdev //! \brief \ref error_guessing 58051c0b2f7Stbbdev TEST_CASE("Tiny tests"){ 58151c0b2f7Stbbdev test_tiny(false); 58251c0b2f7Stbbdev test_tiny(true); 58351c0b2f7Stbbdev } 58451c0b2f7Stbbdev 58551c0b2f7Stbbdev //! Test basic adders in composite node 58651c0b2f7Stbbdev //! \brief \ref error_guessing 58751c0b2f7Stbbdev TEST_CASE("Adder tests"){ 58851c0b2f7Stbbdev test_adder(false); 58951c0b2f7Stbbdev test_adder(true); 59051c0b2f7Stbbdev } 59151c0b2f7Stbbdev 59251c0b2f7Stbbdev //! Test nested adders in composite node 59351c0b2f7Stbbdev //! \brief \ref error_guessing 59451c0b2f7Stbbdev TEST_CASE("Nested adder tests"){ 59551c0b2f7Stbbdev test_nested_adder(true); 59651c0b2f7Stbbdev test_nested_adder(false); 59751c0b2f7Stbbdev } 59851c0b2f7Stbbdev 59951c0b2f7Stbbdev //! Test returning a subset of inputs 60051c0b2f7Stbbdev //! \brief \ref error_guessing 60151c0b2f7Stbbdev TEST_CASE("Prefix test"){ 60251c0b2f7Stbbdev test_prefix(false); 60351c0b2f7Stbbdev test_prefix(true); 60451c0b2f7Stbbdev } 60551c0b2f7Stbbdev 60651c0b2f7Stbbdev //! Test input-only composite node 60751c0b2f7Stbbdev //! \brief \ref error_guessing \ref boundary 60851c0b2f7Stbbdev TEST_CASE("Input-only composite"){ 60951c0b2f7Stbbdev input_only_output_only_composite(true); 61051c0b2f7Stbbdev input_only_output_only_composite(false); 61151c0b2f7Stbbdev } 61251c0b2f7Stbbdev 613