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