1*51c0b2f7Stbbdev /* 2*51c0b2f7Stbbdev Copyright (c) 2005-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/config.h" 19*51c0b2f7Stbbdev 20*51c0b2f7Stbbdev // TODO revamp: move parts dependent on __TBB_EXTRA_DEBUG into separate test(s) since having these 21*51c0b2f7Stbbdev // parts in all of tests might make testing of the product, which is different from what is actually 22*51c0b2f7Stbbdev // released. 23*51c0b2f7Stbbdev #define __TBB_EXTRA_DEBUG 1 24*51c0b2f7Stbbdev #include "tbb/flow_graph.h" 25*51c0b2f7Stbbdev 26*51c0b2f7Stbbdev #include "common/test.h" 27*51c0b2f7Stbbdev #include "common/utils.h" 28*51c0b2f7Stbbdev #include "common/utils_assert.h" 29*51c0b2f7Stbbdev #include "common/graph_utils.h" 30*51c0b2f7Stbbdev #include "common/test_follows_and_precedes_api.h" 31*51c0b2f7Stbbdev 32*51c0b2f7Stbbdev #define N 300 33*51c0b2f7Stbbdev #define T 4 34*51c0b2f7Stbbdev #define M 4 35*51c0b2f7Stbbdev 36*51c0b2f7Stbbdev 37*51c0b2f7Stbbdev //! \file test_write_once_node.cpp 38*51c0b2f7Stbbdev //! \brief Test for [flow_graph.write_once_node] specification 39*51c0b2f7Stbbdev 40*51c0b2f7Stbbdev 41*51c0b2f7Stbbdev template< typename R > 42*51c0b2f7Stbbdev void simple_read_write_tests() { 43*51c0b2f7Stbbdev tbb::flow::graph g; 44*51c0b2f7Stbbdev tbb::flow::write_once_node<R> n(g); 45*51c0b2f7Stbbdev 46*51c0b2f7Stbbdev for ( int t = 0; t < T; ++t ) { 47*51c0b2f7Stbbdev R v0(0); 48*51c0b2f7Stbbdev std::vector< std::shared_ptr<harness_counting_receiver<R>> > r; 49*51c0b2f7Stbbdev for (size_t i = 0; i < M; ++i) { 50*51c0b2f7Stbbdev r.push_back( std::make_shared<harness_counting_receiver<R>>(g) ); 51*51c0b2f7Stbbdev } 52*51c0b2f7Stbbdev 53*51c0b2f7Stbbdev 54*51c0b2f7Stbbdev CHECK_MESSAGE( n.is_valid() == false, "" ); 55*51c0b2f7Stbbdev CHECK_MESSAGE( n.try_get( v0 ) == false, "" ); 56*51c0b2f7Stbbdev 57*51c0b2f7Stbbdev if ( t % 2 ) { 58*51c0b2f7Stbbdev CHECK_MESSAGE( n.try_put( static_cast<R>(N+1) ), "" ); 59*51c0b2f7Stbbdev CHECK_MESSAGE( n.is_valid() == true, "" ); 60*51c0b2f7Stbbdev CHECK_MESSAGE( n.try_get( v0 ) == true, "" ); 61*51c0b2f7Stbbdev CHECK_MESSAGE( v0 == R(N+1), "" ); 62*51c0b2f7Stbbdev } 63*51c0b2f7Stbbdev 64*51c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 65*51c0b2f7Stbbdev tbb::flow::make_edge( n, *r[i] ); 66*51c0b2f7Stbbdev } 67*51c0b2f7Stbbdev 68*51c0b2f7Stbbdev if ( t%2 ) { 69*51c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 70*51c0b2f7Stbbdev size_t c = r[i]->my_count; 71*51c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" ); 72*51c0b2f7Stbbdev } 73*51c0b2f7Stbbdev } 74*51c0b2f7Stbbdev 75*51c0b2f7Stbbdev for (int i = 1; i <= N; ++i ) { 76*51c0b2f7Stbbdev R v1(static_cast<R>(i)); 77*51c0b2f7Stbbdev 78*51c0b2f7Stbbdev bool result = n.try_put( v1 ); 79*51c0b2f7Stbbdev if ( !(t%2) && i == 1 ) 80*51c0b2f7Stbbdev CHECK_MESSAGE( result == true, "" ); 81*51c0b2f7Stbbdev else 82*51c0b2f7Stbbdev CHECK_MESSAGE( result == false, "" ); 83*51c0b2f7Stbbdev 84*51c0b2f7Stbbdev CHECK_MESSAGE( n.is_valid() == true, "" ); 85*51c0b2f7Stbbdev 86*51c0b2f7Stbbdev for (int j = 0; j < N; ++j ) { 87*51c0b2f7Stbbdev R v2(0); 88*51c0b2f7Stbbdev CHECK_MESSAGE( n.try_get( v2 ), "" ); 89*51c0b2f7Stbbdev if ( t%2 ) 90*51c0b2f7Stbbdev CHECK_MESSAGE( R(N+1) == v2, "" ); 91*51c0b2f7Stbbdev else 92*51c0b2f7Stbbdev CHECK_MESSAGE( R(1) == v2, "" ); 93*51c0b2f7Stbbdev } 94*51c0b2f7Stbbdev } 95*51c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 96*51c0b2f7Stbbdev size_t c = r[i]->my_count; 97*51c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" ); 98*51c0b2f7Stbbdev } 99*51c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 100*51c0b2f7Stbbdev tbb::flow::remove_edge( n, *r[i] ); 101*51c0b2f7Stbbdev } 102*51c0b2f7Stbbdev CHECK_MESSAGE( n.try_put( R(0) ) == false, "" ); 103*51c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 104*51c0b2f7Stbbdev size_t c = r[i]->my_count; 105*51c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" ); 106*51c0b2f7Stbbdev } 107*51c0b2f7Stbbdev n.clear(); 108*51c0b2f7Stbbdev CHECK_MESSAGE( n.is_valid() == false, "" ); 109*51c0b2f7Stbbdev CHECK_MESSAGE( n.try_get( v0 ) == false, "" ); 110*51c0b2f7Stbbdev } 111*51c0b2f7Stbbdev } 112*51c0b2f7Stbbdev 113*51c0b2f7Stbbdev template< typename R > 114*51c0b2f7Stbbdev class native_body : utils::NoAssign { 115*51c0b2f7Stbbdev tbb::flow::write_once_node<R> &my_node; 116*51c0b2f7Stbbdev 117*51c0b2f7Stbbdev public: 118*51c0b2f7Stbbdev 119*51c0b2f7Stbbdev native_body( tbb::flow::write_once_node<R> &n ) : my_node(n) {} 120*51c0b2f7Stbbdev 121*51c0b2f7Stbbdev void operator()( int i ) const { 122*51c0b2f7Stbbdev R v1(static_cast<R>(i)); 123*51c0b2f7Stbbdev CHECK_MESSAGE( my_node.try_put( v1 ) == false, "" ); 124*51c0b2f7Stbbdev CHECK_MESSAGE( my_node.is_valid() == true, "" ); 125*51c0b2f7Stbbdev CHECK_MESSAGE( my_node.try_get( v1 ) == true, "" ); 126*51c0b2f7Stbbdev CHECK_MESSAGE( v1 == R(-1), "" ); 127*51c0b2f7Stbbdev } 128*51c0b2f7Stbbdev }; 129*51c0b2f7Stbbdev 130*51c0b2f7Stbbdev template< typename R > 131*51c0b2f7Stbbdev void parallel_read_write_tests() { 132*51c0b2f7Stbbdev tbb::flow::graph g; 133*51c0b2f7Stbbdev tbb::flow::write_once_node<R> n(g); 134*51c0b2f7Stbbdev //Create a vector of identical nodes 135*51c0b2f7Stbbdev std::vector< tbb::flow::write_once_node<R> > wo_vec(2, n); 136*51c0b2f7Stbbdev 137*51c0b2f7Stbbdev for (size_t node_idx=0; node_idx<wo_vec.size(); ++node_idx) { 138*51c0b2f7Stbbdev for ( int t = 0; t < T; ++t ) { 139*51c0b2f7Stbbdev std::vector< std::shared_ptr<harness_counting_receiver<R>> > r; 140*51c0b2f7Stbbdev for (size_t i = 0; i < M; ++i) { 141*51c0b2f7Stbbdev r.push_back( std::make_shared<harness_counting_receiver<R>>(g) ); 142*51c0b2f7Stbbdev } 143*51c0b2f7Stbbdev 144*51c0b2f7Stbbdev 145*51c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 146*51c0b2f7Stbbdev tbb::flow::make_edge( wo_vec[node_idx], *r[i] ); 147*51c0b2f7Stbbdev } 148*51c0b2f7Stbbdev R v0; 149*51c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].is_valid() == false, "" ); 150*51c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].try_get( v0 ) == false, "" ); 151*51c0b2f7Stbbdev 152*51c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].try_put( R(-1) ), "" ); 153*51c0b2f7Stbbdev #if TBB_TEST_LOW_WORKLOAD 154*51c0b2f7Stbbdev const int nthreads = 30; 155*51c0b2f7Stbbdev #else 156*51c0b2f7Stbbdev const int nthreads = N; 157*51c0b2f7Stbbdev #endif 158*51c0b2f7Stbbdev utils::NativeParallelFor( nthreads, native_body<R>( wo_vec[node_idx] ) ); 159*51c0b2f7Stbbdev 160*51c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 161*51c0b2f7Stbbdev size_t c = r[i]->my_count; 162*51c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" ); 163*51c0b2f7Stbbdev } 164*51c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 165*51c0b2f7Stbbdev tbb::flow::remove_edge( wo_vec[node_idx], *r[i] ); 166*51c0b2f7Stbbdev } 167*51c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].try_put( R(0) ) == false, "" ); 168*51c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 169*51c0b2f7Stbbdev size_t c = r[i]->my_count; 170*51c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" ); 171*51c0b2f7Stbbdev } 172*51c0b2f7Stbbdev wo_vec[node_idx].clear(); 173*51c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].is_valid() == false, "" ); 174*51c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].try_get( v0 ) == false, "" ); 175*51c0b2f7Stbbdev } 176*51c0b2f7Stbbdev } 177*51c0b2f7Stbbdev } 178*51c0b2f7Stbbdev 179*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 180*51c0b2f7Stbbdev #include <array> 181*51c0b2f7Stbbdev #include <vector> 182*51c0b2f7Stbbdev void test_follows_and_precedes_api() { 183*51c0b2f7Stbbdev using msg_t = tbb::flow::continue_msg; 184*51c0b2f7Stbbdev 185*51c0b2f7Stbbdev std::array<msg_t, 3> messages_for_follows= {msg_t(), msg_t(), msg_t()}; 186*51c0b2f7Stbbdev std::vector<msg_t> messages_for_precedes = {msg_t()}; 187*51c0b2f7Stbbdev 188*51c0b2f7Stbbdev follows_and_precedes_testing::test_follows<msg_t, tbb::flow::write_once_node<msg_t>>(messages_for_follows); 189*51c0b2f7Stbbdev follows_and_precedes_testing::test_precedes<msg_t, tbb::flow::write_once_node<msg_t>>(messages_for_precedes); 190*51c0b2f7Stbbdev } 191*51c0b2f7Stbbdev #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 192*51c0b2f7Stbbdev 193*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 194*51c0b2f7Stbbdev void test_deduction_guides() { 195*51c0b2f7Stbbdev using namespace tbb::flow; 196*51c0b2f7Stbbdev 197*51c0b2f7Stbbdev graph g; 198*51c0b2f7Stbbdev broadcast_node<int> b1(g); 199*51c0b2f7Stbbdev write_once_node<int> wo0(g); 200*51c0b2f7Stbbdev 201*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 202*51c0b2f7Stbbdev write_once_node wo1(follows(b1)); 203*51c0b2f7Stbbdev static_assert(std::is_same_v<decltype(wo1), write_once_node<int>>); 204*51c0b2f7Stbbdev 205*51c0b2f7Stbbdev write_once_node wo2(precedes(b1)); 206*51c0b2f7Stbbdev static_assert(std::is_same_v<decltype(wo2), write_once_node<int>>); 207*51c0b2f7Stbbdev #endif 208*51c0b2f7Stbbdev 209*51c0b2f7Stbbdev write_once_node wo3(wo0); 210*51c0b2f7Stbbdev static_assert(std::is_same_v<decltype(wo3), write_once_node<int>>); 211*51c0b2f7Stbbdev } 212*51c0b2f7Stbbdev #endif 213*51c0b2f7Stbbdev 214*51c0b2f7Stbbdev //! Test read-write properties 215*51c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing 216*51c0b2f7Stbbdev TEST_CASE("Read-write tests"){ 217*51c0b2f7Stbbdev simple_read_write_tests<int>(); 218*51c0b2f7Stbbdev simple_read_write_tests<float>(); 219*51c0b2f7Stbbdev } 220*51c0b2f7Stbbdev 221*51c0b2f7Stbbdev //! Test read-write properties under parallelism 222*51c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing \ref stress 223*51c0b2f7Stbbdev TEST_CASE("Parallel read-write tests"){ 224*51c0b2f7Stbbdev for( unsigned int p=utils::MinThread; p<=utils::MaxThread; ++p ) { 225*51c0b2f7Stbbdev tbb::task_arena arena(p); 226*51c0b2f7Stbbdev arena.execute( 227*51c0b2f7Stbbdev [&]() { 228*51c0b2f7Stbbdev parallel_read_write_tests<int>(); 229*51c0b2f7Stbbdev parallel_read_write_tests<float>(); 230*51c0b2f7Stbbdev test_reserving_nodes<tbb::flow::write_once_node, size_t>(); 231*51c0b2f7Stbbdev } 232*51c0b2f7Stbbdev ); 233*51c0b2f7Stbbdev } 234*51c0b2f7Stbbdev } 235*51c0b2f7Stbbdev 236*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 237*51c0b2f7Stbbdev //! Test deprecated follows and precedes API 238*51c0b2f7Stbbdev //! \brief \ref error_guessing 239*51c0b2f7Stbbdev TEST_CASE("Test follows and precedes API"){ 240*51c0b2f7Stbbdev test_follows_and_precedes_api(); 241*51c0b2f7Stbbdev } 242*51c0b2f7Stbbdev #endif 243*51c0b2f7Stbbdev 244*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 245*51c0b2f7Stbbdev //! Test deduction guides 246*51c0b2f7Stbbdev //! \brief \ref requirement 247*51c0b2f7Stbbdev TEST_CASE("Deduction guides"){ 248*51c0b2f7Stbbdev test_deduction_guides(); 249*51c0b2f7Stbbdev } 250*51c0b2f7Stbbdev #endif 251