xref: /oneTBB/test/tbb/test_buffer_node.cpp (revision c4a799df)
151c0b2f7Stbbdev /*
2*c4a799dfSJhaShweta1     Copyright (c) 2005-2023 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 #include "common/config.h"
1851c0b2f7Stbbdev 
1951c0b2f7Stbbdev #include "tbb/flow_graph.h"
20552f342bSPavel #include "tbb/global_control.h"
2151c0b2f7Stbbdev 
2251c0b2f7Stbbdev #include "common/test.h"
2351c0b2f7Stbbdev #include "common/utils.h"
2451c0b2f7Stbbdev #include "common/graph_utils.h"
2551c0b2f7Stbbdev #include "common/test_follows_and_precedes_api.h"
2651c0b2f7Stbbdev 
2751c0b2f7Stbbdev 
2851c0b2f7Stbbdev //! \file test_buffer_node.cpp
2951c0b2f7Stbbdev //! \brief Test for [flow_graph.buffer_node] specification
3051c0b2f7Stbbdev 
3151c0b2f7Stbbdev 
3251c0b2f7Stbbdev #define N 1000
3351c0b2f7Stbbdev #define C 10
3451c0b2f7Stbbdev 
3551c0b2f7Stbbdev template< typename T >
spin_try_get(tbb::flow::buffer_node<T> & b,T & value)3651c0b2f7Stbbdev void spin_try_get( tbb::flow::buffer_node<T> &b, T &value ) {
3751c0b2f7Stbbdev     while ( b.try_get(value) != true ) {}
3851c0b2f7Stbbdev }
3951c0b2f7Stbbdev 
4051c0b2f7Stbbdev template< typename T >
check_item(T * count_value,T & value)4151c0b2f7Stbbdev void check_item( T* count_value, T &value ) {
4251c0b2f7Stbbdev     count_value[value / N] += value % N;
4351c0b2f7Stbbdev }
4451c0b2f7Stbbdev 
4551c0b2f7Stbbdev template< typename T >
4651c0b2f7Stbbdev struct parallel_puts : utils::NoAssign {
4751c0b2f7Stbbdev 
4851c0b2f7Stbbdev     tbb::flow::buffer_node<T> &my_b;
4951c0b2f7Stbbdev 
parallel_putsparallel_puts5051c0b2f7Stbbdev     parallel_puts( tbb::flow::buffer_node<T> &b ) : my_b(b) {}
5151c0b2f7Stbbdev 
operator ()parallel_puts5251c0b2f7Stbbdev     void operator()(int i) const {
5351c0b2f7Stbbdev         for (int j = 0; j < N; ++j) {
5451c0b2f7Stbbdev             bool msg = my_b.try_put( T(N*i + j) );
5551c0b2f7Stbbdev             CHECK_MESSAGE( msg == true, "" );
5651c0b2f7Stbbdev         }
5751c0b2f7Stbbdev     }
5851c0b2f7Stbbdev };
5951c0b2f7Stbbdev 
6051c0b2f7Stbbdev template< typename T >
6151c0b2f7Stbbdev struct touches {
6251c0b2f7Stbbdev 
6351c0b2f7Stbbdev     bool **my_touches;
6451c0b2f7Stbbdev     int my_num_threads;
6551c0b2f7Stbbdev 
touchestouches6651c0b2f7Stbbdev     touches( int num_threads ) : my_num_threads(num_threads) {
6751c0b2f7Stbbdev         my_touches = new bool* [my_num_threads];
6851c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
6951c0b2f7Stbbdev             my_touches[p] = new bool[N];
7051c0b2f7Stbbdev             for ( int n = 0; n < N; ++n)
7151c0b2f7Stbbdev                 my_touches[p][n] = false;
7251c0b2f7Stbbdev         }
7351c0b2f7Stbbdev     }
7451c0b2f7Stbbdev 
~touchestouches7551c0b2f7Stbbdev     ~touches() {
7651c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
7751c0b2f7Stbbdev             delete [] my_touches[p];
7851c0b2f7Stbbdev         }
7951c0b2f7Stbbdev         delete [] my_touches;
8051c0b2f7Stbbdev     }
8151c0b2f7Stbbdev 
checktouches8251c0b2f7Stbbdev     bool check( T v ) {
8351c0b2f7Stbbdev         CHECK_MESSAGE( my_touches[v/N][v%N] == false, "" );
8451c0b2f7Stbbdev         my_touches[v/N][v%N] = true;
8551c0b2f7Stbbdev         return true;
8651c0b2f7Stbbdev     }
8751c0b2f7Stbbdev 
validate_touchestouches8851c0b2f7Stbbdev     bool validate_touches() {
8951c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
9051c0b2f7Stbbdev             for ( int n = 0; n < N; ++n) {
9151c0b2f7Stbbdev                 CHECK_MESSAGE( my_touches[p][n] == true, "" );
9251c0b2f7Stbbdev             }
9351c0b2f7Stbbdev         }
9451c0b2f7Stbbdev         return true;
9551c0b2f7Stbbdev     }
9651c0b2f7Stbbdev };
9751c0b2f7Stbbdev 
9851c0b2f7Stbbdev template< typename T >
9951c0b2f7Stbbdev struct parallel_gets : utils::NoAssign {
10051c0b2f7Stbbdev 
10151c0b2f7Stbbdev     tbb::flow::buffer_node<T> &my_b;
10251c0b2f7Stbbdev     touches<T> &my_touches;
10351c0b2f7Stbbdev 
parallel_getsparallel_gets10451c0b2f7Stbbdev     parallel_gets( tbb::flow::buffer_node<T> &b, touches<T> &t) : my_b(b), my_touches(t) {}
10551c0b2f7Stbbdev 
operator ()parallel_gets10651c0b2f7Stbbdev     void operator()(int) const {
10751c0b2f7Stbbdev         for (int j = 0; j < N; ++j) {
10851c0b2f7Stbbdev             T v;
10951c0b2f7Stbbdev             spin_try_get( my_b, v );
11051c0b2f7Stbbdev             my_touches.check( v );
11151c0b2f7Stbbdev         }
11251c0b2f7Stbbdev     }
11351c0b2f7Stbbdev 
11451c0b2f7Stbbdev };
11551c0b2f7Stbbdev 
11651c0b2f7Stbbdev template< typename T >
11751c0b2f7Stbbdev struct parallel_put_get : utils::NoAssign {
11851c0b2f7Stbbdev 
11951c0b2f7Stbbdev     tbb::flow::buffer_node<T> &my_b;
12051c0b2f7Stbbdev     touches<T> &my_touches;
12151c0b2f7Stbbdev 
parallel_put_getparallel_put_get12251c0b2f7Stbbdev     parallel_put_get( tbb::flow::buffer_node<T> &b, touches<T> &t ) : my_b(b), my_touches(t) {}
12351c0b2f7Stbbdev 
operator ()parallel_put_get12451c0b2f7Stbbdev     void operator()(int tid) const {
12551c0b2f7Stbbdev 
12651c0b2f7Stbbdev         for ( int i = 0; i < N; i+=C ) {
12751c0b2f7Stbbdev             int j_end = ( N < i + C ) ? N : i + C;
12851c0b2f7Stbbdev             // dump about C values into the buffer
12951c0b2f7Stbbdev             for ( int j = i; j < j_end; ++j ) {
13051c0b2f7Stbbdev                 CHECK_MESSAGE( my_b.try_put( T (N*tid + j ) ) == true, "" );
13151c0b2f7Stbbdev             }
13251c0b2f7Stbbdev             // receiver about C values from the buffer
13351c0b2f7Stbbdev             for ( int j = i; j < j_end; ++j ) {
13451c0b2f7Stbbdev                 T v;
13551c0b2f7Stbbdev                 spin_try_get( my_b, v );
13651c0b2f7Stbbdev                 my_touches.check( v );
13751c0b2f7Stbbdev             }
13851c0b2f7Stbbdev         }
13951c0b2f7Stbbdev     }
14051c0b2f7Stbbdev 
14151c0b2f7Stbbdev };
14251c0b2f7Stbbdev 
14351c0b2f7Stbbdev //
14451c0b2f7Stbbdev // Tests
14551c0b2f7Stbbdev //
14651c0b2f7Stbbdev // Item can be reserved, released, consumed ( single serial receiver )
14751c0b2f7Stbbdev //
14851c0b2f7Stbbdev template< typename T >
test_reservation()14951c0b2f7Stbbdev int test_reservation() {
15051c0b2f7Stbbdev     tbb::flow::graph g;
15151c0b2f7Stbbdev     T bogus_value(-1);
15251c0b2f7Stbbdev 
15351c0b2f7Stbbdev     // Simple tests
15451c0b2f7Stbbdev     tbb::flow::buffer_node<T> b(g);
15551c0b2f7Stbbdev 
15651c0b2f7Stbbdev     b.try_put(T(1));
15751c0b2f7Stbbdev     b.try_put(T(2));
15851c0b2f7Stbbdev     b.try_put(T(3));
15951c0b2f7Stbbdev 
16051c0b2f7Stbbdev     T v, vsum;
16151c0b2f7Stbbdev     CHECK_MESSAGE( b.try_reserve(v) == true, "" );
16251c0b2f7Stbbdev     CHECK_MESSAGE( b.try_release() == true, "" );
16351c0b2f7Stbbdev     v = bogus_value;
16451c0b2f7Stbbdev     g.wait_for_all();
16551c0b2f7Stbbdev     CHECK_MESSAGE( b.try_reserve(v) == true, "" );
16651c0b2f7Stbbdev     CHECK_MESSAGE( b.try_consume() == true, "" );
16751c0b2f7Stbbdev     vsum += v;
16851c0b2f7Stbbdev     v = bogus_value;
16951c0b2f7Stbbdev     g.wait_for_all();
17051c0b2f7Stbbdev 
17151c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get(v) == true, "" );
17251c0b2f7Stbbdev     vsum += v;
17351c0b2f7Stbbdev     v = bogus_value;
17451c0b2f7Stbbdev     g.wait_for_all();
17551c0b2f7Stbbdev 
17651c0b2f7Stbbdev     CHECK_MESSAGE( b.try_reserve(v) == true, "" );
17751c0b2f7Stbbdev     CHECK_MESSAGE( b.try_release() == true, "" );
17851c0b2f7Stbbdev     v = bogus_value;
17951c0b2f7Stbbdev     g.wait_for_all();
18051c0b2f7Stbbdev     CHECK_MESSAGE( b.try_reserve(v) == true, "" );
18151c0b2f7Stbbdev     CHECK_MESSAGE( b.try_consume() == true, "" );
18251c0b2f7Stbbdev     vsum += v;
18351c0b2f7Stbbdev     CHECK_MESSAGE( vsum == T(6), "");
18451c0b2f7Stbbdev     v = bogus_value;
18551c0b2f7Stbbdev     g.wait_for_all();
18651c0b2f7Stbbdev 
18751c0b2f7Stbbdev     return 0;
18851c0b2f7Stbbdev }
18951c0b2f7Stbbdev 
19051c0b2f7Stbbdev //
19151c0b2f7Stbbdev // Tests
19251c0b2f7Stbbdev //
19351c0b2f7Stbbdev // multiple parallel senders, items in arbitrary order
19451c0b2f7Stbbdev // multiple parallel senders, multiple parallel receivers, items in arbitrary order and all items received
19551c0b2f7Stbbdev //   * overlapped puts / gets
19651c0b2f7Stbbdev //   * all puts finished before any getS
19751c0b2f7Stbbdev //
19851c0b2f7Stbbdev template< typename T >
test_parallel(int num_threads)19951c0b2f7Stbbdev int test_parallel(int num_threads) {
20051c0b2f7Stbbdev     tbb::flow::graph g;
20151c0b2f7Stbbdev     tbb::flow::buffer_node<T> b(g);
20251c0b2f7Stbbdev     tbb::flow::buffer_node<T> b2(g);
20351c0b2f7Stbbdev     tbb::flow::buffer_node<T> b3(g);
20451c0b2f7Stbbdev     T bogus_value(-1);
20551c0b2f7Stbbdev     T j = bogus_value;
20651c0b2f7Stbbdev 
20751c0b2f7Stbbdev     NativeParallelFor( num_threads, parallel_puts<T>(b) );
20851c0b2f7Stbbdev 
20951c0b2f7Stbbdev     T *next_value = new T[num_threads];
21051c0b2f7Stbbdev     for (int tid = 0; tid < num_threads; ++tid) next_value[tid] = T(0);
21151c0b2f7Stbbdev 
21251c0b2f7Stbbdev     for (int i = 0; i < num_threads * N; ++i ) {
21351c0b2f7Stbbdev         spin_try_get( b, j );
21451c0b2f7Stbbdev         check_item( next_value, j );
21551c0b2f7Stbbdev         j = bogus_value;
21651c0b2f7Stbbdev     }
21751c0b2f7Stbbdev     for (int tid = 0; tid < num_threads; ++tid)  {
21851c0b2f7Stbbdev         CHECK_MESSAGE( next_value[tid] == T((N*(N-1))/2), "" );
21951c0b2f7Stbbdev     }
22051c0b2f7Stbbdev 
22151c0b2f7Stbbdev     j = bogus_value;
22251c0b2f7Stbbdev     g.wait_for_all();
22351c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
22451c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
22551c0b2f7Stbbdev 
22651c0b2f7Stbbdev     NativeParallelFor( num_threads, parallel_puts<T>(b) );
22751c0b2f7Stbbdev 
22851c0b2f7Stbbdev     {
22951c0b2f7Stbbdev         touches< T > t( num_threads );
23051c0b2f7Stbbdev         NativeParallelFor( num_threads, parallel_gets<T>(b, t) );
23151c0b2f7Stbbdev         g.wait_for_all();
23251c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
23351c0b2f7Stbbdev     }
23451c0b2f7Stbbdev     j = bogus_value;
23551c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
23651c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
23751c0b2f7Stbbdev 
23851c0b2f7Stbbdev     g.wait_for_all();
23951c0b2f7Stbbdev     {
24051c0b2f7Stbbdev         touches< T > t( num_threads );
24151c0b2f7Stbbdev         NativeParallelFor( num_threads, parallel_put_get<T>(b, t) );
24251c0b2f7Stbbdev         g.wait_for_all();
24351c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
24451c0b2f7Stbbdev     }
24551c0b2f7Stbbdev     j = bogus_value;
24651c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
24751c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
24851c0b2f7Stbbdev 
24951c0b2f7Stbbdev     tbb::flow::make_edge( b, b2 );
25051c0b2f7Stbbdev     tbb::flow::make_edge( b2, b3 );
25151c0b2f7Stbbdev 
25251c0b2f7Stbbdev     NativeParallelFor( num_threads, parallel_puts<T>(b) );
25351c0b2f7Stbbdev     {
25451c0b2f7Stbbdev         touches< T > t( num_threads );
25551c0b2f7Stbbdev         NativeParallelFor( num_threads, parallel_gets<T>(b3, t) );
25651c0b2f7Stbbdev         g.wait_for_all();
25751c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
25851c0b2f7Stbbdev     }
25951c0b2f7Stbbdev     j = bogus_value;
26051c0b2f7Stbbdev     g.wait_for_all();
26151c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
26251c0b2f7Stbbdev     g.wait_for_all();
26351c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
26451c0b2f7Stbbdev     g.wait_for_all();
26551c0b2f7Stbbdev     CHECK_MESSAGE( b3.try_get( j ) == false, "" );
26651c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
26751c0b2f7Stbbdev 
26851c0b2f7Stbbdev     // test copy constructor
26951c0b2f7Stbbdev     CHECK_MESSAGE( b.remove_successor( b2 ), "" );
27051c0b2f7Stbbdev     // fill up b:
27151c0b2f7Stbbdev     NativeParallelFor( num_threads, parallel_puts<T>(b) );
27251c0b2f7Stbbdev     // copy b:
27351c0b2f7Stbbdev     tbb::flow::buffer_node<T> b_copy(b);
27451c0b2f7Stbbdev 
27551c0b2f7Stbbdev     // b_copy should be empty
27651c0b2f7Stbbdev     j = bogus_value;
27751c0b2f7Stbbdev     g.wait_for_all();
27851c0b2f7Stbbdev     CHECK_MESSAGE( b_copy.try_get( j ) == false, "" );
27951c0b2f7Stbbdev 
28051c0b2f7Stbbdev     // hook them together:
28151c0b2f7Stbbdev     CHECK_MESSAGE( b.register_successor(b_copy) == true, "" );
28251c0b2f7Stbbdev     // try to get content from b_copy
28351c0b2f7Stbbdev     {
28451c0b2f7Stbbdev         touches< T > t( num_threads );
28551c0b2f7Stbbdev         NativeParallelFor( num_threads, parallel_gets<T>(b_copy, t) );
28651c0b2f7Stbbdev         g.wait_for_all();
28751c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
28851c0b2f7Stbbdev     }
28951c0b2f7Stbbdev     // now both should be empty
29051c0b2f7Stbbdev     j = bogus_value;
29151c0b2f7Stbbdev     g.wait_for_all();
29251c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
29351c0b2f7Stbbdev     g.wait_for_all();
29451c0b2f7Stbbdev     CHECK_MESSAGE( b_copy.try_get( j ) == false, "" );
29551c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
29651c0b2f7Stbbdev 
29751c0b2f7Stbbdev     delete [] next_value;
29851c0b2f7Stbbdev     return 0;
29951c0b2f7Stbbdev }
30051c0b2f7Stbbdev 
30151c0b2f7Stbbdev //
30251c0b2f7Stbbdev // Tests
30351c0b2f7Stbbdev //
30451c0b2f7Stbbdev // Predecessors cannot be registered
30551c0b2f7Stbbdev // Empty buffer rejects item requests
30651c0b2f7Stbbdev // Single serial sender, items in arbitrary order
30751c0b2f7Stbbdev // Chained buffers ( 2 & 3 ), single sender, items at last buffer in arbitrary order
30851c0b2f7Stbbdev //
30951c0b2f7Stbbdev 
31051c0b2f7Stbbdev #define TBB_INTERNAL_NAMESPACE detail::d1
31151c0b2f7Stbbdev using tbb::TBB_INTERNAL_NAMESPACE::register_predecessor;
31251c0b2f7Stbbdev using tbb::TBB_INTERNAL_NAMESPACE::remove_predecessor;
31351c0b2f7Stbbdev 
31451c0b2f7Stbbdev template< typename T >
test_serial()31551c0b2f7Stbbdev int test_serial() {
31651c0b2f7Stbbdev     tbb::flow::graph g;
31751c0b2f7Stbbdev     T bogus_value(-1);
31851c0b2f7Stbbdev 
31951c0b2f7Stbbdev     tbb::flow::buffer_node<T> b(g);
32051c0b2f7Stbbdev     tbb::flow::buffer_node<T> b2(g);
32151c0b2f7Stbbdev     T j = bogus_value;
32251c0b2f7Stbbdev 
32351c0b2f7Stbbdev     //
32451c0b2f7Stbbdev     // Rejects attempts to add / remove predecessor
32551c0b2f7Stbbdev     // Rejects request from empty buffer
32651c0b2f7Stbbdev     //
32751c0b2f7Stbbdev     CHECK_MESSAGE( register_predecessor<T>( b, b2 ) == false, "" );
32851c0b2f7Stbbdev     CHECK_MESSAGE( remove_predecessor<T>( b, b2 ) == false, "" );
32951c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
33051c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
33151c0b2f7Stbbdev 
33251c0b2f7Stbbdev     //
33351c0b2f7Stbbdev     // Simple puts and gets
33451c0b2f7Stbbdev     //
33551c0b2f7Stbbdev 
33651c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
33751c0b2f7Stbbdev         bool msg = b.try_put( T(i) );
33851c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
33951c0b2f7Stbbdev     }
34051c0b2f7Stbbdev 
34151c0b2f7Stbbdev     T vsum = T(0);
34251c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
34351c0b2f7Stbbdev         j = bogus_value;
34451c0b2f7Stbbdev         spin_try_get( b, j );
34551c0b2f7Stbbdev         vsum += j;
34651c0b2f7Stbbdev     }
34751c0b2f7Stbbdev     CHECK_MESSAGE( vsum == (N*(N-1))/2, "");
34851c0b2f7Stbbdev     j = bogus_value;
34951c0b2f7Stbbdev     g.wait_for_all();
35051c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
35151c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
35251c0b2f7Stbbdev 
35351c0b2f7Stbbdev     tbb::flow::make_edge(b, b2);
35451c0b2f7Stbbdev 
35551c0b2f7Stbbdev     vsum = T(0);
35651c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
35751c0b2f7Stbbdev         bool msg = b.try_put( T(i) );
35851c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
35951c0b2f7Stbbdev     }
36051c0b2f7Stbbdev 
36151c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
36251c0b2f7Stbbdev         j = bogus_value;
36351c0b2f7Stbbdev         spin_try_get( b2, j );
36451c0b2f7Stbbdev         vsum += j;
36551c0b2f7Stbbdev     }
36651c0b2f7Stbbdev     CHECK_MESSAGE( vsum == (N*(N-1))/2, "");
36751c0b2f7Stbbdev     j = bogus_value;
36851c0b2f7Stbbdev     g.wait_for_all();
36951c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
37051c0b2f7Stbbdev     g.wait_for_all();
37151c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
37251c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
37351c0b2f7Stbbdev 
37451c0b2f7Stbbdev     tbb::flow::remove_edge(b, b2);
37551c0b2f7Stbbdev     CHECK_MESSAGE( b.try_put( 1 ) == true, "" );
37651c0b2f7Stbbdev     g.wait_for_all();
37751c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
37851c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
37951c0b2f7Stbbdev     g.wait_for_all();
38051c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == true, "" );
38151c0b2f7Stbbdev     CHECK_MESSAGE( j == 1, "" );
38251c0b2f7Stbbdev 
38351c0b2f7Stbbdev     tbb::flow::buffer_node<T> b3(g);
38451c0b2f7Stbbdev     tbb::flow::make_edge( b, b2 );
38551c0b2f7Stbbdev     tbb::flow::make_edge( b2, b3 );
38651c0b2f7Stbbdev 
38751c0b2f7Stbbdev     vsum = T(0);
38851c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
38951c0b2f7Stbbdev         bool msg = b.try_put( T(i) );
39051c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
39151c0b2f7Stbbdev     }
39251c0b2f7Stbbdev 
39351c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
39451c0b2f7Stbbdev         j = bogus_value;
39551c0b2f7Stbbdev         spin_try_get( b3, j );
39651c0b2f7Stbbdev         vsum += j;
39751c0b2f7Stbbdev     }
39851c0b2f7Stbbdev     CHECK_MESSAGE( vsum == (N*(N-1))/2, "");
39951c0b2f7Stbbdev     j = bogus_value;
40051c0b2f7Stbbdev     g.wait_for_all();
40151c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
40251c0b2f7Stbbdev     g.wait_for_all();
40351c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
40451c0b2f7Stbbdev     g.wait_for_all();
40551c0b2f7Stbbdev     CHECK_MESSAGE( b3.try_get( j ) == false, "" );
40651c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
40751c0b2f7Stbbdev 
40851c0b2f7Stbbdev     tbb::flow::remove_edge(b, b2);
40951c0b2f7Stbbdev     CHECK_MESSAGE( b.try_put( 1 ) == true, "" );
41051c0b2f7Stbbdev     g.wait_for_all();
41151c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
41251c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
41351c0b2f7Stbbdev     g.wait_for_all();
41451c0b2f7Stbbdev     CHECK_MESSAGE( b3.try_get( j ) == false, "" );
41551c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
41651c0b2f7Stbbdev     g.wait_for_all();
41751c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == true, "" );
41851c0b2f7Stbbdev     CHECK_MESSAGE( j == 1, "" );
41951c0b2f7Stbbdev 
42051c0b2f7Stbbdev     return 0;
42151c0b2f7Stbbdev }
42251c0b2f7Stbbdev 
42351c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
42451c0b2f7Stbbdev #include <array>
42551c0b2f7Stbbdev #include <vector>
test_follows_and_precedes_api()42651c0b2f7Stbbdev void test_follows_and_precedes_api() {
42751c0b2f7Stbbdev     using msg_t = tbb::flow::continue_msg;
42851c0b2f7Stbbdev 
42951c0b2f7Stbbdev     std::array<msg_t, 3> messages_for_follows = { {msg_t(), msg_t(), msg_t()} };
43051c0b2f7Stbbdev     std::vector<msg_t> messages_for_precedes = {msg_t(), msg_t(), msg_t()};
43151c0b2f7Stbbdev 
43251c0b2f7Stbbdev     follows_and_precedes_testing::test_follows<msg_t, tbb::flow::buffer_node<msg_t>>(messages_for_follows);
43351c0b2f7Stbbdev     follows_and_precedes_testing::test_precedes<msg_t, tbb::flow::buffer_node<msg_t>>(messages_for_precedes);
43451c0b2f7Stbbdev }
43551c0b2f7Stbbdev #endif
43651c0b2f7Stbbdev 
43751c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
test_deduction_guides()43851c0b2f7Stbbdev void test_deduction_guides() {
43951c0b2f7Stbbdev     using namespace tbb::flow;
44051c0b2f7Stbbdev     graph g;
44151c0b2f7Stbbdev     broadcast_node<int> br(g);
44251c0b2f7Stbbdev     buffer_node<int> b0(g);
44351c0b2f7Stbbdev 
44451c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
44551c0b2f7Stbbdev     buffer_node b1(follows(br));
44651c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(b1), buffer_node<int>>);
44751c0b2f7Stbbdev 
44851c0b2f7Stbbdev     buffer_node b2(precedes(br));
44951c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(b2), buffer_node<int>>);
45051c0b2f7Stbbdev #endif
45151c0b2f7Stbbdev 
45251c0b2f7Stbbdev     buffer_node b3(b0);
45351c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(b3), buffer_node<int>>);
45451c0b2f7Stbbdev     g.wait_for_all();
45551c0b2f7Stbbdev }
45651c0b2f7Stbbdev #endif
45751c0b2f7Stbbdev 
45851c0b2f7Stbbdev #include <iomanip>
45951c0b2f7Stbbdev 
46051c0b2f7Stbbdev //! Test buffer_node with parallel and serial neighbours
46151c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing
46251c0b2f7Stbbdev TEST_CASE("Serial and parallel test"){
46351c0b2f7Stbbdev     for (int p = 2; p <= 4; ++p) {
464552f342bSPavel         tbb::global_control thread_limit(tbb::global_control::max_allowed_parallelism, p);
46551c0b2f7Stbbdev         tbb::task_arena arena(p);
46651c0b2f7Stbbdev         arena.execute(
__anon4e62daa90102() 46751c0b2f7Stbbdev             [&]() {
46851c0b2f7Stbbdev                 test_serial<int>();
46951c0b2f7Stbbdev                 test_parallel<int>(p);
47051c0b2f7Stbbdev             }
47151c0b2f7Stbbdev         );
47251c0b2f7Stbbdev     }
47351c0b2f7Stbbdev }
47451c0b2f7Stbbdev 
47551c0b2f7Stbbdev //! Test reset and cancellation behavior
47651c0b2f7Stbbdev //! \brief \ref error_guessing
47751c0b2f7Stbbdev TEST_CASE("Resets"){
47851c0b2f7Stbbdev     test_resets<int,tbb::flow::buffer_node<int> >();
47951c0b2f7Stbbdev     test_resets<float,tbb::flow::buffer_node<float> >();
48051c0b2f7Stbbdev }
48151c0b2f7Stbbdev 
48251c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
483*c4a799dfSJhaShweta1 //! Test deprecated follows and precedes API
48451c0b2f7Stbbdev //! \brief \ref error_guessing
48551c0b2f7Stbbdev TEST_CASE("Follows and precedes API"){
48651c0b2f7Stbbdev     test_follows_and_precedes_api();
48751c0b2f7Stbbdev }
48851c0b2f7Stbbdev #endif
48951c0b2f7Stbbdev 
49051c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
49151c0b2f7Stbbdev //! Test deduction guides
49251c0b2f7Stbbdev //! \brief requirement
49351c0b2f7Stbbdev TEST_CASE("Deduction guides"){
49451c0b2f7Stbbdev     test_deduction_guides();
49551c0b2f7Stbbdev }
49651c0b2f7Stbbdev #endif
497