1 /* 2 Copyright (c) 2020-2023 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #if __INTEL_COMPILER && _MSC_VER 18 #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated 19 #endif 20 21 #define CONFORMANCE_MULTIFUNCTION_NODE 22 23 #include "conformance_flowgraph.h" 24 #include "common/test_invoke.h" 25 26 //! \file conformance_multifunction_node.cpp 27 //! \brief Test for [flow_graph.function_node] specification 28 29 using input_msg = conformance::message</*default_ctor*/true, /*copy_ctor*/true, /*copy_assign*/false>; 30 using output_msg = conformance::message</*default_ctor*/false, /*copy_ctor*/false, /*copy_assign*/false>; 31 32 /* 33 Test function_node is a graph_node, receiver<Input>, and sender<Output> 34 */ 35 template<typename I, typename O> 36 void test_inheritance(){ 37 using namespace oneapi::tbb::flow; 38 39 CHECK_MESSAGE((std::is_base_of<graph_node, multifunction_node<I, O>>::value), "multifunction_node should be derived from graph_node"); 40 CHECK_MESSAGE((std::is_base_of<receiver<I>, multifunction_node<I, O>>::value), "multifunction_node should be derived from receiver<Input>"); 41 } 42 43 //! Test node reject the incoming message if the concurrency limit achieved. 44 //! \brief \ref interface 45 TEST_CASE("multifunction_node with rejecting policy"){ 46 conformance::test_rejecting<oneapi::tbb::flow::multifunction_node<int, std::tuple<int>, oneapi::tbb::flow::rejecting>>(); 47 } 48 49 //! Test nodes for execution with priority in single-threaded configuration 50 //! \brief \ref interface 51 TEST_CASE("multifunction_node priority"){ 52 conformance::test_priority<oneapi::tbb::flow::multifunction_node<input_msg, std::tuple<int>>, input_msg>(oneapi::tbb::flow::unlimited); 53 } 54 55 //! Test function_node has a user-settable concurrency limit. It can be set to one of predefined values. 56 //! The user can also provide a value of type std::size_t to limit concurrency. 57 //! Test that not more than limited threads works in parallel. 58 //! \brief \ref interface 59 TEST_CASE("multifunction_node concurrency"){ 60 conformance::test_concurrency<oneapi::tbb::flow::multifunction_node<int, std::tuple<int>>>(); 61 } 62 63 //! Test all node constructors 64 //! \brief \ref interface 65 TEST_CASE("multifunction_node constructors"){ 66 using namespace oneapi::tbb::flow; 67 graph g; 68 69 conformance::counting_functor<int> fun; 70 71 multifunction_node<int, std::tuple<int>> fn1(g, unlimited, fun); 72 multifunction_node<int, std::tuple<int>> fn2(g, unlimited, fun, oneapi::tbb::flow::node_priority_t(1)); 73 74 multifunction_node<int, std::tuple<int>, lightweight> lw_node1(g, serial, fun, lightweight()); 75 multifunction_node<int, std::tuple<int>, lightweight> lw_node2(g, serial, fun, lightweight(), oneapi::tbb::flow::node_priority_t(1)); 76 } 77 78 //! The node that is constructed has a reference to the same graph object as src, has a copy of the initial body used by src, and has the same concurrency threshold as src. 79 //! The predecessors and successors of src are not copied. 80 //! \brief \ref interface 81 TEST_CASE("multifunction_node copy constructor"){ 82 conformance::test_copy_ctor<oneapi::tbb::flow::multifunction_node<int, std::tuple<int>>>(); 83 } 84 85 //! Test node not buffered unsuccessful message, and try_get after rejection should not succeed. 86 //! \brief \ref requirement 87 TEST_CASE("multifunction_node buffering"){ 88 conformance::dummy_functor<int> fun; 89 conformance::test_buffering<oneapi::tbb::flow::multifunction_node<input_msg, std::tuple<int>, 90 oneapi::tbb::flow::rejecting>, input_msg>(oneapi::tbb::flow::unlimited, fun); 91 } 92 93 //! Test multifunction_node broadcasting 94 //! \brief \ref requirement 95 TEST_CASE("multifunction_node broadcast"){ 96 conformance::counting_functor<int> fun(conformance::expected); 97 conformance::test_forwarding<oneapi::tbb::flow::multifunction_node<input_msg, std::tuple<int>>, input_msg, int>(1, oneapi::tbb::flow::unlimited, fun); 98 } 99 100 //! Test the body object passed to a node is copied 101 //! \brief \ref interface 102 TEST_CASE("multifunction_node copy body"){ 103 conformance::test_copy_body_function<oneapi::tbb::flow::multifunction_node<int, std::tuple<int>>, conformance::copy_counting_object<int>>(oneapi::tbb::flow::unlimited); 104 } 105 106 //! Test execution of node body 107 //! Test node can do try_put call 108 //! \brief \ref interface \ref requirement 109 TEST_CASE("multifunction_node body") { 110 conformance::test_body_exec<oneapi::tbb::flow::multifunction_node<input_msg, std::tuple<output_msg>, oneapi::tbb::flow::rejecting>, input_msg, output_msg>(oneapi::tbb::flow::unlimited); 111 } 112 113 //! Test multifunction_node output_ports() returns a tuple of output ports. 114 //! \brief \ref interface \ref requirement 115 TEST_CASE("multifunction_node output_ports") { 116 using namespace oneapi::tbb::flow; 117 graph g; 118 conformance::dummy_functor<int> fun; 119 oneapi::tbb::flow::multifunction_node <int, std::tuple<int>> node(g, unlimited, fun); 120 121 CHECK_MESSAGE((std::is_same<oneapi::tbb::flow::multifunction_node<int, std::tuple<int>>::output_ports_type&, 122 decltype(node.output_ports())>::value), "multifunction_node output_ports should returns a tuple of output ports"); 123 } 124 125 //! Test inheritance relations 126 //! \brief \ref interface 127 TEST_CASE("multifunction_node superclasses"){ 128 test_inheritance<int, std::tuple<int>>(); 129 test_inheritance<void*, std::tuple<float>>(); 130 test_inheritance<input_msg, std::tuple<output_msg>>(); 131 } 132 133 //! Test node Input class meet the DefaultConstructible and CopyConstructible requirements and Output class meet the CopyConstructible requirements. 134 //! \brief \ref interface \ref requirement 135 TEST_CASE("Test function_node Output and Input class") { 136 using Body = conformance::copy_counting_object<int>; 137 conformance::test_output_input_class<oneapi::tbb::flow::multifunction_node<Body, std::tuple<Body>>, Body>(); 138 } 139 140 #if __TBB_CPP17_INVOKE_PRESENT 141 //! Test that multifunction_node uses std::invoke to execute the body 142 //! \brief \ref interface \ref requirement 143 TEST_CASE("Test multifunction_node and std::invoke") { 144 using namespace oneapi::tbb::flow; 145 146 using output_type1 = test_invoke::SmartID<std::size_t>; 147 using input_type = test_invoke::SmartID<output_type1>; 148 149 using output_tuple1 = std::tuple<output_type1, output_type1>; 150 using output_tuple2 = std::tuple<std::size_t>; 151 152 using first_mf_node_type = multifunction_node<input_type, output_tuple1>; 153 using second_mf_node_type = multifunction_node<output_type1, output_tuple2>; 154 155 using first_ports_type = typename first_mf_node_type::output_ports_type; 156 using second_ports_type = typename second_mf_node_type::output_ports_type; 157 158 graph g; 159 160 auto first_body = &input_type::template send_id<first_ports_type>; 161 auto second_body = &output_type1::template send_id<second_ports_type>; 162 163 first_mf_node_type mf1(g, unlimited, first_body); 164 second_mf_node_type mf21(g, unlimited, second_body); 165 second_mf_node_type mf22(g, unlimited, second_body); 166 167 buffer_node<std::size_t> buf(g); 168 169 make_edge(output_port<0>(mf1), mf21); 170 make_edge(output_port<1>(mf1), mf22); 171 172 make_edge(output_port<0>(mf21), buf); 173 make_edge(output_port<0>(mf22), buf); 174 175 mf1.try_put(input_type{output_type1{1}}); 176 177 g.wait_for_all(); 178 179 std::size_t buf_size = 0; 180 std::size_t tmp = 0; 181 while(buf.try_get(tmp)) { 182 ++buf_size; 183 CHECK(tmp == 1); 184 } 185 186 CHECK(buf_size == 2); 187 } 188 #endif 189