xref: /oneTBB/test/tbb/test_sequencer_node.cpp (revision b15aabb3)
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 #include "common/config.h"
1851c0b2f7Stbbdev 
1951c0b2f7Stbbdev #include "tbb/flow_graph.h"
2051c0b2f7Stbbdev 
2151c0b2f7Stbbdev #include "common/test.h"
2251c0b2f7Stbbdev #include "common/utils.h"
2351c0b2f7Stbbdev #include "common/utils_assert.h"
2451c0b2f7Stbbdev #include "common/test_follows_and_precedes_api.h"
2551c0b2f7Stbbdev 
2651c0b2f7Stbbdev #include <cstdio>
2751c0b2f7Stbbdev #include <atomic>
2851c0b2f7Stbbdev 
2951c0b2f7Stbbdev 
3051c0b2f7Stbbdev //! \file test_sequencer_node.cpp
3151c0b2f7Stbbdev //! \brief Test for [flow_graph.sequencer_node] specification
3251c0b2f7Stbbdev 
3351c0b2f7Stbbdev 
3451c0b2f7Stbbdev #define N 1000
3551c0b2f7Stbbdev #define C 10
3651c0b2f7Stbbdev 
3751c0b2f7Stbbdev template< typename T >
3851c0b2f7Stbbdev struct seq_inspector {
3951c0b2f7Stbbdev     size_t operator()(const T &v) const { return size_t(v); }
4051c0b2f7Stbbdev };
4151c0b2f7Stbbdev 
4251c0b2f7Stbbdev template< typename T >
4351c0b2f7Stbbdev bool wait_try_get( tbb::flow::graph &g, tbb::flow::sequencer_node<T> &q, T &value ) {
4451c0b2f7Stbbdev     g.wait_for_all();
4551c0b2f7Stbbdev     return q.try_get(value);
4651c0b2f7Stbbdev }
4751c0b2f7Stbbdev 
4851c0b2f7Stbbdev template< typename T >
4951c0b2f7Stbbdev void spin_try_get( tbb::flow::queue_node<T> &q, T &value ) {
5051c0b2f7Stbbdev     while ( q.try_get(value) != true ) ;
5151c0b2f7Stbbdev }
5251c0b2f7Stbbdev 
5351c0b2f7Stbbdev template< typename T >
5451c0b2f7Stbbdev struct parallel_puts : utils::NoAssign {
5551c0b2f7Stbbdev 
5651c0b2f7Stbbdev     tbb::flow::sequencer_node<T> &my_q;
5751c0b2f7Stbbdev     int my_num_threads;
5851c0b2f7Stbbdev 
5951c0b2f7Stbbdev     parallel_puts( tbb::flow::sequencer_node<T> &q, int num_threads ) : my_q(q), my_num_threads(num_threads) {}
6051c0b2f7Stbbdev 
6151c0b2f7Stbbdev     void operator()(int tid) const {
6251c0b2f7Stbbdev         for (int j = tid; j < N; j+=my_num_threads) {
6351c0b2f7Stbbdev             bool msg = my_q.try_put( T(j) );
6451c0b2f7Stbbdev             CHECK_MESSAGE( msg == true, "" );
6551c0b2f7Stbbdev         }
6651c0b2f7Stbbdev     }
6751c0b2f7Stbbdev 
6851c0b2f7Stbbdev };
6951c0b2f7Stbbdev 
7051c0b2f7Stbbdev template< typename T >
7151c0b2f7Stbbdev struct touches {
7251c0b2f7Stbbdev 
7351c0b2f7Stbbdev     bool **my_touches;
7451c0b2f7Stbbdev     T *my_last_touch;
7551c0b2f7Stbbdev     int my_num_threads;
7651c0b2f7Stbbdev 
7751c0b2f7Stbbdev     touches( int num_threads ) : my_num_threads(num_threads) {
7851c0b2f7Stbbdev         my_last_touch = new T[my_num_threads];
7951c0b2f7Stbbdev         my_touches = new bool* [my_num_threads];
8051c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
8151c0b2f7Stbbdev             my_last_touch[p] = T(-1);
8251c0b2f7Stbbdev             my_touches[p] = new bool[N];
8351c0b2f7Stbbdev             for ( int n = 0; n < N; ++n)
8451c0b2f7Stbbdev                 my_touches[p][n] = false;
8551c0b2f7Stbbdev         }
8651c0b2f7Stbbdev     }
8751c0b2f7Stbbdev 
8851c0b2f7Stbbdev     ~touches() {
8951c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
9051c0b2f7Stbbdev             delete [] my_touches[p];
9151c0b2f7Stbbdev         }
9251c0b2f7Stbbdev         delete [] my_touches;
9351c0b2f7Stbbdev         delete [] my_last_touch;
9451c0b2f7Stbbdev     }
9551c0b2f7Stbbdev 
9651c0b2f7Stbbdev     bool check( int tid, T v ) {
9751c0b2f7Stbbdev         if ( my_touches[tid][v] != false ) {
9851c0b2f7Stbbdev             printf("Error: value seen twice by local thread\n");
9951c0b2f7Stbbdev             return false;
10051c0b2f7Stbbdev         }
10151c0b2f7Stbbdev         if ( v <= my_last_touch[tid] ) {
10251c0b2f7Stbbdev             printf("Error: value seen in wrong order by local thread\n");
10351c0b2f7Stbbdev             return false;
10451c0b2f7Stbbdev         }
10551c0b2f7Stbbdev         my_last_touch[tid] = v;
10651c0b2f7Stbbdev         my_touches[tid][v] = true;
10751c0b2f7Stbbdev         return true;
10851c0b2f7Stbbdev     }
10951c0b2f7Stbbdev 
11051c0b2f7Stbbdev     bool validate_touches() {
11151c0b2f7Stbbdev         bool *all_touches = new bool[N];
11251c0b2f7Stbbdev         for ( int n = 0; n < N; ++n)
11351c0b2f7Stbbdev             all_touches[n] = false;
11451c0b2f7Stbbdev 
11551c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
11651c0b2f7Stbbdev             for ( int n = 0; n < N; ++n) {
11751c0b2f7Stbbdev                 if ( my_touches[p][n] == true ) {
11851c0b2f7Stbbdev                     CHECK_MESSAGE( ( all_touches[n] == false), "value see by more than one thread\n" );
11951c0b2f7Stbbdev                     all_touches[n] = true;
12051c0b2f7Stbbdev                 }
12151c0b2f7Stbbdev             }
12251c0b2f7Stbbdev         }
12351c0b2f7Stbbdev         for ( int n = 0; n < N; ++n) {
12451c0b2f7Stbbdev             if ( !all_touches[n] )
12551c0b2f7Stbbdev                 printf("No touch at %d, my_num_threads = %d\n", n, my_num_threads);
12651c0b2f7Stbbdev             //CHECK_MESSAGE( ( all_touches[n] == true), "value not seen by any thread\n" );
12751c0b2f7Stbbdev         }
12851c0b2f7Stbbdev         delete [] all_touches;
12951c0b2f7Stbbdev         return true;
13051c0b2f7Stbbdev     }
13151c0b2f7Stbbdev 
13251c0b2f7Stbbdev };
13351c0b2f7Stbbdev 
13451c0b2f7Stbbdev template< typename T >
13551c0b2f7Stbbdev struct parallel_gets : utils::NoAssign {
13651c0b2f7Stbbdev 
13751c0b2f7Stbbdev     tbb::flow::sequencer_node<T> &my_q;
13851c0b2f7Stbbdev     int my_num_threads;
13951c0b2f7Stbbdev     touches<T> &my_touches;
14051c0b2f7Stbbdev 
14151c0b2f7Stbbdev     parallel_gets( tbb::flow::sequencer_node<T> &q, int num_threads, touches<T> &t ) : my_q(q), my_num_threads(num_threads), my_touches(t) {}
14251c0b2f7Stbbdev 
14351c0b2f7Stbbdev     void operator()(int tid) const {
14451c0b2f7Stbbdev         for (int j = tid; j < N; j+=my_num_threads) {
14551c0b2f7Stbbdev             T v;
14651c0b2f7Stbbdev             spin_try_get( my_q, v );
14751c0b2f7Stbbdev             my_touches.check( tid, v );
14851c0b2f7Stbbdev         }
14951c0b2f7Stbbdev     }
15051c0b2f7Stbbdev 
15151c0b2f7Stbbdev };
15251c0b2f7Stbbdev 
15351c0b2f7Stbbdev template< typename T >
15451c0b2f7Stbbdev struct parallel_put_get : utils::NoAssign {
15551c0b2f7Stbbdev 
15651c0b2f7Stbbdev     tbb::flow::sequencer_node<T> &my_s1;
15751c0b2f7Stbbdev     tbb::flow::sequencer_node<T> &my_s2;
15851c0b2f7Stbbdev     int my_num_threads;
15951c0b2f7Stbbdev     std::atomic< int > &my_counter;
16051c0b2f7Stbbdev     touches<T> &my_touches;
16151c0b2f7Stbbdev 
16251c0b2f7Stbbdev     parallel_put_get( tbb::flow::sequencer_node<T> &s1, tbb::flow::sequencer_node<T> &s2, int num_threads,
16351c0b2f7Stbbdev                       std::atomic<int> &counter, touches<T> &t ) : my_s1(s1), my_s2(s2), my_num_threads(num_threads), my_counter(counter), my_touches(t) {}
16451c0b2f7Stbbdev 
16551c0b2f7Stbbdev     void operator()(int tid) const {
16651c0b2f7Stbbdev         int i_start = 0;
16751c0b2f7Stbbdev 
16851c0b2f7Stbbdev         while ( (i_start = my_counter.fetch_add(C)) < N ) {
16951c0b2f7Stbbdev             int i_end = ( N < i_start + C ) ? N : i_start + C;
17051c0b2f7Stbbdev             for (int i = i_start; i < i_end; ++i) {
17151c0b2f7Stbbdev                 bool msg = my_s1.try_put( T(i) );
17251c0b2f7Stbbdev                 CHECK_MESSAGE( msg == true, "" );
17351c0b2f7Stbbdev             }
17451c0b2f7Stbbdev 
17551c0b2f7Stbbdev             for (int i = i_start; i < i_end; ++i) {
17651c0b2f7Stbbdev                 T v;
17751c0b2f7Stbbdev                 spin_try_get( my_s2, v );
17851c0b2f7Stbbdev                 my_touches.check( tid, v );
17951c0b2f7Stbbdev             }
18051c0b2f7Stbbdev         }
18151c0b2f7Stbbdev     }
18251c0b2f7Stbbdev 
18351c0b2f7Stbbdev };
18451c0b2f7Stbbdev 
18551c0b2f7Stbbdev //
18651c0b2f7Stbbdev // Tests
18751c0b2f7Stbbdev //
18851c0b2f7Stbbdev // multiple parallel senders, multiple receivers, properly sequenced (relative to receiver) at output
18951c0b2f7Stbbdev // chained sequencers, multiple parallel senders, multiple receivers, properly sequenced (relative to receiver) at output
19051c0b2f7Stbbdev //
19151c0b2f7Stbbdev 
19251c0b2f7Stbbdev template< typename T >
19351c0b2f7Stbbdev int test_parallel(int num_threads) {
19451c0b2f7Stbbdev     tbb::flow::graph g;
19551c0b2f7Stbbdev 
19651c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s(g, seq_inspector<T>());
19751c0b2f7Stbbdev     utils::NativeParallelFor( num_threads, parallel_puts<T>(s, num_threads) );
19851c0b2f7Stbbdev     {
19951c0b2f7Stbbdev         touches<T> t( num_threads );
20051c0b2f7Stbbdev         utils::NativeParallelFor( num_threads, parallel_gets<T>(s, num_threads, t) );
20151c0b2f7Stbbdev         g.wait_for_all();
20251c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
20351c0b2f7Stbbdev     }
20451c0b2f7Stbbdev     T bogus_value(-1);
20551c0b2f7Stbbdev     T j = bogus_value;
20651c0b2f7Stbbdev     CHECK_MESSAGE( s.try_get( j ) == false, "" );
20751c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
20851c0b2f7Stbbdev     g.wait_for_all();
20951c0b2f7Stbbdev 
21051c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s1(g, seq_inspector<T>());
21151c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s2(g, seq_inspector<T>());
21251c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s3(g, seq_inspector<T>());
21351c0b2f7Stbbdev     tbb::flow::make_edge( s1, s2 );
21451c0b2f7Stbbdev     tbb::flow::make_edge( s2, s3 );
21551c0b2f7Stbbdev 
21651c0b2f7Stbbdev     {
21751c0b2f7Stbbdev         touches<T> t( num_threads );
21851c0b2f7Stbbdev         std::atomic<int> counter;
21951c0b2f7Stbbdev         counter = 0;
22051c0b2f7Stbbdev         utils::NativeParallelFor( num_threads, parallel_put_get<T>(s1, s3, num_threads, counter, t) );
22151c0b2f7Stbbdev         g.wait_for_all();
22251c0b2f7Stbbdev         t.validate_touches();
22351c0b2f7Stbbdev     }
22451c0b2f7Stbbdev     g.wait_for_all();
22551c0b2f7Stbbdev     CHECK_MESSAGE( s1.try_get( j ) == false, "" );
22651c0b2f7Stbbdev     g.wait_for_all();
22751c0b2f7Stbbdev     CHECK_MESSAGE( s2.try_get( j ) == false, "" );
22851c0b2f7Stbbdev     g.wait_for_all();
22951c0b2f7Stbbdev     CHECK_MESSAGE( s3.try_get( j ) == false, "" );
23051c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
23151c0b2f7Stbbdev 
23251c0b2f7Stbbdev     // test copy constructor
23351c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s_copy(s);
23451c0b2f7Stbbdev     utils::NativeParallelFor( num_threads, parallel_puts<T>(s_copy, num_threads) );
23551c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
23651c0b2f7Stbbdev         j = bogus_value;
23751c0b2f7Stbbdev         spin_try_get( s_copy, j );
23851c0b2f7Stbbdev         CHECK_MESSAGE( i == j, "" );
23951c0b2f7Stbbdev     }
24051c0b2f7Stbbdev     j = bogus_value;
24151c0b2f7Stbbdev     g.wait_for_all();
24251c0b2f7Stbbdev     CHECK_MESSAGE( s_copy.try_get( j ) == false, "" );
24351c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
24451c0b2f7Stbbdev 
24551c0b2f7Stbbdev     return 0;
24651c0b2f7Stbbdev }
24751c0b2f7Stbbdev 
24851c0b2f7Stbbdev 
24951c0b2f7Stbbdev //
25051c0b2f7Stbbdev // Tests
25151c0b2f7Stbbdev //
25251c0b2f7Stbbdev // No predecessors can be registered
25351c0b2f7Stbbdev // Request from empty buffer fails
25451c0b2f7Stbbdev // In-order puts, single sender, single receiver, properly sequenced at output
25551c0b2f7Stbbdev // Reverse-order puts, single sender, single receiver, properly sequenced at output
25651c0b2f7Stbbdev // Chained sequencers (3), in-order and reverse-order tests, properly sequenced at output
25751c0b2f7Stbbdev //
25851c0b2f7Stbbdev 
25951c0b2f7Stbbdev template< typename T >
26051c0b2f7Stbbdev int test_serial() {
26151c0b2f7Stbbdev     tbb::flow::graph g;
26251c0b2f7Stbbdev     T bogus_value(-1);
26351c0b2f7Stbbdev 
26451c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s(g, seq_inspector<T>());
26551c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s2(g, seq_inspector<T>());
26651c0b2f7Stbbdev     T j = bogus_value;
26751c0b2f7Stbbdev 
26851c0b2f7Stbbdev     //
26951c0b2f7Stbbdev     // Rejects attempts to add / remove predecessor
27051c0b2f7Stbbdev     // Rejects request from empty Q
27151c0b2f7Stbbdev     //
27251c0b2f7Stbbdev     CHECK_MESSAGE( register_predecessor( s, s2 ) == false, "" );
27351c0b2f7Stbbdev     CHECK_MESSAGE( remove_predecessor( s, s2 ) == false, "" );
27451c0b2f7Stbbdev     CHECK_MESSAGE( s.try_get( j ) == false, "" );
27551c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
27651c0b2f7Stbbdev 
27751c0b2f7Stbbdev     //
27851c0b2f7Stbbdev     // In-order simple puts and gets
27951c0b2f7Stbbdev     //
28051c0b2f7Stbbdev 
28151c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
28251c0b2f7Stbbdev         bool msg = s.try_put( T(i) );
28351c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
28451c0b2f7Stbbdev         CHECK_MESSAGE(!s.try_put( T(i) ), "");  // second attempt to put should reject
28551c0b2f7Stbbdev     }
28651c0b2f7Stbbdev 
28751c0b2f7Stbbdev 
28851c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
28951c0b2f7Stbbdev         j = bogus_value;
29051c0b2f7Stbbdev         CHECK_MESSAGE(wait_try_get( g, s, j ) == true, "");
29151c0b2f7Stbbdev         CHECK_MESSAGE( i == j, "" );
29251c0b2f7Stbbdev         CHECK_MESSAGE(!s.try_put( T(i) ),"" );  // after retrieving value, subsequent put should fail
29351c0b2f7Stbbdev     }
29451c0b2f7Stbbdev     j = bogus_value;
29551c0b2f7Stbbdev     g.wait_for_all();
29651c0b2f7Stbbdev     CHECK_MESSAGE( s.try_get( j ) == false, "" );
29751c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
29851c0b2f7Stbbdev 
29951c0b2f7Stbbdev     //
30051c0b2f7Stbbdev     // Reverse-order simple puts and gets
30151c0b2f7Stbbdev     //
30251c0b2f7Stbbdev 
30351c0b2f7Stbbdev     for (int i = N-1; i >= 0; --i) {
30451c0b2f7Stbbdev         bool msg = s2.try_put( T(i) );
30551c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
30651c0b2f7Stbbdev     }
30751c0b2f7Stbbdev 
30851c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
30951c0b2f7Stbbdev         j = bogus_value;
31051c0b2f7Stbbdev         CHECK_MESSAGE(wait_try_get( g, s2, j ) == true, "");
31151c0b2f7Stbbdev         CHECK_MESSAGE( i == j, "" );
31251c0b2f7Stbbdev     }
31351c0b2f7Stbbdev     j = bogus_value;
31451c0b2f7Stbbdev     g.wait_for_all();
31551c0b2f7Stbbdev     CHECK_MESSAGE( s2.try_get( j ) == false, "" );
31651c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
31751c0b2f7Stbbdev 
31851c0b2f7Stbbdev     //
31951c0b2f7Stbbdev     // Chained in-order simple puts and gets
32051c0b2f7Stbbdev     //
32151c0b2f7Stbbdev 
32251c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s3(g, seq_inspector<T>());
32351c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s4(g, seq_inspector<T>());
32451c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s5(g, seq_inspector<T>());
32551c0b2f7Stbbdev     tbb::flow::make_edge( s3, s4 );
32651c0b2f7Stbbdev     tbb::flow::make_edge( s4, s5 );
32751c0b2f7Stbbdev 
32851c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
32951c0b2f7Stbbdev         bool msg = s3.try_put( T(i) );
33051c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
33151c0b2f7Stbbdev     }
33251c0b2f7Stbbdev 
33351c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
33451c0b2f7Stbbdev         j = bogus_value;
33551c0b2f7Stbbdev         CHECK_MESSAGE(wait_try_get( g, s5, j ) == true, "");
33651c0b2f7Stbbdev         CHECK_MESSAGE( i == j, "" );
33751c0b2f7Stbbdev     }
33851c0b2f7Stbbdev     j = bogus_value;
33951c0b2f7Stbbdev     CHECK_MESSAGE( wait_try_get( g, s3, j ) == false, "" );
34051c0b2f7Stbbdev     CHECK_MESSAGE( wait_try_get( g, s4, j ) == false, "" );
34151c0b2f7Stbbdev     CHECK_MESSAGE( wait_try_get( g, s5, j ) == false, "" );
34251c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
34351c0b2f7Stbbdev 
34451c0b2f7Stbbdev     g.wait_for_all();
34551c0b2f7Stbbdev     tbb::flow::remove_edge( s3, s4 );
34651c0b2f7Stbbdev     CHECK_MESSAGE( s3.try_put( N ) == true, "" );
34751c0b2f7Stbbdev     CHECK_MESSAGE( wait_try_get( g, s4, j ) == false, "" );
34851c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
34951c0b2f7Stbbdev     CHECK_MESSAGE( wait_try_get( g, s5, j ) == false, "" );
35051c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
35151c0b2f7Stbbdev     CHECK_MESSAGE( wait_try_get( g, s3, j ) == true, "" );
35251c0b2f7Stbbdev     CHECK_MESSAGE( j == N, "" );
35351c0b2f7Stbbdev 
35451c0b2f7Stbbdev     //
35551c0b2f7Stbbdev     // Chained reverse-order simple puts and gets
35651c0b2f7Stbbdev     //
35751c0b2f7Stbbdev 
35851c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s6(g, seq_inspector<T>());
35951c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s7(g, seq_inspector<T>());
36051c0b2f7Stbbdev     tbb::flow::sequencer_node<T> s8(g, seq_inspector<T>());
36151c0b2f7Stbbdev     tbb::flow::make_edge( s6, s7 );
36251c0b2f7Stbbdev     tbb::flow::make_edge( s7, s8 );
36351c0b2f7Stbbdev 
36451c0b2f7Stbbdev     for (int i = N-1; i >= 0; --i) {
36551c0b2f7Stbbdev         bool msg = s6.try_put( T(i) );
36651c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
36751c0b2f7Stbbdev     }
36851c0b2f7Stbbdev 
36951c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
37051c0b2f7Stbbdev         j = bogus_value;
37151c0b2f7Stbbdev         CHECK_MESSAGE( wait_try_get( g, s8, j ) == true, "" );
37251c0b2f7Stbbdev         CHECK_MESSAGE( i == j, "" );
37351c0b2f7Stbbdev     }
37451c0b2f7Stbbdev     j = bogus_value;
37551c0b2f7Stbbdev     CHECK_MESSAGE( wait_try_get( g, s6, j ) == false, "" );
37651c0b2f7Stbbdev     CHECK_MESSAGE( wait_try_get( g, s7, j ) == false, "" );
37751c0b2f7Stbbdev     CHECK_MESSAGE( wait_try_get( g, s8, j ) == false, "" );
37851c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
37951c0b2f7Stbbdev 
38051c0b2f7Stbbdev     g.wait_for_all();
38151c0b2f7Stbbdev     tbb::flow::remove_edge( s6, s7 );
38251c0b2f7Stbbdev     CHECK_MESSAGE( s6.try_put( N ) == true, "" );
38351c0b2f7Stbbdev     CHECK_MESSAGE( wait_try_get( g, s7, j ) == false, "" );
38451c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
38551c0b2f7Stbbdev     CHECK_MESSAGE( wait_try_get( g, s8, j ) == false, "" );
38651c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
38751c0b2f7Stbbdev     CHECK_MESSAGE( wait_try_get( g, s6, j ) == true, "" );
38851c0b2f7Stbbdev     CHECK_MESSAGE( j == N, "" );
38951c0b2f7Stbbdev 
39051c0b2f7Stbbdev     return 0;
39151c0b2f7Stbbdev }
39251c0b2f7Stbbdev 
39351c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
39451c0b2f7Stbbdev #include <array>
39551c0b2f7Stbbdev #include <vector>
39651c0b2f7Stbbdev void test_follows_and_precedes_api() {
39751c0b2f7Stbbdev     std::array<int, 3> messages_for_follows = { {0, 1, 2} };
39851c0b2f7Stbbdev     std::vector<int> messages_for_precedes = {0, 1, 2};
39951c0b2f7Stbbdev 
40051c0b2f7Stbbdev     follows_and_precedes_testing::test_follows
40151c0b2f7Stbbdev         <int, tbb::flow::sequencer_node<int>>
40251c0b2f7Stbbdev         (messages_for_follows, [](const int& i) { return i; });
40351c0b2f7Stbbdev 
40451c0b2f7Stbbdev     follows_and_precedes_testing::test_precedes
40551c0b2f7Stbbdev         <int, tbb::flow::sequencer_node<int>>
40651c0b2f7Stbbdev         (messages_for_precedes, [](const int& i) { return i; });
40751c0b2f7Stbbdev }
40851c0b2f7Stbbdev #endif
40951c0b2f7Stbbdev 
41051c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
41151c0b2f7Stbbdev template <typename Body>
41251c0b2f7Stbbdev void test_deduction_guides_common(Body body) {
41351c0b2f7Stbbdev     using namespace tbb::flow;
41451c0b2f7Stbbdev     graph g;
41551c0b2f7Stbbdev     broadcast_node<int> br(g);
41651c0b2f7Stbbdev 
41751c0b2f7Stbbdev     sequencer_node s1(g, body);
41851c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(s1), sequencer_node<int>>);
41951c0b2f7Stbbdev 
42051c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
42151c0b2f7Stbbdev     sequencer_node s2(follows(br), body);
42251c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(s2), sequencer_node<int>>);
42351c0b2f7Stbbdev #endif
42451c0b2f7Stbbdev 
42551c0b2f7Stbbdev     sequencer_node s3(s1);
42651c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(s3), sequencer_node<int>>);
42751c0b2f7Stbbdev }
42851c0b2f7Stbbdev 
42951c0b2f7Stbbdev int sequencer_body_f(const int&) { return 1; }
43051c0b2f7Stbbdev 
43151c0b2f7Stbbdev void test_deduction_guides() {
43251c0b2f7Stbbdev     test_deduction_guides_common([](const int&)->int { return 1; });
43351c0b2f7Stbbdev     test_deduction_guides_common([](const int&) mutable ->int { return 1; });
43451c0b2f7Stbbdev     test_deduction_guides_common(sequencer_body_f);
43551c0b2f7Stbbdev }
43651c0b2f7Stbbdev #endif
43751c0b2f7Stbbdev 
43851c0b2f7Stbbdev //! Test sequencer with various request orders and parallelism levels
43951c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing
44051c0b2f7Stbbdev TEST_CASE("Serial and parallel test"){
44151c0b2f7Stbbdev     for (int p = 2; p <= 4; ++p) {
44251c0b2f7Stbbdev         tbb::task_arena arena(p);
44351c0b2f7Stbbdev         arena.execute(
44451c0b2f7Stbbdev             [&]() {
44551c0b2f7Stbbdev 
44651c0b2f7Stbbdev                 test_serial<int>();
44751c0b2f7Stbbdev                 test_parallel<int>(p);
44851c0b2f7Stbbdev 
44951c0b2f7Stbbdev             }
45051c0b2f7Stbbdev         );
45151c0b2f7Stbbdev 	}
45251c0b2f7Stbbdev }
45351c0b2f7Stbbdev 
45451c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
45551c0b2f7Stbbdev //! Test decution guides
45651c0b2f7Stbbdev //! \brief \ref requirement
45751c0b2f7Stbbdev TEST_CASE("Test follows and precedes API"){
45851c0b2f7Stbbdev     test_follows_and_precedes_api();
45951c0b2f7Stbbdev }
46051c0b2f7Stbbdev #endif
46151c0b2f7Stbbdev 
46251c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
46351c0b2f7Stbbdev //! Test decution guides
46451c0b2f7Stbbdev //! \brief \ref requirement
46551c0b2f7Stbbdev TEST_CASE("Test deduction guides"){
46651c0b2f7Stbbdev     test_deduction_guides();
46751c0b2f7Stbbdev }
46851c0b2f7Stbbdev #endif
469