1*51c0b2f7Stbbdev /* 2*51c0b2f7Stbbdev Copyright (c) 2005-2020 Intel Corporation 3*51c0b2f7Stbbdev 4*51c0b2f7Stbbdev Licensed under the Apache License, Version 2.0 (the "License"); 5*51c0b2f7Stbbdev you may not use this file except in compliance with the License. 6*51c0b2f7Stbbdev You may obtain a copy of the License at 7*51c0b2f7Stbbdev 8*51c0b2f7Stbbdev http://www.apache.org/licenses/LICENSE-2.0 9*51c0b2f7Stbbdev 10*51c0b2f7Stbbdev Unless required by applicable law or agreed to in writing, software 11*51c0b2f7Stbbdev distributed under the License is distributed on an "AS IS" BASIS, 12*51c0b2f7Stbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*51c0b2f7Stbbdev See the License for the specific language governing permissions and 14*51c0b2f7Stbbdev limitations under the License. 15*51c0b2f7Stbbdev */ 16*51c0b2f7Stbbdev 17*51c0b2f7Stbbdev #include "common/config.h" 18*51c0b2f7Stbbdev 19*51c0b2f7Stbbdev #include "tbb/flow_graph.h" 20*51c0b2f7Stbbdev 21*51c0b2f7Stbbdev #include "common/test.h" 22*51c0b2f7Stbbdev #include "common/utils.h" 23*51c0b2f7Stbbdev #include "common/utils_assert.h" 24*51c0b2f7Stbbdev #include "common/test_follows_and_precedes_api.h" 25*51c0b2f7Stbbdev 26*51c0b2f7Stbbdev #include <cstdio> 27*51c0b2f7Stbbdev #include <atomic> 28*51c0b2f7Stbbdev 29*51c0b2f7Stbbdev 30*51c0b2f7Stbbdev //! \file test_sequencer_node.cpp 31*51c0b2f7Stbbdev //! \brief Test for [flow_graph.sequencer_node] specification 32*51c0b2f7Stbbdev 33*51c0b2f7Stbbdev 34*51c0b2f7Stbbdev #define N 1000 35*51c0b2f7Stbbdev #define C 10 36*51c0b2f7Stbbdev 37*51c0b2f7Stbbdev template< typename T > 38*51c0b2f7Stbbdev struct seq_inspector { 39*51c0b2f7Stbbdev size_t operator()(const T &v) const { return size_t(v); } 40*51c0b2f7Stbbdev }; 41*51c0b2f7Stbbdev 42*51c0b2f7Stbbdev template< typename T > 43*51c0b2f7Stbbdev bool wait_try_get( tbb::flow::graph &g, tbb::flow::sequencer_node<T> &q, T &value ) { 44*51c0b2f7Stbbdev g.wait_for_all(); 45*51c0b2f7Stbbdev return q.try_get(value); 46*51c0b2f7Stbbdev } 47*51c0b2f7Stbbdev 48*51c0b2f7Stbbdev template< typename T > 49*51c0b2f7Stbbdev void spin_try_get( tbb::flow::queue_node<T> &q, T &value ) { 50*51c0b2f7Stbbdev while ( q.try_get(value) != true ) ; 51*51c0b2f7Stbbdev } 52*51c0b2f7Stbbdev 53*51c0b2f7Stbbdev template< typename T > 54*51c0b2f7Stbbdev struct parallel_puts : utils::NoAssign { 55*51c0b2f7Stbbdev 56*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> &my_q; 57*51c0b2f7Stbbdev int my_num_threads; 58*51c0b2f7Stbbdev 59*51c0b2f7Stbbdev parallel_puts( tbb::flow::sequencer_node<T> &q, int num_threads ) : my_q(q), my_num_threads(num_threads) {} 60*51c0b2f7Stbbdev 61*51c0b2f7Stbbdev void operator()(int tid) const { 62*51c0b2f7Stbbdev for (int j = tid; j < N; j+=my_num_threads) { 63*51c0b2f7Stbbdev bool msg = my_q.try_put( T(j) ); 64*51c0b2f7Stbbdev CHECK_MESSAGE( msg == true, "" ); 65*51c0b2f7Stbbdev } 66*51c0b2f7Stbbdev } 67*51c0b2f7Stbbdev 68*51c0b2f7Stbbdev }; 69*51c0b2f7Stbbdev 70*51c0b2f7Stbbdev template< typename T > 71*51c0b2f7Stbbdev struct touches { 72*51c0b2f7Stbbdev 73*51c0b2f7Stbbdev bool **my_touches; 74*51c0b2f7Stbbdev T *my_last_touch; 75*51c0b2f7Stbbdev int my_num_threads; 76*51c0b2f7Stbbdev 77*51c0b2f7Stbbdev touches( int num_threads ) : my_num_threads(num_threads) { 78*51c0b2f7Stbbdev my_last_touch = new T[my_num_threads]; 79*51c0b2f7Stbbdev my_touches = new bool* [my_num_threads]; 80*51c0b2f7Stbbdev for ( int p = 0; p < my_num_threads; ++p) { 81*51c0b2f7Stbbdev my_last_touch[p] = T(-1); 82*51c0b2f7Stbbdev my_touches[p] = new bool[N]; 83*51c0b2f7Stbbdev for ( int n = 0; n < N; ++n) 84*51c0b2f7Stbbdev my_touches[p][n] = false; 85*51c0b2f7Stbbdev } 86*51c0b2f7Stbbdev } 87*51c0b2f7Stbbdev 88*51c0b2f7Stbbdev ~touches() { 89*51c0b2f7Stbbdev for ( int p = 0; p < my_num_threads; ++p) { 90*51c0b2f7Stbbdev delete [] my_touches[p]; 91*51c0b2f7Stbbdev } 92*51c0b2f7Stbbdev delete [] my_touches; 93*51c0b2f7Stbbdev delete [] my_last_touch; 94*51c0b2f7Stbbdev } 95*51c0b2f7Stbbdev 96*51c0b2f7Stbbdev bool check( int tid, T v ) { 97*51c0b2f7Stbbdev if ( my_touches[tid][v] != false ) { 98*51c0b2f7Stbbdev printf("Error: value seen twice by local thread\n"); 99*51c0b2f7Stbbdev return false; 100*51c0b2f7Stbbdev } 101*51c0b2f7Stbbdev if ( v <= my_last_touch[tid] ) { 102*51c0b2f7Stbbdev printf("Error: value seen in wrong order by local thread\n"); 103*51c0b2f7Stbbdev return false; 104*51c0b2f7Stbbdev } 105*51c0b2f7Stbbdev my_last_touch[tid] = v; 106*51c0b2f7Stbbdev my_touches[tid][v] = true; 107*51c0b2f7Stbbdev return true; 108*51c0b2f7Stbbdev } 109*51c0b2f7Stbbdev 110*51c0b2f7Stbbdev bool validate_touches() { 111*51c0b2f7Stbbdev bool *all_touches = new bool[N]; 112*51c0b2f7Stbbdev for ( int n = 0; n < N; ++n) 113*51c0b2f7Stbbdev all_touches[n] = false; 114*51c0b2f7Stbbdev 115*51c0b2f7Stbbdev for ( int p = 0; p < my_num_threads; ++p) { 116*51c0b2f7Stbbdev for ( int n = 0; n < N; ++n) { 117*51c0b2f7Stbbdev if ( my_touches[p][n] == true ) { 118*51c0b2f7Stbbdev CHECK_MESSAGE( ( all_touches[n] == false), "value see by more than one thread\n" ); 119*51c0b2f7Stbbdev all_touches[n] = true; 120*51c0b2f7Stbbdev } 121*51c0b2f7Stbbdev } 122*51c0b2f7Stbbdev } 123*51c0b2f7Stbbdev for ( int n = 0; n < N; ++n) { 124*51c0b2f7Stbbdev if ( !all_touches[n] ) 125*51c0b2f7Stbbdev printf("No touch at %d, my_num_threads = %d\n", n, my_num_threads); 126*51c0b2f7Stbbdev //CHECK_MESSAGE( ( all_touches[n] == true), "value not seen by any thread\n" ); 127*51c0b2f7Stbbdev } 128*51c0b2f7Stbbdev delete [] all_touches; 129*51c0b2f7Stbbdev return true; 130*51c0b2f7Stbbdev } 131*51c0b2f7Stbbdev 132*51c0b2f7Stbbdev }; 133*51c0b2f7Stbbdev 134*51c0b2f7Stbbdev template< typename T > 135*51c0b2f7Stbbdev struct parallel_gets : utils::NoAssign { 136*51c0b2f7Stbbdev 137*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> &my_q; 138*51c0b2f7Stbbdev int my_num_threads; 139*51c0b2f7Stbbdev touches<T> &my_touches; 140*51c0b2f7Stbbdev 141*51c0b2f7Stbbdev 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) {} 142*51c0b2f7Stbbdev 143*51c0b2f7Stbbdev void operator()(int tid) const { 144*51c0b2f7Stbbdev for (int j = tid; j < N; j+=my_num_threads) { 145*51c0b2f7Stbbdev T v; 146*51c0b2f7Stbbdev spin_try_get( my_q, v ); 147*51c0b2f7Stbbdev my_touches.check( tid, v ); 148*51c0b2f7Stbbdev } 149*51c0b2f7Stbbdev } 150*51c0b2f7Stbbdev 151*51c0b2f7Stbbdev }; 152*51c0b2f7Stbbdev 153*51c0b2f7Stbbdev template< typename T > 154*51c0b2f7Stbbdev struct parallel_put_get : utils::NoAssign { 155*51c0b2f7Stbbdev 156*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> &my_s1; 157*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> &my_s2; 158*51c0b2f7Stbbdev int my_num_threads; 159*51c0b2f7Stbbdev std::atomic< int > &my_counter; 160*51c0b2f7Stbbdev touches<T> &my_touches; 161*51c0b2f7Stbbdev 162*51c0b2f7Stbbdev parallel_put_get( tbb::flow::sequencer_node<T> &s1, tbb::flow::sequencer_node<T> &s2, int num_threads, 163*51c0b2f7Stbbdev std::atomic<int> &counter, touches<T> &t ) : my_s1(s1), my_s2(s2), my_num_threads(num_threads), my_counter(counter), my_touches(t) {} 164*51c0b2f7Stbbdev 165*51c0b2f7Stbbdev void operator()(int tid) const { 166*51c0b2f7Stbbdev int i_start = 0; 167*51c0b2f7Stbbdev 168*51c0b2f7Stbbdev while ( (i_start = my_counter.fetch_add(C)) < N ) { 169*51c0b2f7Stbbdev int i_end = ( N < i_start + C ) ? N : i_start + C; 170*51c0b2f7Stbbdev for (int i = i_start; i < i_end; ++i) { 171*51c0b2f7Stbbdev bool msg = my_s1.try_put( T(i) ); 172*51c0b2f7Stbbdev CHECK_MESSAGE( msg == true, "" ); 173*51c0b2f7Stbbdev } 174*51c0b2f7Stbbdev 175*51c0b2f7Stbbdev for (int i = i_start; i < i_end; ++i) { 176*51c0b2f7Stbbdev T v; 177*51c0b2f7Stbbdev spin_try_get( my_s2, v ); 178*51c0b2f7Stbbdev my_touches.check( tid, v ); 179*51c0b2f7Stbbdev } 180*51c0b2f7Stbbdev } 181*51c0b2f7Stbbdev } 182*51c0b2f7Stbbdev 183*51c0b2f7Stbbdev }; 184*51c0b2f7Stbbdev 185*51c0b2f7Stbbdev // 186*51c0b2f7Stbbdev // Tests 187*51c0b2f7Stbbdev // 188*51c0b2f7Stbbdev // multiple parallel senders, multiple receivers, properly sequenced (relative to receiver) at output 189*51c0b2f7Stbbdev // chained sequencers, multiple parallel senders, multiple receivers, properly sequenced (relative to receiver) at output 190*51c0b2f7Stbbdev // 191*51c0b2f7Stbbdev 192*51c0b2f7Stbbdev template< typename T > 193*51c0b2f7Stbbdev int test_parallel(int num_threads) { 194*51c0b2f7Stbbdev tbb::flow::graph g; 195*51c0b2f7Stbbdev 196*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s(g, seq_inspector<T>()); 197*51c0b2f7Stbbdev utils::NativeParallelFor( num_threads, parallel_puts<T>(s, num_threads) ); 198*51c0b2f7Stbbdev { 199*51c0b2f7Stbbdev touches<T> t( num_threads ); 200*51c0b2f7Stbbdev utils::NativeParallelFor( num_threads, parallel_gets<T>(s, num_threads, t) ); 201*51c0b2f7Stbbdev g.wait_for_all(); 202*51c0b2f7Stbbdev CHECK_MESSAGE( t.validate_touches(), "" ); 203*51c0b2f7Stbbdev } 204*51c0b2f7Stbbdev T bogus_value(-1); 205*51c0b2f7Stbbdev T j = bogus_value; 206*51c0b2f7Stbbdev CHECK_MESSAGE( s.try_get( j ) == false, "" ); 207*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 208*51c0b2f7Stbbdev g.wait_for_all(); 209*51c0b2f7Stbbdev 210*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s1(g, seq_inspector<T>()); 211*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s2(g, seq_inspector<T>()); 212*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s3(g, seq_inspector<T>()); 213*51c0b2f7Stbbdev tbb::flow::make_edge( s1, s2 ); 214*51c0b2f7Stbbdev tbb::flow::make_edge( s2, s3 ); 215*51c0b2f7Stbbdev 216*51c0b2f7Stbbdev { 217*51c0b2f7Stbbdev touches<T> t( num_threads ); 218*51c0b2f7Stbbdev std::atomic<int> counter; 219*51c0b2f7Stbbdev counter = 0; 220*51c0b2f7Stbbdev utils::NativeParallelFor( num_threads, parallel_put_get<T>(s1, s3, num_threads, counter, t) ); 221*51c0b2f7Stbbdev g.wait_for_all(); 222*51c0b2f7Stbbdev t.validate_touches(); 223*51c0b2f7Stbbdev } 224*51c0b2f7Stbbdev g.wait_for_all(); 225*51c0b2f7Stbbdev CHECK_MESSAGE( s1.try_get( j ) == false, "" ); 226*51c0b2f7Stbbdev g.wait_for_all(); 227*51c0b2f7Stbbdev CHECK_MESSAGE( s2.try_get( j ) == false, "" ); 228*51c0b2f7Stbbdev g.wait_for_all(); 229*51c0b2f7Stbbdev CHECK_MESSAGE( s3.try_get( j ) == false, "" ); 230*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 231*51c0b2f7Stbbdev 232*51c0b2f7Stbbdev // test copy constructor 233*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s_copy(s); 234*51c0b2f7Stbbdev utils::NativeParallelFor( num_threads, parallel_puts<T>(s_copy, num_threads) ); 235*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 236*51c0b2f7Stbbdev j = bogus_value; 237*51c0b2f7Stbbdev spin_try_get( s_copy, j ); 238*51c0b2f7Stbbdev CHECK_MESSAGE( i == j, "" ); 239*51c0b2f7Stbbdev } 240*51c0b2f7Stbbdev j = bogus_value; 241*51c0b2f7Stbbdev g.wait_for_all(); 242*51c0b2f7Stbbdev CHECK_MESSAGE( s_copy.try_get( j ) == false, "" ); 243*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 244*51c0b2f7Stbbdev 245*51c0b2f7Stbbdev return 0; 246*51c0b2f7Stbbdev } 247*51c0b2f7Stbbdev 248*51c0b2f7Stbbdev 249*51c0b2f7Stbbdev // 250*51c0b2f7Stbbdev // Tests 251*51c0b2f7Stbbdev // 252*51c0b2f7Stbbdev // No predecessors can be registered 253*51c0b2f7Stbbdev // Request from empty buffer fails 254*51c0b2f7Stbbdev // In-order puts, single sender, single receiver, properly sequenced at output 255*51c0b2f7Stbbdev // Reverse-order puts, single sender, single receiver, properly sequenced at output 256*51c0b2f7Stbbdev // Chained sequencers (3), in-order and reverse-order tests, properly sequenced at output 257*51c0b2f7Stbbdev // 258*51c0b2f7Stbbdev 259*51c0b2f7Stbbdev template< typename T > 260*51c0b2f7Stbbdev int test_serial() { 261*51c0b2f7Stbbdev tbb::flow::graph g; 262*51c0b2f7Stbbdev T bogus_value(-1); 263*51c0b2f7Stbbdev 264*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s(g, seq_inspector<T>()); 265*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s2(g, seq_inspector<T>()); 266*51c0b2f7Stbbdev T j = bogus_value; 267*51c0b2f7Stbbdev 268*51c0b2f7Stbbdev // 269*51c0b2f7Stbbdev // Rejects attempts to add / remove predecessor 270*51c0b2f7Stbbdev // Rejects request from empty Q 271*51c0b2f7Stbbdev // 272*51c0b2f7Stbbdev CHECK_MESSAGE( register_predecessor( s, s2 ) == false, "" ); 273*51c0b2f7Stbbdev CHECK_MESSAGE( remove_predecessor( s, s2 ) == false, "" ); 274*51c0b2f7Stbbdev CHECK_MESSAGE( s.try_get( j ) == false, "" ); 275*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 276*51c0b2f7Stbbdev 277*51c0b2f7Stbbdev // 278*51c0b2f7Stbbdev // In-order simple puts and gets 279*51c0b2f7Stbbdev // 280*51c0b2f7Stbbdev 281*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 282*51c0b2f7Stbbdev bool msg = s.try_put( T(i) ); 283*51c0b2f7Stbbdev CHECK_MESSAGE( msg == true, "" ); 284*51c0b2f7Stbbdev CHECK_MESSAGE(!s.try_put( T(i) ), ""); // second attempt to put should reject 285*51c0b2f7Stbbdev } 286*51c0b2f7Stbbdev 287*51c0b2f7Stbbdev 288*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 289*51c0b2f7Stbbdev j = bogus_value; 290*51c0b2f7Stbbdev CHECK_MESSAGE(wait_try_get( g, s, j ) == true, ""); 291*51c0b2f7Stbbdev CHECK_MESSAGE( i == j, "" ); 292*51c0b2f7Stbbdev CHECK_MESSAGE(!s.try_put( T(i) ),"" ); // after retrieving value, subsequent put should fail 293*51c0b2f7Stbbdev } 294*51c0b2f7Stbbdev j = bogus_value; 295*51c0b2f7Stbbdev g.wait_for_all(); 296*51c0b2f7Stbbdev CHECK_MESSAGE( s.try_get( j ) == false, "" ); 297*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 298*51c0b2f7Stbbdev 299*51c0b2f7Stbbdev // 300*51c0b2f7Stbbdev // Reverse-order simple puts and gets 301*51c0b2f7Stbbdev // 302*51c0b2f7Stbbdev 303*51c0b2f7Stbbdev for (int i = N-1; i >= 0; --i) { 304*51c0b2f7Stbbdev bool msg = s2.try_put( T(i) ); 305*51c0b2f7Stbbdev CHECK_MESSAGE( msg == true, "" ); 306*51c0b2f7Stbbdev } 307*51c0b2f7Stbbdev 308*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 309*51c0b2f7Stbbdev j = bogus_value; 310*51c0b2f7Stbbdev CHECK_MESSAGE(wait_try_get( g, s2, j ) == true, ""); 311*51c0b2f7Stbbdev CHECK_MESSAGE( i == j, "" ); 312*51c0b2f7Stbbdev } 313*51c0b2f7Stbbdev j = bogus_value; 314*51c0b2f7Stbbdev g.wait_for_all(); 315*51c0b2f7Stbbdev CHECK_MESSAGE( s2.try_get( j ) == false, "" ); 316*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 317*51c0b2f7Stbbdev 318*51c0b2f7Stbbdev // 319*51c0b2f7Stbbdev // Chained in-order simple puts and gets 320*51c0b2f7Stbbdev // 321*51c0b2f7Stbbdev 322*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s3(g, seq_inspector<T>()); 323*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s4(g, seq_inspector<T>()); 324*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s5(g, seq_inspector<T>()); 325*51c0b2f7Stbbdev tbb::flow::make_edge( s3, s4 ); 326*51c0b2f7Stbbdev tbb::flow::make_edge( s4, s5 ); 327*51c0b2f7Stbbdev 328*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 329*51c0b2f7Stbbdev bool msg = s3.try_put( T(i) ); 330*51c0b2f7Stbbdev CHECK_MESSAGE( msg == true, "" ); 331*51c0b2f7Stbbdev } 332*51c0b2f7Stbbdev 333*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 334*51c0b2f7Stbbdev j = bogus_value; 335*51c0b2f7Stbbdev CHECK_MESSAGE(wait_try_get( g, s5, j ) == true, ""); 336*51c0b2f7Stbbdev CHECK_MESSAGE( i == j, "" ); 337*51c0b2f7Stbbdev } 338*51c0b2f7Stbbdev j = bogus_value; 339*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s3, j ) == false, "" ); 340*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s4, j ) == false, "" ); 341*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s5, j ) == false, "" ); 342*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 343*51c0b2f7Stbbdev 344*51c0b2f7Stbbdev g.wait_for_all(); 345*51c0b2f7Stbbdev tbb::flow::remove_edge( s3, s4 ); 346*51c0b2f7Stbbdev CHECK_MESSAGE( s3.try_put( N ) == true, "" ); 347*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s4, j ) == false, "" ); 348*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 349*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s5, j ) == false, "" ); 350*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 351*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s3, j ) == true, "" ); 352*51c0b2f7Stbbdev CHECK_MESSAGE( j == N, "" ); 353*51c0b2f7Stbbdev 354*51c0b2f7Stbbdev // 355*51c0b2f7Stbbdev // Chained reverse-order simple puts and gets 356*51c0b2f7Stbbdev // 357*51c0b2f7Stbbdev 358*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s6(g, seq_inspector<T>()); 359*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s7(g, seq_inspector<T>()); 360*51c0b2f7Stbbdev tbb::flow::sequencer_node<T> s8(g, seq_inspector<T>()); 361*51c0b2f7Stbbdev tbb::flow::make_edge( s6, s7 ); 362*51c0b2f7Stbbdev tbb::flow::make_edge( s7, s8 ); 363*51c0b2f7Stbbdev 364*51c0b2f7Stbbdev for (int i = N-1; i >= 0; --i) { 365*51c0b2f7Stbbdev bool msg = s6.try_put( T(i) ); 366*51c0b2f7Stbbdev CHECK_MESSAGE( msg == true, "" ); 367*51c0b2f7Stbbdev } 368*51c0b2f7Stbbdev 369*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 370*51c0b2f7Stbbdev j = bogus_value; 371*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s8, j ) == true, "" ); 372*51c0b2f7Stbbdev CHECK_MESSAGE( i == j, "" ); 373*51c0b2f7Stbbdev } 374*51c0b2f7Stbbdev j = bogus_value; 375*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s6, j ) == false, "" ); 376*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s7, j ) == false, "" ); 377*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s8, j ) == false, "" ); 378*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 379*51c0b2f7Stbbdev 380*51c0b2f7Stbbdev g.wait_for_all(); 381*51c0b2f7Stbbdev tbb::flow::remove_edge( s6, s7 ); 382*51c0b2f7Stbbdev CHECK_MESSAGE( s6.try_put( N ) == true, "" ); 383*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s7, j ) == false, "" ); 384*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 385*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s8, j ) == false, "" ); 386*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 387*51c0b2f7Stbbdev CHECK_MESSAGE( wait_try_get( g, s6, j ) == true, "" ); 388*51c0b2f7Stbbdev CHECK_MESSAGE( j == N, "" ); 389*51c0b2f7Stbbdev 390*51c0b2f7Stbbdev return 0; 391*51c0b2f7Stbbdev } 392*51c0b2f7Stbbdev 393*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 394*51c0b2f7Stbbdev #include <array> 395*51c0b2f7Stbbdev #include <vector> 396*51c0b2f7Stbbdev void test_follows_and_precedes_api() { 397*51c0b2f7Stbbdev std::array<int, 3> messages_for_follows = { {0, 1, 2} }; 398*51c0b2f7Stbbdev std::vector<int> messages_for_precedes = {0, 1, 2}; 399*51c0b2f7Stbbdev 400*51c0b2f7Stbbdev follows_and_precedes_testing::test_follows 401*51c0b2f7Stbbdev <int, tbb::flow::sequencer_node<int>> 402*51c0b2f7Stbbdev (messages_for_follows, [](const int& i) { return i; }); 403*51c0b2f7Stbbdev 404*51c0b2f7Stbbdev follows_and_precedes_testing::test_precedes 405*51c0b2f7Stbbdev <int, tbb::flow::sequencer_node<int>> 406*51c0b2f7Stbbdev (messages_for_precedes, [](const int& i) { return i; }); 407*51c0b2f7Stbbdev } 408*51c0b2f7Stbbdev #endif 409*51c0b2f7Stbbdev 410*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 411*51c0b2f7Stbbdev template <typename Body> 412*51c0b2f7Stbbdev void test_deduction_guides_common(Body body) { 413*51c0b2f7Stbbdev using namespace tbb::flow; 414*51c0b2f7Stbbdev graph g; 415*51c0b2f7Stbbdev broadcast_node<int> br(g); 416*51c0b2f7Stbbdev 417*51c0b2f7Stbbdev sequencer_node s1(g, body); 418*51c0b2f7Stbbdev static_assert(std::is_same_v<decltype(s1), sequencer_node<int>>); 419*51c0b2f7Stbbdev 420*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 421*51c0b2f7Stbbdev sequencer_node s2(follows(br), body); 422*51c0b2f7Stbbdev static_assert(std::is_same_v<decltype(s2), sequencer_node<int>>); 423*51c0b2f7Stbbdev #endif 424*51c0b2f7Stbbdev 425*51c0b2f7Stbbdev sequencer_node s3(s1); 426*51c0b2f7Stbbdev static_assert(std::is_same_v<decltype(s3), sequencer_node<int>>); 427*51c0b2f7Stbbdev } 428*51c0b2f7Stbbdev 429*51c0b2f7Stbbdev int sequencer_body_f(const int&) { return 1; } 430*51c0b2f7Stbbdev 431*51c0b2f7Stbbdev void test_deduction_guides() { 432*51c0b2f7Stbbdev test_deduction_guides_common([](const int&)->int { return 1; }); 433*51c0b2f7Stbbdev test_deduction_guides_common([](const int&) mutable ->int { return 1; }); 434*51c0b2f7Stbbdev test_deduction_guides_common(sequencer_body_f); 435*51c0b2f7Stbbdev } 436*51c0b2f7Stbbdev #endif 437*51c0b2f7Stbbdev 438*51c0b2f7Stbbdev //! Test sequencer with various request orders and parallelism levels 439*51c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing 440*51c0b2f7Stbbdev TEST_CASE("Serial and parallel test"){ 441*51c0b2f7Stbbdev for (int p = 2; p <= 4; ++p) { 442*51c0b2f7Stbbdev tbb::task_arena arena(p); 443*51c0b2f7Stbbdev arena.execute( 444*51c0b2f7Stbbdev [&]() { 445*51c0b2f7Stbbdev 446*51c0b2f7Stbbdev test_serial<int>(); 447*51c0b2f7Stbbdev test_parallel<int>(p); 448*51c0b2f7Stbbdev 449*51c0b2f7Stbbdev } 450*51c0b2f7Stbbdev ); 451*51c0b2f7Stbbdev } 452*51c0b2f7Stbbdev } 453*51c0b2f7Stbbdev 454*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 455*51c0b2f7Stbbdev //! Test decution guides 456*51c0b2f7Stbbdev //! \brief \ref requirement 457*51c0b2f7Stbbdev TEST_CASE("Test follows and precedes API"){ 458*51c0b2f7Stbbdev test_follows_and_precedes_api(); 459*51c0b2f7Stbbdev } 460*51c0b2f7Stbbdev #endif 461*51c0b2f7Stbbdev 462*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 463*51c0b2f7Stbbdev //! Test decution guides 464*51c0b2f7Stbbdev //! \brief \ref requirement 465*51c0b2f7Stbbdev TEST_CASE("Test deduction guides"){ 466*51c0b2f7Stbbdev test_deduction_guides(); 467*51c0b2f7Stbbdev } 468*51c0b2f7Stbbdev #endif 469