xref: /oneTBB/test/tbb/test_buffer_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 // TODO revamp: move parts dependent on __TBB_EXTRA_DEBUG into separate test(s) since having these
20*51c0b2f7Stbbdev // parts in all of tests might make testing of the product, which is different from what is actually
21*51c0b2f7Stbbdev // released.
22*51c0b2f7Stbbdev #define __TBB_EXTRA_DEBUG 1
23*51c0b2f7Stbbdev #include "tbb/flow_graph.h"
24*51c0b2f7Stbbdev 
25*51c0b2f7Stbbdev #include "common/test.h"
26*51c0b2f7Stbbdev #include "common/utils.h"
27*51c0b2f7Stbbdev #include "common/graph_utils.h"
28*51c0b2f7Stbbdev #include "common/test_follows_and_precedes_api.h"
29*51c0b2f7Stbbdev 
30*51c0b2f7Stbbdev 
31*51c0b2f7Stbbdev //! \file test_buffer_node.cpp
32*51c0b2f7Stbbdev //! \brief Test for [flow_graph.buffer_node] specification
33*51c0b2f7Stbbdev 
34*51c0b2f7Stbbdev 
35*51c0b2f7Stbbdev #define N 1000
36*51c0b2f7Stbbdev #define C 10
37*51c0b2f7Stbbdev 
38*51c0b2f7Stbbdev template< typename T >
39*51c0b2f7Stbbdev void spin_try_get( tbb::flow::buffer_node<T> &b, T &value ) {
40*51c0b2f7Stbbdev     while ( b.try_get(value) != true ) {}
41*51c0b2f7Stbbdev }
42*51c0b2f7Stbbdev 
43*51c0b2f7Stbbdev template< typename T >
44*51c0b2f7Stbbdev void check_item( T* count_value, T &value ) {
45*51c0b2f7Stbbdev     count_value[value / N] += value % N;
46*51c0b2f7Stbbdev }
47*51c0b2f7Stbbdev 
48*51c0b2f7Stbbdev template< typename T >
49*51c0b2f7Stbbdev struct parallel_puts : utils::NoAssign {
50*51c0b2f7Stbbdev 
51*51c0b2f7Stbbdev     tbb::flow::buffer_node<T> &my_b;
52*51c0b2f7Stbbdev 
53*51c0b2f7Stbbdev     parallel_puts( tbb::flow::buffer_node<T> &b ) : my_b(b) {}
54*51c0b2f7Stbbdev 
55*51c0b2f7Stbbdev     void operator()(int i) const {
56*51c0b2f7Stbbdev         for (int j = 0; j < N; ++j) {
57*51c0b2f7Stbbdev             bool msg = my_b.try_put( T(N*i + j) );
58*51c0b2f7Stbbdev             CHECK_MESSAGE( msg == true, "" );
59*51c0b2f7Stbbdev         }
60*51c0b2f7Stbbdev     }
61*51c0b2f7Stbbdev };
62*51c0b2f7Stbbdev 
63*51c0b2f7Stbbdev template< typename T >
64*51c0b2f7Stbbdev struct touches {
65*51c0b2f7Stbbdev 
66*51c0b2f7Stbbdev     bool **my_touches;
67*51c0b2f7Stbbdev     int my_num_threads;
68*51c0b2f7Stbbdev 
69*51c0b2f7Stbbdev     touches( int num_threads ) : my_num_threads(num_threads) {
70*51c0b2f7Stbbdev         my_touches = new bool* [my_num_threads];
71*51c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
72*51c0b2f7Stbbdev             my_touches[p] = new bool[N];
73*51c0b2f7Stbbdev             for ( int n = 0; n < N; ++n)
74*51c0b2f7Stbbdev                 my_touches[p][n] = false;
75*51c0b2f7Stbbdev         }
76*51c0b2f7Stbbdev     }
77*51c0b2f7Stbbdev 
78*51c0b2f7Stbbdev     ~touches() {
79*51c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
80*51c0b2f7Stbbdev             delete [] my_touches[p];
81*51c0b2f7Stbbdev         }
82*51c0b2f7Stbbdev         delete [] my_touches;
83*51c0b2f7Stbbdev     }
84*51c0b2f7Stbbdev 
85*51c0b2f7Stbbdev     bool check( T v ) {
86*51c0b2f7Stbbdev         CHECK_MESSAGE( my_touches[v/N][v%N] == false, "" );
87*51c0b2f7Stbbdev         my_touches[v/N][v%N] = true;
88*51c0b2f7Stbbdev         return true;
89*51c0b2f7Stbbdev     }
90*51c0b2f7Stbbdev 
91*51c0b2f7Stbbdev     bool validate_touches() {
92*51c0b2f7Stbbdev         for ( int p = 0; p < my_num_threads; ++p) {
93*51c0b2f7Stbbdev             for ( int n = 0; n < N; ++n) {
94*51c0b2f7Stbbdev                 CHECK_MESSAGE( my_touches[p][n] == true, "" );
95*51c0b2f7Stbbdev             }
96*51c0b2f7Stbbdev         }
97*51c0b2f7Stbbdev         return true;
98*51c0b2f7Stbbdev     }
99*51c0b2f7Stbbdev };
100*51c0b2f7Stbbdev 
101*51c0b2f7Stbbdev template< typename T >
102*51c0b2f7Stbbdev struct parallel_gets : utils::NoAssign {
103*51c0b2f7Stbbdev 
104*51c0b2f7Stbbdev     tbb::flow::buffer_node<T> &my_b;
105*51c0b2f7Stbbdev     touches<T> &my_touches;
106*51c0b2f7Stbbdev 
107*51c0b2f7Stbbdev     parallel_gets( tbb::flow::buffer_node<T> &b, touches<T> &t) : my_b(b), my_touches(t) {}
108*51c0b2f7Stbbdev 
109*51c0b2f7Stbbdev     void operator()(int) const {
110*51c0b2f7Stbbdev         for (int j = 0; j < N; ++j) {
111*51c0b2f7Stbbdev             T v;
112*51c0b2f7Stbbdev             spin_try_get( my_b, v );
113*51c0b2f7Stbbdev             my_touches.check( v );
114*51c0b2f7Stbbdev         }
115*51c0b2f7Stbbdev     }
116*51c0b2f7Stbbdev 
117*51c0b2f7Stbbdev };
118*51c0b2f7Stbbdev 
119*51c0b2f7Stbbdev template< typename T >
120*51c0b2f7Stbbdev struct parallel_put_get : utils::NoAssign {
121*51c0b2f7Stbbdev 
122*51c0b2f7Stbbdev     tbb::flow::buffer_node<T> &my_b;
123*51c0b2f7Stbbdev     touches<T> &my_touches;
124*51c0b2f7Stbbdev 
125*51c0b2f7Stbbdev     parallel_put_get( tbb::flow::buffer_node<T> &b, touches<T> &t ) : my_b(b), my_touches(t) {}
126*51c0b2f7Stbbdev 
127*51c0b2f7Stbbdev     void operator()(int tid) const {
128*51c0b2f7Stbbdev 
129*51c0b2f7Stbbdev         for ( int i = 0; i < N; i+=C ) {
130*51c0b2f7Stbbdev             int j_end = ( N < i + C ) ? N : i + C;
131*51c0b2f7Stbbdev             // dump about C values into the buffer
132*51c0b2f7Stbbdev             for ( int j = i; j < j_end; ++j ) {
133*51c0b2f7Stbbdev                 CHECK_MESSAGE( my_b.try_put( T (N*tid + j ) ) == true, "" );
134*51c0b2f7Stbbdev             }
135*51c0b2f7Stbbdev             // receiver about C values from the buffer
136*51c0b2f7Stbbdev             for ( int j = i; j < j_end; ++j ) {
137*51c0b2f7Stbbdev                 T v;
138*51c0b2f7Stbbdev                 spin_try_get( my_b, v );
139*51c0b2f7Stbbdev                 my_touches.check( v );
140*51c0b2f7Stbbdev             }
141*51c0b2f7Stbbdev         }
142*51c0b2f7Stbbdev     }
143*51c0b2f7Stbbdev 
144*51c0b2f7Stbbdev };
145*51c0b2f7Stbbdev 
146*51c0b2f7Stbbdev //
147*51c0b2f7Stbbdev // Tests
148*51c0b2f7Stbbdev //
149*51c0b2f7Stbbdev // Item can be reserved, released, consumed ( single serial receiver )
150*51c0b2f7Stbbdev //
151*51c0b2f7Stbbdev template< typename T >
152*51c0b2f7Stbbdev int test_reservation() {
153*51c0b2f7Stbbdev     tbb::flow::graph g;
154*51c0b2f7Stbbdev     T bogus_value(-1);
155*51c0b2f7Stbbdev 
156*51c0b2f7Stbbdev     // Simple tests
157*51c0b2f7Stbbdev     tbb::flow::buffer_node<T> b(g);
158*51c0b2f7Stbbdev 
159*51c0b2f7Stbbdev     b.try_put(T(1));
160*51c0b2f7Stbbdev     b.try_put(T(2));
161*51c0b2f7Stbbdev     b.try_put(T(3));
162*51c0b2f7Stbbdev 
163*51c0b2f7Stbbdev     T v, vsum;
164*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_reserve(v) == true, "" );
165*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_release() == true, "" );
166*51c0b2f7Stbbdev     v = bogus_value;
167*51c0b2f7Stbbdev     g.wait_for_all();
168*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_reserve(v) == true, "" );
169*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_consume() == true, "" );
170*51c0b2f7Stbbdev     vsum += v;
171*51c0b2f7Stbbdev     v = bogus_value;
172*51c0b2f7Stbbdev     g.wait_for_all();
173*51c0b2f7Stbbdev 
174*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get(v) == true, "" );
175*51c0b2f7Stbbdev     vsum += v;
176*51c0b2f7Stbbdev     v = bogus_value;
177*51c0b2f7Stbbdev     g.wait_for_all();
178*51c0b2f7Stbbdev 
179*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_reserve(v) == true, "" );
180*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_release() == true, "" );
181*51c0b2f7Stbbdev     v = bogus_value;
182*51c0b2f7Stbbdev     g.wait_for_all();
183*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_reserve(v) == true, "" );
184*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_consume() == true, "" );
185*51c0b2f7Stbbdev     vsum += v;
186*51c0b2f7Stbbdev     CHECK_MESSAGE( vsum == T(6), "");
187*51c0b2f7Stbbdev     v = bogus_value;
188*51c0b2f7Stbbdev     g.wait_for_all();
189*51c0b2f7Stbbdev 
190*51c0b2f7Stbbdev     return 0;
191*51c0b2f7Stbbdev }
192*51c0b2f7Stbbdev 
193*51c0b2f7Stbbdev //
194*51c0b2f7Stbbdev // Tests
195*51c0b2f7Stbbdev //
196*51c0b2f7Stbbdev // multiple parallel senders, items in arbitrary order
197*51c0b2f7Stbbdev // multiple parallel senders, multiple parallel receivers, items in arbitrary order and all items received
198*51c0b2f7Stbbdev //   * overlapped puts / gets
199*51c0b2f7Stbbdev //   * all puts finished before any getS
200*51c0b2f7Stbbdev //
201*51c0b2f7Stbbdev template< typename T >
202*51c0b2f7Stbbdev int test_parallel(int num_threads) {
203*51c0b2f7Stbbdev     tbb::flow::graph g;
204*51c0b2f7Stbbdev     tbb::flow::buffer_node<T> b(g);
205*51c0b2f7Stbbdev     tbb::flow::buffer_node<T> b2(g);
206*51c0b2f7Stbbdev     tbb::flow::buffer_node<T> b3(g);
207*51c0b2f7Stbbdev     T bogus_value(-1);
208*51c0b2f7Stbbdev     T j = bogus_value;
209*51c0b2f7Stbbdev 
210*51c0b2f7Stbbdev     NativeParallelFor( num_threads, parallel_puts<T>(b) );
211*51c0b2f7Stbbdev 
212*51c0b2f7Stbbdev     T *next_value = new T[num_threads];
213*51c0b2f7Stbbdev     for (int tid = 0; tid < num_threads; ++tid) next_value[tid] = T(0);
214*51c0b2f7Stbbdev 
215*51c0b2f7Stbbdev     for (int i = 0; i < num_threads * N; ++i ) {
216*51c0b2f7Stbbdev         spin_try_get( b, j );
217*51c0b2f7Stbbdev         check_item( next_value, j );
218*51c0b2f7Stbbdev         j = bogus_value;
219*51c0b2f7Stbbdev     }
220*51c0b2f7Stbbdev     for (int tid = 0; tid < num_threads; ++tid)  {
221*51c0b2f7Stbbdev         CHECK_MESSAGE( next_value[tid] == T((N*(N-1))/2), "" );
222*51c0b2f7Stbbdev     }
223*51c0b2f7Stbbdev 
224*51c0b2f7Stbbdev     j = bogus_value;
225*51c0b2f7Stbbdev     g.wait_for_all();
226*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
227*51c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
228*51c0b2f7Stbbdev 
229*51c0b2f7Stbbdev     NativeParallelFor( num_threads, parallel_puts<T>(b) );
230*51c0b2f7Stbbdev 
231*51c0b2f7Stbbdev     {
232*51c0b2f7Stbbdev         touches< T > t( num_threads );
233*51c0b2f7Stbbdev         NativeParallelFor( num_threads, parallel_gets<T>(b, t) );
234*51c0b2f7Stbbdev         g.wait_for_all();
235*51c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
236*51c0b2f7Stbbdev     }
237*51c0b2f7Stbbdev     j = bogus_value;
238*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
239*51c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
240*51c0b2f7Stbbdev 
241*51c0b2f7Stbbdev     g.wait_for_all();
242*51c0b2f7Stbbdev     {
243*51c0b2f7Stbbdev         touches< T > t( num_threads );
244*51c0b2f7Stbbdev         NativeParallelFor( num_threads, parallel_put_get<T>(b, t) );
245*51c0b2f7Stbbdev         g.wait_for_all();
246*51c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
247*51c0b2f7Stbbdev     }
248*51c0b2f7Stbbdev     j = bogus_value;
249*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
250*51c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
251*51c0b2f7Stbbdev 
252*51c0b2f7Stbbdev     tbb::flow::make_edge( b, b2 );
253*51c0b2f7Stbbdev     tbb::flow::make_edge( b2, b3 );
254*51c0b2f7Stbbdev 
255*51c0b2f7Stbbdev     NativeParallelFor( num_threads, parallel_puts<T>(b) );
256*51c0b2f7Stbbdev     {
257*51c0b2f7Stbbdev         touches< T > t( num_threads );
258*51c0b2f7Stbbdev         NativeParallelFor( num_threads, parallel_gets<T>(b3, t) );
259*51c0b2f7Stbbdev         g.wait_for_all();
260*51c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
261*51c0b2f7Stbbdev     }
262*51c0b2f7Stbbdev     j = bogus_value;
263*51c0b2f7Stbbdev     g.wait_for_all();
264*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
265*51c0b2f7Stbbdev     g.wait_for_all();
266*51c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
267*51c0b2f7Stbbdev     g.wait_for_all();
268*51c0b2f7Stbbdev     CHECK_MESSAGE( b3.try_get( j ) == false, "" );
269*51c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
270*51c0b2f7Stbbdev 
271*51c0b2f7Stbbdev     // test copy constructor
272*51c0b2f7Stbbdev     CHECK_MESSAGE( b.remove_successor( b2 ), "" );
273*51c0b2f7Stbbdev     // fill up b:
274*51c0b2f7Stbbdev     NativeParallelFor( num_threads, parallel_puts<T>(b) );
275*51c0b2f7Stbbdev     // copy b:
276*51c0b2f7Stbbdev     tbb::flow::buffer_node<T> b_copy(b);
277*51c0b2f7Stbbdev 
278*51c0b2f7Stbbdev     // b_copy should be empty
279*51c0b2f7Stbbdev     j = bogus_value;
280*51c0b2f7Stbbdev     g.wait_for_all();
281*51c0b2f7Stbbdev     CHECK_MESSAGE( b_copy.try_get( j ) == false, "" );
282*51c0b2f7Stbbdev 
283*51c0b2f7Stbbdev     // hook them together:
284*51c0b2f7Stbbdev     CHECK_MESSAGE( b.register_successor(b_copy) == true, "" );
285*51c0b2f7Stbbdev     // try to get content from b_copy
286*51c0b2f7Stbbdev     {
287*51c0b2f7Stbbdev         touches< T > t( num_threads );
288*51c0b2f7Stbbdev         NativeParallelFor( num_threads, parallel_gets<T>(b_copy, t) );
289*51c0b2f7Stbbdev         g.wait_for_all();
290*51c0b2f7Stbbdev         CHECK_MESSAGE( t.validate_touches(), "" );
291*51c0b2f7Stbbdev     }
292*51c0b2f7Stbbdev     // now both should be empty
293*51c0b2f7Stbbdev     j = bogus_value;
294*51c0b2f7Stbbdev     g.wait_for_all();
295*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
296*51c0b2f7Stbbdev     g.wait_for_all();
297*51c0b2f7Stbbdev     CHECK_MESSAGE( b_copy.try_get( j ) == false, "" );
298*51c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
299*51c0b2f7Stbbdev 
300*51c0b2f7Stbbdev     delete [] next_value;
301*51c0b2f7Stbbdev     return 0;
302*51c0b2f7Stbbdev }
303*51c0b2f7Stbbdev 
304*51c0b2f7Stbbdev //
305*51c0b2f7Stbbdev // Tests
306*51c0b2f7Stbbdev //
307*51c0b2f7Stbbdev // Predecessors cannot be registered
308*51c0b2f7Stbbdev // Empty buffer rejects item requests
309*51c0b2f7Stbbdev // Single serial sender, items in arbitrary order
310*51c0b2f7Stbbdev // Chained buffers ( 2 & 3 ), single sender, items at last buffer in arbitrary order
311*51c0b2f7Stbbdev //
312*51c0b2f7Stbbdev 
313*51c0b2f7Stbbdev #define TBB_INTERNAL_NAMESPACE detail::d1
314*51c0b2f7Stbbdev using tbb::TBB_INTERNAL_NAMESPACE::register_predecessor;
315*51c0b2f7Stbbdev using tbb::TBB_INTERNAL_NAMESPACE::remove_predecessor;
316*51c0b2f7Stbbdev 
317*51c0b2f7Stbbdev template< typename T >
318*51c0b2f7Stbbdev int test_serial() {
319*51c0b2f7Stbbdev     tbb::flow::graph g;
320*51c0b2f7Stbbdev     T bogus_value(-1);
321*51c0b2f7Stbbdev 
322*51c0b2f7Stbbdev     tbb::flow::buffer_node<T> b(g);
323*51c0b2f7Stbbdev     tbb::flow::buffer_node<T> b2(g);
324*51c0b2f7Stbbdev     T j = bogus_value;
325*51c0b2f7Stbbdev 
326*51c0b2f7Stbbdev     //
327*51c0b2f7Stbbdev     // Rejects attempts to add / remove predecessor
328*51c0b2f7Stbbdev     // Rejects request from empty buffer
329*51c0b2f7Stbbdev     //
330*51c0b2f7Stbbdev     CHECK_MESSAGE( register_predecessor<T>( b, b2 ) == false, "" );
331*51c0b2f7Stbbdev     CHECK_MESSAGE( remove_predecessor<T>( b, b2 ) == false, "" );
332*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
333*51c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
334*51c0b2f7Stbbdev 
335*51c0b2f7Stbbdev     //
336*51c0b2f7Stbbdev     // Simple puts and gets
337*51c0b2f7Stbbdev     //
338*51c0b2f7Stbbdev 
339*51c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
340*51c0b2f7Stbbdev         bool msg = b.try_put( T(i) );
341*51c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
342*51c0b2f7Stbbdev     }
343*51c0b2f7Stbbdev 
344*51c0b2f7Stbbdev     T vsum = T(0);
345*51c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
346*51c0b2f7Stbbdev         j = bogus_value;
347*51c0b2f7Stbbdev         spin_try_get( b, j );
348*51c0b2f7Stbbdev         vsum += j;
349*51c0b2f7Stbbdev     }
350*51c0b2f7Stbbdev     CHECK_MESSAGE( vsum == (N*(N-1))/2, "");
351*51c0b2f7Stbbdev     j = bogus_value;
352*51c0b2f7Stbbdev     g.wait_for_all();
353*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
354*51c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
355*51c0b2f7Stbbdev 
356*51c0b2f7Stbbdev     tbb::flow::make_edge(b, b2);
357*51c0b2f7Stbbdev 
358*51c0b2f7Stbbdev     vsum = T(0);
359*51c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
360*51c0b2f7Stbbdev         bool msg = b.try_put( T(i) );
361*51c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
362*51c0b2f7Stbbdev     }
363*51c0b2f7Stbbdev 
364*51c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
365*51c0b2f7Stbbdev         j = bogus_value;
366*51c0b2f7Stbbdev         spin_try_get( b2, j );
367*51c0b2f7Stbbdev         vsum += j;
368*51c0b2f7Stbbdev     }
369*51c0b2f7Stbbdev     CHECK_MESSAGE( vsum == (N*(N-1))/2, "");
370*51c0b2f7Stbbdev     j = bogus_value;
371*51c0b2f7Stbbdev     g.wait_for_all();
372*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
373*51c0b2f7Stbbdev     g.wait_for_all();
374*51c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
375*51c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
376*51c0b2f7Stbbdev 
377*51c0b2f7Stbbdev     tbb::flow::remove_edge(b, b2);
378*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_put( 1 ) == true, "" );
379*51c0b2f7Stbbdev     g.wait_for_all();
380*51c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
381*51c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
382*51c0b2f7Stbbdev     g.wait_for_all();
383*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == true, "" );
384*51c0b2f7Stbbdev     CHECK_MESSAGE( j == 1, "" );
385*51c0b2f7Stbbdev 
386*51c0b2f7Stbbdev     tbb::flow::buffer_node<T> b3(g);
387*51c0b2f7Stbbdev     tbb::flow::make_edge( b, b2 );
388*51c0b2f7Stbbdev     tbb::flow::make_edge( b2, b3 );
389*51c0b2f7Stbbdev 
390*51c0b2f7Stbbdev     vsum = T(0);
391*51c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
392*51c0b2f7Stbbdev         bool msg = b.try_put( T(i) );
393*51c0b2f7Stbbdev         CHECK_MESSAGE( msg == true, "" );
394*51c0b2f7Stbbdev     }
395*51c0b2f7Stbbdev 
396*51c0b2f7Stbbdev     for (int i = 0; i < N; ++i) {
397*51c0b2f7Stbbdev         j = bogus_value;
398*51c0b2f7Stbbdev         spin_try_get( b3, j );
399*51c0b2f7Stbbdev         vsum += j;
400*51c0b2f7Stbbdev     }
401*51c0b2f7Stbbdev     CHECK_MESSAGE( vsum == (N*(N-1))/2, "");
402*51c0b2f7Stbbdev     j = bogus_value;
403*51c0b2f7Stbbdev     g.wait_for_all();
404*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == false, "" );
405*51c0b2f7Stbbdev     g.wait_for_all();
406*51c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
407*51c0b2f7Stbbdev     g.wait_for_all();
408*51c0b2f7Stbbdev     CHECK_MESSAGE( b3.try_get( j ) == false, "" );
409*51c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
410*51c0b2f7Stbbdev 
411*51c0b2f7Stbbdev     tbb::flow::remove_edge(b, b2);
412*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_put( 1 ) == true, "" );
413*51c0b2f7Stbbdev     g.wait_for_all();
414*51c0b2f7Stbbdev     CHECK_MESSAGE( b2.try_get( j ) == false, "" );
415*51c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
416*51c0b2f7Stbbdev     g.wait_for_all();
417*51c0b2f7Stbbdev     CHECK_MESSAGE( b3.try_get( j ) == false, "" );
418*51c0b2f7Stbbdev     CHECK_MESSAGE( j == bogus_value, "" );
419*51c0b2f7Stbbdev     g.wait_for_all();
420*51c0b2f7Stbbdev     CHECK_MESSAGE( b.try_get( j ) == true, "" );
421*51c0b2f7Stbbdev     CHECK_MESSAGE( j == 1, "" );
422*51c0b2f7Stbbdev 
423*51c0b2f7Stbbdev     return 0;
424*51c0b2f7Stbbdev }
425*51c0b2f7Stbbdev 
426*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
427*51c0b2f7Stbbdev #include <array>
428*51c0b2f7Stbbdev #include <vector>
429*51c0b2f7Stbbdev void test_follows_and_precedes_api() {
430*51c0b2f7Stbbdev     using msg_t = tbb::flow::continue_msg;
431*51c0b2f7Stbbdev 
432*51c0b2f7Stbbdev     std::array<msg_t, 3> messages_for_follows = { {msg_t(), msg_t(), msg_t()} };
433*51c0b2f7Stbbdev     std::vector<msg_t> messages_for_precedes = {msg_t(), msg_t(), msg_t()};
434*51c0b2f7Stbbdev 
435*51c0b2f7Stbbdev     follows_and_precedes_testing::test_follows<msg_t, tbb::flow::buffer_node<msg_t>>(messages_for_follows);
436*51c0b2f7Stbbdev     follows_and_precedes_testing::test_precedes<msg_t, tbb::flow::buffer_node<msg_t>>(messages_for_precedes);
437*51c0b2f7Stbbdev }
438*51c0b2f7Stbbdev #endif
439*51c0b2f7Stbbdev 
440*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
441*51c0b2f7Stbbdev void test_deduction_guides() {
442*51c0b2f7Stbbdev     using namespace tbb::flow;
443*51c0b2f7Stbbdev     graph g;
444*51c0b2f7Stbbdev     broadcast_node<int> br(g);
445*51c0b2f7Stbbdev     buffer_node<int> b0(g);
446*51c0b2f7Stbbdev 
447*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
448*51c0b2f7Stbbdev     buffer_node b1(follows(br));
449*51c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(b1), buffer_node<int>>);
450*51c0b2f7Stbbdev 
451*51c0b2f7Stbbdev     buffer_node b2(precedes(br));
452*51c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(b2), buffer_node<int>>);
453*51c0b2f7Stbbdev #endif
454*51c0b2f7Stbbdev 
455*51c0b2f7Stbbdev     buffer_node b3(b0);
456*51c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(b3), buffer_node<int>>);
457*51c0b2f7Stbbdev     g.wait_for_all();
458*51c0b2f7Stbbdev }
459*51c0b2f7Stbbdev #endif
460*51c0b2f7Stbbdev 
461*51c0b2f7Stbbdev #include <iomanip>
462*51c0b2f7Stbbdev 
463*51c0b2f7Stbbdev //! Test buffer_node with parallel and serial neighbours
464*51c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing
465*51c0b2f7Stbbdev TEST_CASE("Serial and parallel test"){
466*51c0b2f7Stbbdev     for (int p = 2; p <= 4; ++p) {
467*51c0b2f7Stbbdev         tbb::task_arena arena(p);
468*51c0b2f7Stbbdev         arena.execute(
469*51c0b2f7Stbbdev             [&]() {
470*51c0b2f7Stbbdev                 test_serial<int>();
471*51c0b2f7Stbbdev                 test_parallel<int>(p);
472*51c0b2f7Stbbdev             }
473*51c0b2f7Stbbdev         );
474*51c0b2f7Stbbdev     }
475*51c0b2f7Stbbdev }
476*51c0b2f7Stbbdev 
477*51c0b2f7Stbbdev //! Test reset and cancellation behavior
478*51c0b2f7Stbbdev //! \brief \ref error_guessing
479*51c0b2f7Stbbdev TEST_CASE("Resets"){
480*51c0b2f7Stbbdev     test_resets<int,tbb::flow::buffer_node<int> >();
481*51c0b2f7Stbbdev     test_resets<float,tbb::flow::buffer_node<float> >();
482*51c0b2f7Stbbdev }
483*51c0b2f7Stbbdev 
484*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
485*51c0b2f7Stbbdev //! Test deprecated follows and preceedes API
486*51c0b2f7Stbbdev //! \brief \ref error_guessing
487*51c0b2f7Stbbdev TEST_CASE("Follows and precedes API"){
488*51c0b2f7Stbbdev     test_follows_and_precedes_api();
489*51c0b2f7Stbbdev }
490*51c0b2f7Stbbdev #endif
491*51c0b2f7Stbbdev 
492*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
493*51c0b2f7Stbbdev //! Test deduction guides
494*51c0b2f7Stbbdev //! \brief requirement
495*51c0b2f7Stbbdev TEST_CASE("Deduction guides"){
496*51c0b2f7Stbbdev     test_deduction_guides();
497*51c0b2f7Stbbdev }
498*51c0b2f7Stbbdev #endif
499