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