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