xref: /oneTBB/test/tbb/test_sequencer_node.cpp (revision 51c0b2f7)
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