1*51c0b2f7Stbbdev /* 2*51c0b2f7Stbbdev Copyright (c) 2020 Intel Corporation 3*51c0b2f7Stbbdev 4*51c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License"); 5*51c0b2f7Stbbdev you may not use this file except in compliance with the License. 6*51c0b2f7Stbbdev You may obtain a copy of the License at 7*51c0b2f7Stbbdev 8*51c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0 9*51c0b2f7Stbbdev 10*51c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software 11*51c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS, 12*51c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*51c0b2f7Stbbdev See the License for the specific language governing permissions and 14*51c0b2f7Stbbdev limitations under the License. 15*51c0b2f7Stbbdev */ 16*51c0b2f7Stbbdev 17*51c0b2f7Stbbdev #include "common/test.h" 18*51c0b2f7Stbbdev 19*51c0b2f7Stbbdev #include "common/utils.h" 20*51c0b2f7Stbbdev #include "common/graph_utils.h" 21*51c0b2f7Stbbdev 22*51c0b2f7Stbbdev #include "tbb/flow_graph.h" 23*51c0b2f7Stbbdev #include "tbb/task_arena.h" 24*51c0b2f7Stbbdev 25*51c0b2f7Stbbdev #include "tbb/global_control.h" 26*51c0b2f7Stbbdev #include "conformance_flowgraph.h" 27*51c0b2f7Stbbdev 28*51c0b2f7Stbbdev //! \file conformance_continue_node.cpp 29*51c0b2f7Stbbdev //! \brief Test for [flow_graph.continue_node] specification 30*51c0b2f7Stbbdev 31*51c0b2f7Stbbdev /* 32*51c0b2f7Stbbdev TODO: implement missing conformance tests for continue_node: 33*51c0b2f7Stbbdev - [ ] For `test_forwarding' check that the value passed is the actual one received. 34*51c0b2f7Stbbdev - [ ] The `copy_body' function copies altered body (e.g. after its successful invocation). 35*51c0b2f7Stbbdev - [ ] Improve CTAD test. 36*51c0b2f7Stbbdev - [ ] Improve constructors test, including addition of calls to constructors with 37*51c0b2f7Stbbdev `number_of_predecessors' parameter. 38*51c0b2f7Stbbdev - [ ] Explicit test for copy constructor of the node. 39*51c0b2f7Stbbdev - [ ] Rewrite test_priority. 40*51c0b2f7Stbbdev - [ ] Check `Output' type indeed copy-constructed and copy-assigned while working with the node. 41*51c0b2f7Stbbdev - [ ] Explicit test for correct working of `number_of_predecessors' constructor parameter, 42*51c0b2f7Stbbdev including taking it into account when making and removing edges. 43*51c0b2f7Stbbdev - [ ] Add testing of `try_put' statement. In particular that it does not wait for the execution of 44*51c0b2f7Stbbdev the body to complete. 45*51c0b2f7Stbbdev */ 46*51c0b2f7Stbbdev 47*51c0b2f7Stbbdev void test_cont_body(){ 48*51c0b2f7Stbbdev tbb::flow::graph g; 49*51c0b2f7Stbbdev inc_functor<int> cf; 50*51c0b2f7Stbbdev cf.execute_count = 0; 51*51c0b2f7Stbbdev 52*51c0b2f7Stbbdev tbb::flow::continue_node<int> node1(g, cf); 53*51c0b2f7Stbbdev 54*51c0b2f7Stbbdev const size_t n = 10; 55*51c0b2f7Stbbdev for(size_t i = 0; i < n; ++i) { 56*51c0b2f7Stbbdev CHECK_MESSAGE((node1.try_put(tbb::flow::continue_msg()) == true), 57*51c0b2f7Stbbdev "continue_node::try_put() should never reject a message."); 58*51c0b2f7Stbbdev } 59*51c0b2f7Stbbdev g.wait_for_all(); 60*51c0b2f7Stbbdev 61*51c0b2f7Stbbdev CHECK_MESSAGE( (cf.execute_count == n), "Body of the first node needs to be executed N times"); 62*51c0b2f7Stbbdev } 63*51c0b2f7Stbbdev 64*51c0b2f7Stbbdev template<typename O> 65*51c0b2f7Stbbdev void test_inheritance(){ 66*51c0b2f7Stbbdev using namespace tbb::flow; 67*51c0b2f7Stbbdev 68*51c0b2f7Stbbdev CHECK_MESSAGE( (std::is_base_of<graph_node, continue_node<O>>::value), "continue_node should be derived from graph_node"); 69*51c0b2f7Stbbdev CHECK_MESSAGE( (std::is_base_of<receiver<continue_msg>, continue_node<O>>::value), "continue_node should be derived from receiver<Input>"); 70*51c0b2f7Stbbdev CHECK_MESSAGE( (std::is_base_of<sender<O>, continue_node<O>>::value), "continue_node should be derived from sender<Output>"); 71*51c0b2f7Stbbdev } 72*51c0b2f7Stbbdev 73*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 74*51c0b2f7Stbbdev void test_deduction_guides(){ 75*51c0b2f7Stbbdev tbb::flow::graph g; 76*51c0b2f7Stbbdev inc_functor<int> fun; 77*51c0b2f7Stbbdev tbb::flow::continue_node node1(g, fun); 78*51c0b2f7Stbbdev } 79*51c0b2f7Stbbdev #endif 80*51c0b2f7Stbbdev 81*51c0b2f7Stbbdev void test_forwarding(){ 82*51c0b2f7Stbbdev tbb::flow::graph g; 83*51c0b2f7Stbbdev inc_functor<int> fun; 84*51c0b2f7Stbbdev fun.execute_count = 0; 85*51c0b2f7Stbbdev 86*51c0b2f7Stbbdev tbb::flow::continue_node<int> node1(g, fun); 87*51c0b2f7Stbbdev test_push_receiver<int> node2(g); 88*51c0b2f7Stbbdev test_push_receiver<int> node3(g); 89*51c0b2f7Stbbdev 90*51c0b2f7Stbbdev tbb::flow::make_edge(node1, node2); 91*51c0b2f7Stbbdev tbb::flow::make_edge(node1, node3); 92*51c0b2f7Stbbdev 93*51c0b2f7Stbbdev node1.try_put(tbb::flow::continue_msg()); 94*51c0b2f7Stbbdev g.wait_for_all(); 95*51c0b2f7Stbbdev 96*51c0b2f7Stbbdev CHECK_MESSAGE( (get_count(node2) == 1), "Descendant of the node must receive one message."); 97*51c0b2f7Stbbdev CHECK_MESSAGE( (get_count(node3) == 1), "Descendant of the node must receive one message."); 98*51c0b2f7Stbbdev } 99*51c0b2f7Stbbdev 100*51c0b2f7Stbbdev void test_buffering(){ 101*51c0b2f7Stbbdev tbb::flow::graph g; 102*51c0b2f7Stbbdev inc_functor<int> fun; 103*51c0b2f7Stbbdev 104*51c0b2f7Stbbdev tbb::flow::continue_node<int> node(g, fun); 105*51c0b2f7Stbbdev tbb::flow::limiter_node<int> rejecter(g, 0); 106*51c0b2f7Stbbdev 107*51c0b2f7Stbbdev tbb::flow::make_edge(node, rejecter); 108*51c0b2f7Stbbdev node.try_put(tbb::flow::continue_msg()); 109*51c0b2f7Stbbdev 110*51c0b2f7Stbbdev int tmp = -1; 111*51c0b2f7Stbbdev CHECK_MESSAGE( (node.try_get(tmp) == false), "try_get after rejection should not succeed"); 112*51c0b2f7Stbbdev CHECK_MESSAGE( (tmp == -1), "try_get after rejection should not alter passed value"); 113*51c0b2f7Stbbdev g.wait_for_all(); 114*51c0b2f7Stbbdev } 115*51c0b2f7Stbbdev 116*51c0b2f7Stbbdev void test_policy_ctors(){ 117*51c0b2f7Stbbdev using namespace tbb::flow; 118*51c0b2f7Stbbdev graph g; 119*51c0b2f7Stbbdev 120*51c0b2f7Stbbdev inc_functor<int> fun; 121*51c0b2f7Stbbdev 122*51c0b2f7Stbbdev continue_node<int, lightweight> lw_node(g, fun); 123*51c0b2f7Stbbdev } 124*51c0b2f7Stbbdev 125*51c0b2f7Stbbdev void test_ctors(){ 126*51c0b2f7Stbbdev using namespace tbb::flow; 127*51c0b2f7Stbbdev graph g; 128*51c0b2f7Stbbdev 129*51c0b2f7Stbbdev inc_functor<int> fun; 130*51c0b2f7Stbbdev 131*51c0b2f7Stbbdev continue_node<int> proto1(g, 2, fun, tbb::flow::node_priority_t(1)); 132*51c0b2f7Stbbdev } 133*51c0b2f7Stbbdev 134*51c0b2f7Stbbdev template<typename O> 135*51c0b2f7Stbbdev struct CopyCounterBody{ 136*51c0b2f7Stbbdev size_t copy_count; 137*51c0b2f7Stbbdev 138*51c0b2f7Stbbdev CopyCounterBody(): 139*51c0b2f7Stbbdev copy_count(0) {} 140*51c0b2f7Stbbdev 141*51c0b2f7Stbbdev CopyCounterBody(const CopyCounterBody<O>& other): 142*51c0b2f7Stbbdev copy_count(other.copy_count + 1) {} 143*51c0b2f7Stbbdev 144*51c0b2f7Stbbdev CopyCounterBody& operator=(const CopyCounterBody<O>& other){ 145*51c0b2f7Stbbdev copy_count = other.copy_count + 1; 146*51c0b2f7Stbbdev return *this; 147*51c0b2f7Stbbdev } 148*51c0b2f7Stbbdev 149*51c0b2f7Stbbdev O operator()(tbb::flow::continue_msg){ 150*51c0b2f7Stbbdev return 1; 151*51c0b2f7Stbbdev } 152*51c0b2f7Stbbdev }; 153*51c0b2f7Stbbdev 154*51c0b2f7Stbbdev void test_copies(){ 155*51c0b2f7Stbbdev using namespace tbb::flow; 156*51c0b2f7Stbbdev 157*51c0b2f7Stbbdev CopyCounterBody<int> b; 158*51c0b2f7Stbbdev 159*51c0b2f7Stbbdev graph g; 160*51c0b2f7Stbbdev continue_node<int> fn(g, b); 161*51c0b2f7Stbbdev 162*51c0b2f7Stbbdev CopyCounterBody<int> b2 = copy_body<CopyCounterBody<int>, 163*51c0b2f7Stbbdev continue_node<int>>(fn); 164*51c0b2f7Stbbdev 165*51c0b2f7Stbbdev CHECK_MESSAGE( (b.copy_count + 2 <= b2.copy_count), "copy_body and constructor should copy bodies"); 166*51c0b2f7Stbbdev } 167*51c0b2f7Stbbdev 168*51c0b2f7Stbbdev 169*51c0b2f7Stbbdev void test_priority(){ 170*51c0b2f7Stbbdev size_t concurrency_limit = 1; 171*51c0b2f7Stbbdev tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_limit); 172*51c0b2f7Stbbdev 173*51c0b2f7Stbbdev tbb::flow::graph g; 174*51c0b2f7Stbbdev 175*51c0b2f7Stbbdev tbb::flow::continue_node<tbb::flow::continue_msg> source(g, 176*51c0b2f7Stbbdev [](tbb::flow::continue_msg){ return tbb::flow::continue_msg();}); 177*51c0b2f7Stbbdev source.try_put(tbb::flow::continue_msg()); 178*51c0b2f7Stbbdev 179*51c0b2f7Stbbdev first_functor<int>::first_id = -1; 180*51c0b2f7Stbbdev first_functor<int> low_functor(1); 181*51c0b2f7Stbbdev first_functor<int> high_functor(2); 182*51c0b2f7Stbbdev 183*51c0b2f7Stbbdev tbb::flow::continue_node<int, int> high(g, high_functor, tbb::flow::node_priority_t(1)); 184*51c0b2f7Stbbdev tbb::flow::continue_node<int, int> low(g, low_functor); 185*51c0b2f7Stbbdev 186*51c0b2f7Stbbdev make_edge(source, low); 187*51c0b2f7Stbbdev make_edge(source, high); 188*51c0b2f7Stbbdev 189*51c0b2f7Stbbdev g.wait_for_all(); 190*51c0b2f7Stbbdev 191*51c0b2f7Stbbdev CHECK_MESSAGE( (first_functor<int>::first_id == 2), "High priority node should execute first"); 192*51c0b2f7Stbbdev } 193*51c0b2f7Stbbdev 194*51c0b2f7Stbbdev //! Test node costructors 195*51c0b2f7Stbbdev //! \brief \ref requirement 196*51c0b2f7Stbbdev TEST_CASE("continue_node constructors"){ 197*51c0b2f7Stbbdev test_ctors(); 198*51c0b2f7Stbbdev } 199*51c0b2f7Stbbdev 200*51c0b2f7Stbbdev //! Test priorities work in single-threaded configuration 201*51c0b2f7Stbbdev //! \brief \ref requirement 202*51c0b2f7Stbbdev TEST_CASE("continue_node priority support"){ 203*51c0b2f7Stbbdev test_priority(); 204*51c0b2f7Stbbdev } 205*51c0b2f7Stbbdev 206*51c0b2f7Stbbdev //! Test body copying and copy_body logic 207*51c0b2f7Stbbdev //! \brief \ref interface 208*51c0b2f7Stbbdev TEST_CASE("continue_node and body copying"){ 209*51c0b2f7Stbbdev test_copies(); 210*51c0b2f7Stbbdev } 211*51c0b2f7Stbbdev 212*51c0b2f7Stbbdev //! Test constructors 213*51c0b2f7Stbbdev //! \brief \ref interface 214*51c0b2f7Stbbdev TEST_CASE("continue_node constructors"){ 215*51c0b2f7Stbbdev test_policy_ctors(); 216*51c0b2f7Stbbdev } 217*51c0b2f7Stbbdev 218*51c0b2f7Stbbdev //! Test continue_node buffering 219*51c0b2f7Stbbdev //! \brief \ref requirement 220*51c0b2f7Stbbdev TEST_CASE("continue_node buffering"){ 221*51c0b2f7Stbbdev test_buffering(); 222*51c0b2f7Stbbdev } 223*51c0b2f7Stbbdev 224*51c0b2f7Stbbdev //! Test function_node broadcasting 225*51c0b2f7Stbbdev //! \brief \ref requirement 226*51c0b2f7Stbbdev TEST_CASE("continue_node broadcast"){ 227*51c0b2f7Stbbdev test_forwarding(); 228*51c0b2f7Stbbdev } 229*51c0b2f7Stbbdev 230*51c0b2f7Stbbdev //! Test deduction guides 231*51c0b2f7Stbbdev //! \brief \ref interface \ref requirement 232*51c0b2f7Stbbdev TEST_CASE("Deduction guides"){ 233*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 234*51c0b2f7Stbbdev test_deduction_guides(); 235*51c0b2f7Stbbdev #endif 236*51c0b2f7Stbbdev } 237*51c0b2f7Stbbdev 238*51c0b2f7Stbbdev //! Test inheritance relations 239*51c0b2f7Stbbdev //! \brief \ref interface 240*51c0b2f7Stbbdev TEST_CASE("continue_node superclasses"){ 241*51c0b2f7Stbbdev test_inheritance<int>(); 242*51c0b2f7Stbbdev test_inheritance<void*>(); 243*51c0b2f7Stbbdev } 244*51c0b2f7Stbbdev 245*51c0b2f7Stbbdev //! Test body execution 246*51c0b2f7Stbbdev //! \brief \ref interface \ref requirement 247*51c0b2f7Stbbdev TEST_CASE("continue body") { 248*51c0b2f7Stbbdev test_cont_body(); 249*51c0b2f7Stbbdev } 250