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