151c0b2f7Stbbdev /* 2*b15aabb3Stbbdev Copyright (c) 2005-2021 Intel Corporation 351c0b2f7Stbbdev 451c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License"); 551c0b2f7Stbbdev you may not use this file except in compliance with the License. 651c0b2f7Stbbdev You may obtain a copy of the License at 751c0b2f7Stbbdev 851c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0 951c0b2f7Stbbdev 1051c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software 1151c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS, 1251c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1351c0b2f7Stbbdev See the License for the specific language governing permissions and 1451c0b2f7Stbbdev limitations under the License. 1551c0b2f7Stbbdev */ 1651c0b2f7Stbbdev 1751c0b2f7Stbbdev 1851c0b2f7Stbbdev #include "common/config.h" 1951c0b2f7Stbbdev 2051c0b2f7Stbbdev // TODO revamp: move parts dependent on __TBB_EXTRA_DEBUG into separate test(s) since having these 2151c0b2f7Stbbdev // parts in all of tests might make testing of the product, which is different from what is actually 2251c0b2f7Stbbdev // released. 2351c0b2f7Stbbdev #define __TBB_EXTRA_DEBUG 1 2451c0b2f7Stbbdev #include "tbb/flow_graph.h" 2551c0b2f7Stbbdev 2651c0b2f7Stbbdev #include "common/test.h" 2751c0b2f7Stbbdev #include "common/utils.h" 2851c0b2f7Stbbdev #include "common/utils_assert.h" 2951c0b2f7Stbbdev #include "common/graph_utils.h" 3051c0b2f7Stbbdev #include "common/test_follows_and_precedes_api.h" 3151c0b2f7Stbbdev 3251c0b2f7Stbbdev #define N 300 3351c0b2f7Stbbdev #define T 4 3451c0b2f7Stbbdev #define M 4 3551c0b2f7Stbbdev 3651c0b2f7Stbbdev 3751c0b2f7Stbbdev //! \file test_write_once_node.cpp 3851c0b2f7Stbbdev //! \brief Test for [flow_graph.write_once_node] specification 3951c0b2f7Stbbdev 4051c0b2f7Stbbdev 4151c0b2f7Stbbdev template< typename R > 4251c0b2f7Stbbdev void simple_read_write_tests() { 4351c0b2f7Stbbdev tbb::flow::graph g; 4451c0b2f7Stbbdev tbb::flow::write_once_node<R> n(g); 4551c0b2f7Stbbdev 4651c0b2f7Stbbdev for ( int t = 0; t < T; ++t ) { 4751c0b2f7Stbbdev R v0(0); 4851c0b2f7Stbbdev std::vector< std::shared_ptr<harness_counting_receiver<R>> > r; 4951c0b2f7Stbbdev for (size_t i = 0; i < M; ++i) { 5051c0b2f7Stbbdev r.push_back( std::make_shared<harness_counting_receiver<R>>(g) ); 5151c0b2f7Stbbdev } 5251c0b2f7Stbbdev 5351c0b2f7Stbbdev 5451c0b2f7Stbbdev CHECK_MESSAGE( n.is_valid() == false, "" ); 5551c0b2f7Stbbdev CHECK_MESSAGE( n.try_get( v0 ) == false, "" ); 5651c0b2f7Stbbdev 5751c0b2f7Stbbdev if ( t % 2 ) { 5851c0b2f7Stbbdev CHECK_MESSAGE( n.try_put( static_cast<R>(N+1) ), "" ); 5951c0b2f7Stbbdev CHECK_MESSAGE( n.is_valid() == true, "" ); 6051c0b2f7Stbbdev CHECK_MESSAGE( n.try_get( v0 ) == true, "" ); 6151c0b2f7Stbbdev CHECK_MESSAGE( v0 == R(N+1), "" ); 6251c0b2f7Stbbdev } 6351c0b2f7Stbbdev 6451c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 6551c0b2f7Stbbdev tbb::flow::make_edge( n, *r[i] ); 6651c0b2f7Stbbdev } 6751c0b2f7Stbbdev 6851c0b2f7Stbbdev if ( t%2 ) { 6951c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 7051c0b2f7Stbbdev size_t c = r[i]->my_count; 7151c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" ); 7251c0b2f7Stbbdev } 7351c0b2f7Stbbdev } 7451c0b2f7Stbbdev 7551c0b2f7Stbbdev for (int i = 1; i <= N; ++i ) { 7651c0b2f7Stbbdev R v1(static_cast<R>(i)); 7751c0b2f7Stbbdev 7851c0b2f7Stbbdev bool result = n.try_put( v1 ); 7951c0b2f7Stbbdev if ( !(t%2) && i == 1 ) 8051c0b2f7Stbbdev CHECK_MESSAGE( result == true, "" ); 8151c0b2f7Stbbdev else 8251c0b2f7Stbbdev CHECK_MESSAGE( result == false, "" ); 8351c0b2f7Stbbdev 8451c0b2f7Stbbdev CHECK_MESSAGE( n.is_valid() == true, "" ); 8551c0b2f7Stbbdev 8651c0b2f7Stbbdev for (int j = 0; j < N; ++j ) { 8751c0b2f7Stbbdev R v2(0); 8851c0b2f7Stbbdev CHECK_MESSAGE( n.try_get( v2 ), "" ); 8951c0b2f7Stbbdev if ( t%2 ) 9051c0b2f7Stbbdev CHECK_MESSAGE( R(N+1) == v2, "" ); 9151c0b2f7Stbbdev else 9251c0b2f7Stbbdev CHECK_MESSAGE( R(1) == v2, "" ); 9351c0b2f7Stbbdev } 9451c0b2f7Stbbdev } 9551c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 9651c0b2f7Stbbdev size_t c = r[i]->my_count; 9751c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" ); 9851c0b2f7Stbbdev } 9951c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 10051c0b2f7Stbbdev tbb::flow::remove_edge( n, *r[i] ); 10151c0b2f7Stbbdev } 10251c0b2f7Stbbdev CHECK_MESSAGE( n.try_put( R(0) ) == false, "" ); 10351c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 10451c0b2f7Stbbdev size_t c = r[i]->my_count; 10551c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" ); 10651c0b2f7Stbbdev } 10751c0b2f7Stbbdev n.clear(); 10851c0b2f7Stbbdev CHECK_MESSAGE( n.is_valid() == false, "" ); 10951c0b2f7Stbbdev CHECK_MESSAGE( n.try_get( v0 ) == false, "" ); 11051c0b2f7Stbbdev } 11151c0b2f7Stbbdev } 11251c0b2f7Stbbdev 11351c0b2f7Stbbdev template< typename R > 11451c0b2f7Stbbdev class native_body : utils::NoAssign { 11551c0b2f7Stbbdev tbb::flow::write_once_node<R> &my_node; 11651c0b2f7Stbbdev 11751c0b2f7Stbbdev public: 11851c0b2f7Stbbdev 11951c0b2f7Stbbdev native_body( tbb::flow::write_once_node<R> &n ) : my_node(n) {} 12051c0b2f7Stbbdev 12151c0b2f7Stbbdev void operator()( int i ) const { 12251c0b2f7Stbbdev R v1(static_cast<R>(i)); 12351c0b2f7Stbbdev CHECK_MESSAGE( my_node.try_put( v1 ) == false, "" ); 12451c0b2f7Stbbdev CHECK_MESSAGE( my_node.is_valid() == true, "" ); 12551c0b2f7Stbbdev CHECK_MESSAGE( my_node.try_get( v1 ) == true, "" ); 12651c0b2f7Stbbdev CHECK_MESSAGE( v1 == R(-1), "" ); 12751c0b2f7Stbbdev } 12851c0b2f7Stbbdev }; 12951c0b2f7Stbbdev 13051c0b2f7Stbbdev template< typename R > 13151c0b2f7Stbbdev void parallel_read_write_tests() { 13251c0b2f7Stbbdev tbb::flow::graph g; 13351c0b2f7Stbbdev tbb::flow::write_once_node<R> n(g); 13451c0b2f7Stbbdev //Create a vector of identical nodes 13551c0b2f7Stbbdev std::vector< tbb::flow::write_once_node<R> > wo_vec(2, n); 13651c0b2f7Stbbdev 13751c0b2f7Stbbdev for (size_t node_idx=0; node_idx<wo_vec.size(); ++node_idx) { 13851c0b2f7Stbbdev for ( int t = 0; t < T; ++t ) { 13951c0b2f7Stbbdev std::vector< std::shared_ptr<harness_counting_receiver<R>> > r; 14051c0b2f7Stbbdev for (size_t i = 0; i < M; ++i) { 14151c0b2f7Stbbdev r.push_back( std::make_shared<harness_counting_receiver<R>>(g) ); 14251c0b2f7Stbbdev } 14351c0b2f7Stbbdev 14451c0b2f7Stbbdev 14551c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 14651c0b2f7Stbbdev tbb::flow::make_edge( wo_vec[node_idx], *r[i] ); 14751c0b2f7Stbbdev } 14851c0b2f7Stbbdev R v0; 14951c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].is_valid() == false, "" ); 15051c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].try_get( v0 ) == false, "" ); 15151c0b2f7Stbbdev 15251c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].try_put( R(-1) ), "" ); 15351c0b2f7Stbbdev #if TBB_TEST_LOW_WORKLOAD 15451c0b2f7Stbbdev const int nthreads = 30; 15551c0b2f7Stbbdev #else 15651c0b2f7Stbbdev const int nthreads = N; 15751c0b2f7Stbbdev #endif 15851c0b2f7Stbbdev utils::NativeParallelFor( nthreads, native_body<R>( wo_vec[node_idx] ) ); 15951c0b2f7Stbbdev 16051c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 16151c0b2f7Stbbdev size_t c = r[i]->my_count; 16251c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" ); 16351c0b2f7Stbbdev } 16451c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 16551c0b2f7Stbbdev tbb::flow::remove_edge( wo_vec[node_idx], *r[i] ); 16651c0b2f7Stbbdev } 16751c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].try_put( R(0) ) == false, "" ); 16851c0b2f7Stbbdev for (int i = 0; i < M; ++i) { 16951c0b2f7Stbbdev size_t c = r[i]->my_count; 17051c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" ); 17151c0b2f7Stbbdev } 17251c0b2f7Stbbdev wo_vec[node_idx].clear(); 17351c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].is_valid() == false, "" ); 17451c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].try_get( v0 ) == false, "" ); 17551c0b2f7Stbbdev } 17651c0b2f7Stbbdev } 17751c0b2f7Stbbdev } 17851c0b2f7Stbbdev 17951c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 18051c0b2f7Stbbdev #include <array> 18151c0b2f7Stbbdev #include <vector> 18251c0b2f7Stbbdev void test_follows_and_precedes_api() { 18351c0b2f7Stbbdev using msg_t = tbb::flow::continue_msg; 18451c0b2f7Stbbdev 18551c0b2f7Stbbdev std::array<msg_t, 3> messages_for_follows= {msg_t(), msg_t(), msg_t()}; 18651c0b2f7Stbbdev std::vector<msg_t> messages_for_precedes = {msg_t()}; 18751c0b2f7Stbbdev 18851c0b2f7Stbbdev follows_and_precedes_testing::test_follows<msg_t, tbb::flow::write_once_node<msg_t>>(messages_for_follows); 18951c0b2f7Stbbdev follows_and_precedes_testing::test_precedes<msg_t, tbb::flow::write_once_node<msg_t>>(messages_for_precedes); 19051c0b2f7Stbbdev } 19151c0b2f7Stbbdev #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 19251c0b2f7Stbbdev 19351c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 19451c0b2f7Stbbdev void test_deduction_guides() { 19551c0b2f7Stbbdev using namespace tbb::flow; 19651c0b2f7Stbbdev 19751c0b2f7Stbbdev graph g; 19851c0b2f7Stbbdev broadcast_node<int> b1(g); 19951c0b2f7Stbbdev write_once_node<int> wo0(g); 20051c0b2f7Stbbdev 20151c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 20251c0b2f7Stbbdev write_once_node wo1(follows(b1)); 20351c0b2f7Stbbdev static_assert(std::is_same_v<decltype(wo1), write_once_node<int>>); 20451c0b2f7Stbbdev 20551c0b2f7Stbbdev write_once_node wo2(precedes(b1)); 20651c0b2f7Stbbdev static_assert(std::is_same_v<decltype(wo2), write_once_node<int>>); 20751c0b2f7Stbbdev #endif 20851c0b2f7Stbbdev 20951c0b2f7Stbbdev write_once_node wo3(wo0); 21051c0b2f7Stbbdev static_assert(std::is_same_v<decltype(wo3), write_once_node<int>>); 21151c0b2f7Stbbdev } 21251c0b2f7Stbbdev #endif 21351c0b2f7Stbbdev 21451c0b2f7Stbbdev //! Test read-write properties 21551c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing 21651c0b2f7Stbbdev TEST_CASE("Read-write tests"){ 21751c0b2f7Stbbdev simple_read_write_tests<int>(); 21851c0b2f7Stbbdev simple_read_write_tests<float>(); 21951c0b2f7Stbbdev } 22051c0b2f7Stbbdev 22151c0b2f7Stbbdev //! Test read-write properties under parallelism 22251c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing \ref stress 22351c0b2f7Stbbdev TEST_CASE("Parallel read-write tests"){ 22451c0b2f7Stbbdev for( unsigned int p=utils::MinThread; p<=utils::MaxThread; ++p ) { 22551c0b2f7Stbbdev tbb::task_arena arena(p); 22651c0b2f7Stbbdev arena.execute( 22751c0b2f7Stbbdev [&]() { 22851c0b2f7Stbbdev parallel_read_write_tests<int>(); 22951c0b2f7Stbbdev parallel_read_write_tests<float>(); 23051c0b2f7Stbbdev test_reserving_nodes<tbb::flow::write_once_node, size_t>(); 23151c0b2f7Stbbdev } 23251c0b2f7Stbbdev ); 23351c0b2f7Stbbdev } 23451c0b2f7Stbbdev } 23551c0b2f7Stbbdev 23651c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 23751c0b2f7Stbbdev //! Test deprecated follows and precedes API 23851c0b2f7Stbbdev //! \brief \ref error_guessing 23951c0b2f7Stbbdev TEST_CASE("Test follows and precedes API"){ 24051c0b2f7Stbbdev test_follows_and_precedes_api(); 24151c0b2f7Stbbdev } 24251c0b2f7Stbbdev #endif 24351c0b2f7Stbbdev 24451c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 24551c0b2f7Stbbdev //! Test deduction guides 24651c0b2f7Stbbdev //! \brief \ref requirement 24751c0b2f7Stbbdev TEST_CASE("Deduction guides"){ 24851c0b2f7Stbbdev test_deduction_guides(); 24951c0b2f7Stbbdev } 25051c0b2f7Stbbdev #endif 251