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 18*51c0b2f7Stbbdev #include "common/test.h" 19*51c0b2f7Stbbdev 20*51c0b2f7Stbbdev #include "common/utils.h" 21*51c0b2f7Stbbdev #include "common/graph_utils.h" 22*51c0b2f7Stbbdev 23*51c0b2f7Stbbdev #include "tbb/flow_graph.h" 24*51c0b2f7Stbbdev #include "tbb/task_arena.h" 25*51c0b2f7Stbbdev 26*51c0b2f7Stbbdev #include "conformance_flowgraph.h" 27*51c0b2f7Stbbdev 28*51c0b2f7Stbbdev //! \file conformance_input_node.cpp 29*51c0b2f7Stbbdev //! \brief Test for [flow_graph.input_node] specification 30*51c0b2f7Stbbdev 31*51c0b2f7Stbbdev /* 32*51c0b2f7Stbbdev TODO: implement missing conformance tests for input_node: 33*51c0b2f7Stbbdev - [ ] The `copy_body' function copies altered body (e.g. after its successful invocation). 34*51c0b2f7Stbbdev - [ ] Check that in `test_forwarding' the value passed is the actual one received. 35*51c0b2f7Stbbdev - [ ] Improve CTAD test to assert result node type. 36*51c0b2f7Stbbdev - [ ] Explicit test for copy constructor of the node. 37*51c0b2f7Stbbdev - [ ] Check `Output' type indeed copy-constructed and copy-assigned while working with the node. 38*51c0b2f7Stbbdev - [ ] Check node cannot have predecessors (Will ADL be of any help here?) 39*51c0b2f7Stbbdev - [ ] Check the node is serial and its body never invoked concurrently. 40*51c0b2f7Stbbdev - [ ] `try_get()' call testing: a call to body is made only when the internal buffer is empty. 41*51c0b2f7Stbbdev */ 42*51c0b2f7Stbbdev 43*51c0b2f7Stbbdev std::atomic<size_t> global_execute_count; 44*51c0b2f7Stbbdev 45*51c0b2f7Stbbdev template<typename OutputType> 46*51c0b2f7Stbbdev struct input_functor { 47*51c0b2f7Stbbdev const size_t n; 48*51c0b2f7Stbbdev 49*51c0b2f7Stbbdev input_functor( ) : n(10) { } 50*51c0b2f7Stbbdev input_functor( const input_functor &f ) : n(f.n) { } 51*51c0b2f7Stbbdev void operator=(const input_functor &f) { n = f.n; } 52*51c0b2f7Stbbdev 53*51c0b2f7Stbbdev OutputType operator()( tbb::flow_control & fc ) { 54*51c0b2f7Stbbdev ++global_execute_count; 55*51c0b2f7Stbbdev if(global_execute_count > n){ 56*51c0b2f7Stbbdev fc.stop(); 57*51c0b2f7Stbbdev return OutputType(); 58*51c0b2f7Stbbdev } 59*51c0b2f7Stbbdev return OutputType(global_execute_count.load()); 60*51c0b2f7Stbbdev } 61*51c0b2f7Stbbdev 62*51c0b2f7Stbbdev }; 63*51c0b2f7Stbbdev 64*51c0b2f7Stbbdev template<typename O> 65*51c0b2f7Stbbdev struct CopyCounterBody{ 66*51c0b2f7Stbbdev size_t copy_count; 67*51c0b2f7Stbbdev 68*51c0b2f7Stbbdev CopyCounterBody(): 69*51c0b2f7Stbbdev copy_count(0) {} 70*51c0b2f7Stbbdev 71*51c0b2f7Stbbdev CopyCounterBody(const CopyCounterBody<O>& other): 72*51c0b2f7Stbbdev copy_count(other.copy_count + 1) {} 73*51c0b2f7Stbbdev 74*51c0b2f7Stbbdev CopyCounterBody& operator=(const CopyCounterBody<O>& other) { 75*51c0b2f7Stbbdev copy_count = other.copy_count + 1; return *this; 76*51c0b2f7Stbbdev } 77*51c0b2f7Stbbdev 78*51c0b2f7Stbbdev O operator()(tbb::flow_control & fc){ 79*51c0b2f7Stbbdev fc.stop(); 80*51c0b2f7Stbbdev return O(); 81*51c0b2f7Stbbdev } 82*51c0b2f7Stbbdev }; 83*51c0b2f7Stbbdev 84*51c0b2f7Stbbdev 85*51c0b2f7Stbbdev void test_input_body(){ 86*51c0b2f7Stbbdev tbb::flow::graph g; 87*51c0b2f7Stbbdev input_functor<int> fun; 88*51c0b2f7Stbbdev 89*51c0b2f7Stbbdev global_execute_count = 0; 90*51c0b2f7Stbbdev tbb::flow::input_node<int> node1(g, fun); 91*51c0b2f7Stbbdev test_push_receiver<int> node2(g); 92*51c0b2f7Stbbdev 93*51c0b2f7Stbbdev tbb::flow::make_edge(node1, node2); 94*51c0b2f7Stbbdev 95*51c0b2f7Stbbdev node1.activate(); 96*51c0b2f7Stbbdev g.wait_for_all(); 97*51c0b2f7Stbbdev 98*51c0b2f7Stbbdev CHECK_MESSAGE( (get_count(node2) == 10), "Descendant of the node needs to be receive N messages"); 99*51c0b2f7Stbbdev CHECK_MESSAGE( (global_execute_count == 10 + 1), "Body of the node needs to be executed N + 1 times"); 100*51c0b2f7Stbbdev } 101*51c0b2f7Stbbdev 102*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 103*51c0b2f7Stbbdev void test_deduction_guides(){ 104*51c0b2f7Stbbdev tbb::flow::graph g; 105*51c0b2f7Stbbdev input_functor<int> fun; 106*51c0b2f7Stbbdev tbb::flow::input_node node1(g, fun); 107*51c0b2f7Stbbdev } 108*51c0b2f7Stbbdev #endif 109*51c0b2f7Stbbdev 110*51c0b2f7Stbbdev void test_buffering(){ 111*51c0b2f7Stbbdev tbb::flow::graph g; 112*51c0b2f7Stbbdev input_functor<int> fun; 113*51c0b2f7Stbbdev global_execute_count = 0; 114*51c0b2f7Stbbdev 115*51c0b2f7Stbbdev tbb::flow::input_node<int> source(g, fun); 116*51c0b2f7Stbbdev tbb::flow::limiter_node<int> rejecter(g, 0); 117*51c0b2f7Stbbdev 118*51c0b2f7Stbbdev tbb::flow::make_edge(source, rejecter); 119*51c0b2f7Stbbdev source.activate(); 120*51c0b2f7Stbbdev g.wait_for_all(); 121*51c0b2f7Stbbdev 122*51c0b2f7Stbbdev int tmp = -1; 123*51c0b2f7Stbbdev CHECK_MESSAGE( (source.try_get(tmp) == true), "try_get after rejection should succeed"); 124*51c0b2f7Stbbdev CHECK_MESSAGE( (tmp == 1), "try_get should return correct value"); 125*51c0b2f7Stbbdev } 126*51c0b2f7Stbbdev 127*51c0b2f7Stbbdev void test_forwarding(){ 128*51c0b2f7Stbbdev tbb::flow::graph g; 129*51c0b2f7Stbbdev input_functor<int> fun; 130*51c0b2f7Stbbdev 131*51c0b2f7Stbbdev global_execute_count = 0; 132*51c0b2f7Stbbdev tbb::flow::input_node<int> node1(g, fun); 133*51c0b2f7Stbbdev test_push_receiver<int> node2(g); 134*51c0b2f7Stbbdev test_push_receiver<int> node3(g); 135*51c0b2f7Stbbdev 136*51c0b2f7Stbbdev tbb::flow::make_edge(node1, node2); 137*51c0b2f7Stbbdev tbb::flow::make_edge(node1, node3); 138*51c0b2f7Stbbdev 139*51c0b2f7Stbbdev node1.activate(); 140*51c0b2f7Stbbdev g.wait_for_all(); 141*51c0b2f7Stbbdev 142*51c0b2f7Stbbdev CHECK_MESSAGE( (get_count(node2) == 10), "Descendant of the node needs to be receive N messages"); 143*51c0b2f7Stbbdev CHECK_MESSAGE( (get_count(node3) == 10), "Descendant of the node needs to be receive N messages"); 144*51c0b2f7Stbbdev } 145*51c0b2f7Stbbdev 146*51c0b2f7Stbbdev template<typename O> 147*51c0b2f7Stbbdev void test_inheritance(){ 148*51c0b2f7Stbbdev using namespace tbb::flow; 149*51c0b2f7Stbbdev 150*51c0b2f7Stbbdev CHECK_MESSAGE( (std::is_base_of<graph_node, input_node<O>>::value), "input_node should be derived from graph_node"); 151*51c0b2f7Stbbdev CHECK_MESSAGE( (std::is_base_of<sender<O>, input_node<O>>::value), "input_node should be derived from sender<Output>"); 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 input_node<int> fn(g, b); 161*51c0b2f7Stbbdev 162*51c0b2f7Stbbdev CopyCounterBody<int> b2 = copy_body<CopyCounterBody<int>, input_node<int>>(fn); 163*51c0b2f7Stbbdev 164*51c0b2f7Stbbdev CHECK_MESSAGE( (b.copy_count + 2 <= b2.copy_count), "copy_body and constructor should copy bodies"); 165*51c0b2f7Stbbdev } 166*51c0b2f7Stbbdev 167*51c0b2f7Stbbdev //! Test body copying and copy_body logic 168*51c0b2f7Stbbdev //! \brief \ref interface 169*51c0b2f7Stbbdev TEST_CASE("input_node and body copying"){ 170*51c0b2f7Stbbdev test_copies(); 171*51c0b2f7Stbbdev } 172*51c0b2f7Stbbdev 173*51c0b2f7Stbbdev //! Test inheritance relations 174*51c0b2f7Stbbdev //! \brief \ref interface 175*51c0b2f7Stbbdev TEST_CASE("input_node superclasses"){ 176*51c0b2f7Stbbdev test_inheritance<int>(); 177*51c0b2f7Stbbdev test_inheritance<void*>(); 178*51c0b2f7Stbbdev } 179*51c0b2f7Stbbdev 180*51c0b2f7Stbbdev //! Test input_node forwarding 181*51c0b2f7Stbbdev //! \brief \ref requirement 182*51c0b2f7Stbbdev TEST_CASE("input_node forwarding"){ 183*51c0b2f7Stbbdev test_forwarding(); 184*51c0b2f7Stbbdev } 185*51c0b2f7Stbbdev 186*51c0b2f7Stbbdev //! Test input_node buffering 187*51c0b2f7Stbbdev //! \brief \ref requirement 188*51c0b2f7Stbbdev TEST_CASE("input_node buffering"){ 189*51c0b2f7Stbbdev test_buffering(); 190*51c0b2f7Stbbdev } 191*51c0b2f7Stbbdev 192*51c0b2f7Stbbdev //! Test calling input_node body 193*51c0b2f7Stbbdev //! \brief \ref interface \ref requirement 194*51c0b2f7Stbbdev TEST_CASE("input_node body") { 195*51c0b2f7Stbbdev test_input_body(); 196*51c0b2f7Stbbdev } 197*51c0b2f7Stbbdev 198*51c0b2f7Stbbdev //! Test deduction guides 199*51c0b2f7Stbbdev //! \brief \ref interface \ref requirement 200*51c0b2f7Stbbdev TEST_CASE("Deduction guides"){ 201*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 202*51c0b2f7Stbbdev test_deduction_guides(); 203*51c0b2f7Stbbdev #endif 204*51c0b2f7Stbbdev } 205