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 #include "tbb/flow_graph.h"
2151c0b2f7Stbbdev
2251c0b2f7Stbbdev #include "common/test.h"
2351c0b2f7Stbbdev #include "common/utils.h"
2451c0b2f7Stbbdev #include "common/utils_assert.h"
2551c0b2f7Stbbdev #include "common/graph_utils.h"
2651c0b2f7Stbbdev #include "common/test_follows_and_precedes_api.h"
2751c0b2f7Stbbdev
2851c0b2f7Stbbdev #define N 300
2951c0b2f7Stbbdev #define T 4
3051c0b2f7Stbbdev #define M 4
3151c0b2f7Stbbdev
3251c0b2f7Stbbdev
3351c0b2f7Stbbdev //! \file test_write_once_node.cpp
3451c0b2f7Stbbdev //! \brief Test for [flow_graph.write_once_node] specification
3551c0b2f7Stbbdev
3651c0b2f7Stbbdev
3751c0b2f7Stbbdev template< typename R >
simple_read_write_tests()3851c0b2f7Stbbdev void simple_read_write_tests() {
3951c0b2f7Stbbdev tbb::flow::graph g;
4051c0b2f7Stbbdev tbb::flow::write_once_node<R> n(g);
4151c0b2f7Stbbdev
4251c0b2f7Stbbdev for ( int t = 0; t < T; ++t ) {
4351c0b2f7Stbbdev R v0(0);
4451c0b2f7Stbbdev std::vector< std::shared_ptr<harness_counting_receiver<R>> > r;
4551c0b2f7Stbbdev for (size_t i = 0; i < M; ++i) {
4651c0b2f7Stbbdev r.push_back( std::make_shared<harness_counting_receiver<R>>(g) );
4751c0b2f7Stbbdev }
4851c0b2f7Stbbdev
4951c0b2f7Stbbdev
5051c0b2f7Stbbdev CHECK_MESSAGE( n.is_valid() == false, "" );
5151c0b2f7Stbbdev CHECK_MESSAGE( n.try_get( v0 ) == false, "" );
5251c0b2f7Stbbdev
5351c0b2f7Stbbdev if ( t % 2 ) {
5451c0b2f7Stbbdev CHECK_MESSAGE( n.try_put( static_cast<R>(N+1) ), "" );
5551c0b2f7Stbbdev CHECK_MESSAGE( n.is_valid() == true, "" );
5651c0b2f7Stbbdev CHECK_MESSAGE( n.try_get( v0 ) == true, "" );
5751c0b2f7Stbbdev CHECK_MESSAGE( v0 == R(N+1), "" );
5851c0b2f7Stbbdev }
5951c0b2f7Stbbdev
6051c0b2f7Stbbdev for (int i = 0; i < M; ++i) {
6151c0b2f7Stbbdev tbb::flow::make_edge( n, *r[i] );
6251c0b2f7Stbbdev }
6351c0b2f7Stbbdev
6451c0b2f7Stbbdev if ( t%2 ) {
6551c0b2f7Stbbdev for (int i = 0; i < M; ++i) {
6651c0b2f7Stbbdev size_t c = r[i]->my_count;
6751c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" );
6851c0b2f7Stbbdev }
6951c0b2f7Stbbdev }
7051c0b2f7Stbbdev
7151c0b2f7Stbbdev for (int i = 1; i <= N; ++i ) {
7251c0b2f7Stbbdev R v1(static_cast<R>(i));
7351c0b2f7Stbbdev
7451c0b2f7Stbbdev bool result = n.try_put( v1 );
7551c0b2f7Stbbdev if ( !(t%2) && i == 1 )
7651c0b2f7Stbbdev CHECK_MESSAGE( result == true, "" );
7751c0b2f7Stbbdev else
7851c0b2f7Stbbdev CHECK_MESSAGE( result == false, "" );
7951c0b2f7Stbbdev
8051c0b2f7Stbbdev CHECK_MESSAGE( n.is_valid() == true, "" );
8151c0b2f7Stbbdev
8251c0b2f7Stbbdev for (int j = 0; j < N; ++j ) {
8351c0b2f7Stbbdev R v2(0);
8451c0b2f7Stbbdev CHECK_MESSAGE( n.try_get( v2 ), "" );
8551c0b2f7Stbbdev if ( t%2 )
8651c0b2f7Stbbdev CHECK_MESSAGE( R(N+1) == v2, "" );
8751c0b2f7Stbbdev else
8851c0b2f7Stbbdev CHECK_MESSAGE( R(1) == v2, "" );
8951c0b2f7Stbbdev }
9051c0b2f7Stbbdev }
9151c0b2f7Stbbdev for (int i = 0; i < M; ++i) {
9251c0b2f7Stbbdev size_t c = r[i]->my_count;
9351c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" );
9451c0b2f7Stbbdev }
9551c0b2f7Stbbdev for (int i = 0; i < M; ++i) {
9651c0b2f7Stbbdev tbb::flow::remove_edge( n, *r[i] );
9751c0b2f7Stbbdev }
9851c0b2f7Stbbdev CHECK_MESSAGE( n.try_put( R(0) ) == false, "" );
9951c0b2f7Stbbdev for (int i = 0; i < M; ++i) {
10051c0b2f7Stbbdev size_t c = r[i]->my_count;
10151c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" );
10251c0b2f7Stbbdev }
10351c0b2f7Stbbdev n.clear();
10451c0b2f7Stbbdev CHECK_MESSAGE( n.is_valid() == false, "" );
10551c0b2f7Stbbdev CHECK_MESSAGE( n.try_get( v0 ) == false, "" );
10651c0b2f7Stbbdev }
10751c0b2f7Stbbdev }
10851c0b2f7Stbbdev
10951c0b2f7Stbbdev template< typename R >
11051c0b2f7Stbbdev class native_body : utils::NoAssign {
11151c0b2f7Stbbdev tbb::flow::write_once_node<R> &my_node;
11251c0b2f7Stbbdev
11351c0b2f7Stbbdev public:
11451c0b2f7Stbbdev
native_body(tbb::flow::write_once_node<R> & n)11551c0b2f7Stbbdev native_body( tbb::flow::write_once_node<R> &n ) : my_node(n) {}
11651c0b2f7Stbbdev
operator ()(int i) const11751c0b2f7Stbbdev void operator()( int i ) const {
11851c0b2f7Stbbdev R v1(static_cast<R>(i));
11951c0b2f7Stbbdev CHECK_MESSAGE( my_node.try_put( v1 ) == false, "" );
12051c0b2f7Stbbdev CHECK_MESSAGE( my_node.is_valid() == true, "" );
12151c0b2f7Stbbdev CHECK_MESSAGE( my_node.try_get( v1 ) == true, "" );
12251c0b2f7Stbbdev CHECK_MESSAGE( v1 == R(-1), "" );
12351c0b2f7Stbbdev }
12451c0b2f7Stbbdev };
12551c0b2f7Stbbdev
12651c0b2f7Stbbdev template< typename R >
parallel_read_write_tests()12751c0b2f7Stbbdev void parallel_read_write_tests() {
12851c0b2f7Stbbdev tbb::flow::graph g;
12951c0b2f7Stbbdev tbb::flow::write_once_node<R> n(g);
13051c0b2f7Stbbdev //Create a vector of identical nodes
13151c0b2f7Stbbdev std::vector< tbb::flow::write_once_node<R> > wo_vec(2, n);
13251c0b2f7Stbbdev
13351c0b2f7Stbbdev for (size_t node_idx=0; node_idx<wo_vec.size(); ++node_idx) {
13451c0b2f7Stbbdev for ( int t = 0; t < T; ++t ) {
13551c0b2f7Stbbdev std::vector< std::shared_ptr<harness_counting_receiver<R>> > r;
13651c0b2f7Stbbdev for (size_t i = 0; i < M; ++i) {
13751c0b2f7Stbbdev r.push_back( std::make_shared<harness_counting_receiver<R>>(g) );
13851c0b2f7Stbbdev }
13951c0b2f7Stbbdev
14051c0b2f7Stbbdev
14151c0b2f7Stbbdev for (int i = 0; i < M; ++i) {
14251c0b2f7Stbbdev tbb::flow::make_edge( wo_vec[node_idx], *r[i] );
14351c0b2f7Stbbdev }
14451c0b2f7Stbbdev R v0;
14551c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].is_valid() == false, "" );
14651c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].try_get( v0 ) == false, "" );
14751c0b2f7Stbbdev
14851c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].try_put( R(-1) ), "" );
14951c0b2f7Stbbdev #if TBB_TEST_LOW_WORKLOAD
15051c0b2f7Stbbdev const int nthreads = 30;
15151c0b2f7Stbbdev #else
15251c0b2f7Stbbdev const int nthreads = N;
15351c0b2f7Stbbdev #endif
15451c0b2f7Stbbdev utils::NativeParallelFor( nthreads, native_body<R>( wo_vec[node_idx] ) );
15551c0b2f7Stbbdev
15651c0b2f7Stbbdev for (int i = 0; i < M; ++i) {
15751c0b2f7Stbbdev size_t c = r[i]->my_count;
15851c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" );
15951c0b2f7Stbbdev }
16051c0b2f7Stbbdev for (int i = 0; i < M; ++i) {
16151c0b2f7Stbbdev tbb::flow::remove_edge( wo_vec[node_idx], *r[i] );
16251c0b2f7Stbbdev }
16351c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].try_put( R(0) ) == false, "" );
16451c0b2f7Stbbdev for (int i = 0; i < M; ++i) {
16551c0b2f7Stbbdev size_t c = r[i]->my_count;
16651c0b2f7Stbbdev CHECK_MESSAGE( int(c) == 1, "" );
16751c0b2f7Stbbdev }
16851c0b2f7Stbbdev wo_vec[node_idx].clear();
16951c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].is_valid() == false, "" );
17051c0b2f7Stbbdev CHECK_MESSAGE( wo_vec[node_idx].try_get( v0 ) == false, "" );
17151c0b2f7Stbbdev }
17251c0b2f7Stbbdev }
17351c0b2f7Stbbdev }
17451c0b2f7Stbbdev
17551c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
17651c0b2f7Stbbdev #include <array>
17751c0b2f7Stbbdev #include <vector>
test_follows_and_precedes_api()17851c0b2f7Stbbdev void test_follows_and_precedes_api() {
17951c0b2f7Stbbdev using msg_t = tbb::flow::continue_msg;
18051c0b2f7Stbbdev
18151c0b2f7Stbbdev std::array<msg_t, 3> messages_for_follows= {msg_t(), msg_t(), msg_t()};
18251c0b2f7Stbbdev std::vector<msg_t> messages_for_precedes = {msg_t()};
18351c0b2f7Stbbdev
18451c0b2f7Stbbdev follows_and_precedes_testing::test_follows<msg_t, tbb::flow::write_once_node<msg_t>>(messages_for_follows);
18551c0b2f7Stbbdev follows_and_precedes_testing::test_precedes<msg_t, tbb::flow::write_once_node<msg_t>>(messages_for_precedes);
18651c0b2f7Stbbdev }
18751c0b2f7Stbbdev #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
18851c0b2f7Stbbdev
18951c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
test_deduction_guides()19051c0b2f7Stbbdev void test_deduction_guides() {
19151c0b2f7Stbbdev using namespace tbb::flow;
19251c0b2f7Stbbdev
19351c0b2f7Stbbdev graph g;
19451c0b2f7Stbbdev broadcast_node<int> b1(g);
19551c0b2f7Stbbdev write_once_node<int> wo0(g);
19651c0b2f7Stbbdev
19751c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
19851c0b2f7Stbbdev write_once_node wo1(follows(b1));
19951c0b2f7Stbbdev static_assert(std::is_same_v<decltype(wo1), write_once_node<int>>);
20051c0b2f7Stbbdev
20151c0b2f7Stbbdev write_once_node wo2(precedes(b1));
20251c0b2f7Stbbdev static_assert(std::is_same_v<decltype(wo2), write_once_node<int>>);
20351c0b2f7Stbbdev #endif
20451c0b2f7Stbbdev
20551c0b2f7Stbbdev write_once_node wo3(wo0);
20651c0b2f7Stbbdev static_assert(std::is_same_v<decltype(wo3), write_once_node<int>>);
20751c0b2f7Stbbdev }
20851c0b2f7Stbbdev #endif
20951c0b2f7Stbbdev
21051c0b2f7Stbbdev //! Test read-write properties
21151c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing
21251c0b2f7Stbbdev TEST_CASE("Read-write tests"){
21351c0b2f7Stbbdev simple_read_write_tests<int>();
21451c0b2f7Stbbdev simple_read_write_tests<float>();
21551c0b2f7Stbbdev }
21651c0b2f7Stbbdev
21751c0b2f7Stbbdev //! Test read-write properties under parallelism
21851c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing \ref stress
21951c0b2f7Stbbdev TEST_CASE("Parallel read-write tests"){
22051c0b2f7Stbbdev for( unsigned int p=utils::MinThread; p<=utils::MaxThread; ++p ) {
22151c0b2f7Stbbdev tbb::task_arena arena(p);
22251c0b2f7Stbbdev arena.execute(
__anon67c9833e0102() 22351c0b2f7Stbbdev [&]() {
22451c0b2f7Stbbdev parallel_read_write_tests<int>();
22551c0b2f7Stbbdev parallel_read_write_tests<float>();
22651c0b2f7Stbbdev test_reserving_nodes<tbb::flow::write_once_node, size_t>();
22751c0b2f7Stbbdev }
22851c0b2f7Stbbdev );
22951c0b2f7Stbbdev }
23051c0b2f7Stbbdev }
23151c0b2f7Stbbdev
23251c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
23351c0b2f7Stbbdev //! Test deprecated follows and precedes API
23451c0b2f7Stbbdev //! \brief \ref error_guessing
23551c0b2f7Stbbdev TEST_CASE("Test follows and precedes API"){
23651c0b2f7Stbbdev test_follows_and_precedes_api();
23751c0b2f7Stbbdev }
23851c0b2f7Stbbdev #endif
23951c0b2f7Stbbdev
24051c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
24151c0b2f7Stbbdev //! Test deduction guides
24251c0b2f7Stbbdev //! \brief \ref requirement
24351c0b2f7Stbbdev TEST_CASE("Deduction guides"){
24451c0b2f7Stbbdev test_deduction_guides();
24551c0b2f7Stbbdev }
24651c0b2f7Stbbdev #endif
247