1 /* 2 Copyright (c) 2020-2021 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_INPUT_NODE 22 23 #include "conformance_flowgraph.h" 24 25 //! \file conformance_input_node.cpp 26 //! \brief Test for [flow_graph.input_node] specification 27 28 using output_msg = conformance::message<true, true, true>; 29 30 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 31 int input_body_f(tbb::flow_control&) { return 42; } 32 33 void test_deduction_guides() { 34 using namespace tbb::flow; 35 graph g; 36 37 auto lambda = [](tbb::flow_control&) { return 42; }; 38 auto non_const_lambda = [](tbb::flow_control&) mutable { return 42; }; 39 40 // Tests for input_node(graph&, Body) 41 input_node s1(g, lambda); 42 static_assert(std::is_same_v<decltype(s1), input_node<int>>); 43 44 input_node s2(g, non_const_lambda); 45 static_assert(std::is_same_v<decltype(s2), input_node<int>>); 46 47 input_node s3(g, input_body_f); 48 static_assert(std::is_same_v<decltype(s3), input_node<int>>); 49 50 input_node s4(s3); 51 static_assert(std::is_same_v<decltype(s4), input_node<int>>); 52 53 #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 54 broadcast_node<int> bc(g); 55 56 // Tests for input_node(const node_set<Args...>&, Body) 57 input_node s5(precedes(bc), lambda); 58 static_assert(std::is_same_v<decltype(s5), input_node<int>>); 59 60 input_node s6(precedes(bc), non_const_lambda); 61 static_assert(std::is_same_v<decltype(s6), input_node<int>>); 62 63 input_node s7(precedes(bc), input_body_f); 64 static_assert(std::is_same_v<decltype(s7), input_node<int>>); 65 #endif 66 g.wait_for_all(); 67 } 68 69 #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 70 71 template<typename O> 72 void test_inheritance(){ 73 using namespace oneapi::tbb::flow; 74 75 CHECK_MESSAGE((std::is_base_of<graph_node, input_node<O>>::value), "input_node should be derived from graph_node"); 76 CHECK_MESSAGE((std::is_base_of<sender<O>, input_node<O>>::value), "input_node should be derived from sender<Output>"); 77 CHECK_MESSAGE((!std::is_base_of<receiver<O>, input_node<O>>::value), "input_node cannot have predecessors"); 78 } 79 80 //! Test the body object passed to a node is copied 81 //! \brief \ref interface 82 TEST_CASE("input_node and body copying"){ 83 conformance::test_copy_body_function<oneapi::tbb::flow::input_node<int>, conformance::copy_counting_object<int>>(); 84 } 85 86 //! The node that is constructed has a reference to the same graph object as src, 87 //! has a copy of the initial body used by src. 88 //! The successors of src are not copied. 89 //! \brief \ref requirement 90 TEST_CASE("input_node copy constructor"){ 91 using namespace oneapi::tbb::flow; 92 graph g; 93 94 conformance::copy_counting_object<output_msg> fun2; 95 96 input_node<output_msg> node1(g, fun2); 97 conformance::test_push_receiver<output_msg> node2(g); 98 conformance::test_push_receiver<output_msg> node3(g); 99 100 oneapi::tbb::flow::make_edge(node1, node2); 101 102 input_node<output_msg> node_copy(node1); 103 104 conformance::copy_counting_object<output_msg> b2 = copy_body<conformance::copy_counting_object<output_msg>, input_node<output_msg>>(node_copy); 105 106 CHECK_MESSAGE((fun2.copy_count + 1 < b2.copy_count), "constructor should copy bodies"); 107 108 oneapi::tbb::flow::make_edge(node_copy, node3); 109 110 node_copy.activate(); 111 g.wait_for_all(); 112 113 CHECK_MESSAGE((conformance::get_values(node2).size() == 0 && conformance::get_values(node3).size() == 1), "Copied node doesn`t copy successor"); 114 115 node1.activate(); 116 g.wait_for_all(); 117 118 CHECK_MESSAGE((conformance::get_values(node2).size() == 1 && conformance::get_values(node3).size() == 0), "Copied node doesn`t copy successor"); 119 } 120 121 //! Test inheritance relations 122 //! \brief \ref interface 123 TEST_CASE("input_node superclasses"){ 124 test_inheritance<int>(); 125 test_inheritance<void*>(); 126 test_inheritance<output_msg>(); 127 } 128 129 //! Test input_node forwarding 130 //! \brief \ref requirement 131 TEST_CASE("input_node forwarding"){ 132 conformance::counting_functor<output_msg> fun(conformance::expected); 133 conformance::test_forwarding<oneapi::tbb::flow::input_node<output_msg>, void, output_msg>(5, fun); 134 } 135 136 //! Test input_node buffering 137 //! \brief \ref requirement 138 TEST_CASE("input_node buffering"){ 139 conformance::dummy_functor<int> fun; 140 conformance::test_buffering<oneapi::tbb::flow::input_node<int>, int>(fun); 141 } 142 143 //! Test calling input_node body 144 //! \brief \ref interface \ref requirement 145 TEST_CASE("input_node body") { 146 oneapi::tbb::flow::graph g; 147 constexpr std::size_t counting_threshold = 10; 148 conformance::counting_functor<output_msg> fun(counting_threshold); 149 150 oneapi::tbb::flow::input_node<output_msg> node1(g, fun); 151 conformance::test_push_receiver<output_msg> node2(g); 152 153 oneapi::tbb::flow::make_edge(node1, node2); 154 155 node1.activate(); 156 g.wait_for_all(); 157 158 CHECK_MESSAGE((conformance::get_values(node2).size() == counting_threshold), "Descendant of the node needs to be receive N messages"); 159 CHECK_MESSAGE((fun.execute_count == counting_threshold + 1), "Body of the node needs to be executed N + 1 times"); 160 } 161 162 //! Test deduction guides 163 //! \brief \ref interface \ref requirement 164 TEST_CASE("Deduction guides"){ 165 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 166 test_deduction_guides(); 167 #endif 168 } 169 170 //! Test that measured concurrency respects set limits 171 //! \brief \ref requirement 172 TEST_CASE("concurrency follows set limits"){ 173 oneapi::tbb::global_control c(oneapi::tbb::global_control::max_allowed_parallelism, 174 oneapi::tbb::this_task_arena::max_concurrency()); 175 176 177 utils::ConcurrencyTracker::Reset(); 178 oneapi::tbb::flow::graph g; 179 conformance::concurrency_peak_checker_body counter(1); 180 oneapi::tbb::flow::input_node<int> testing_node(g, counter); 181 182 conformance::test_push_receiver<int> sink(g); 183 184 make_edge(testing_node, sink); 185 testing_node.activate(); 186 187 g.wait_for_all(); 188 } 189 190 //! Test node Output class meet the CopyConstructible requirements. 191 //! \brief \ref interface \ref requirement 192 TEST_CASE("Test input_node Output class") { 193 conformance::test_output_class<oneapi::tbb::flow::input_node<conformance::copy_counting_object<int>>>(); 194 } 195 196 struct input_node_counter{ 197 static int count; 198 int N; 199 input_node_counter(int n) : N(n){}; 200 201 int operator()( oneapi::tbb::flow_control & fc ) { 202 ++count; 203 if(count > N){ 204 fc.stop(); 205 return N; 206 } 207 return N; 208 } 209 }; 210 211 struct function_node_counter{ 212 static int count; 213 214 int operator()( int ) { 215 ++count; 216 utils::doDummyWork(1000000); 217 CHECK_MESSAGE((input_node_counter::count <= function_node_counter::count + 1), "input_node `try_get()' call testing: a call to body is made only when the internal buffer is empty"); 218 return 1; 219 } 220 }; 221 222 int input_node_counter::count = 0; 223 int function_node_counter::count = 0; 224 225 //! Test input_node `try_get()' call testing: a call to body is made only when the internal buffer is empty. 226 //! \brief \ref requirement 227 TEST_CASE("input_node `try_get()' call testing: a call to body is made only when the internal buffer is empty.") { 228 oneapi::tbb::global_control control(oneapi::tbb::global_control::max_allowed_parallelism, 1); 229 oneapi::tbb::flow::graph g; 230 input_node_counter fun1(500); 231 function_node_counter fun2; 232 233 oneapi::tbb::flow::function_node <int, int, oneapi::tbb::flow::rejecting> fnode(g, oneapi::tbb::flow::serial, fun2); 234 oneapi::tbb::flow::input_node<int> testing_node(g, fun1); 235 236 make_edge(testing_node, fnode); 237 testing_node.activate(); 238 239 g.wait_for_all(); 240 } 241