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 // TODO: Add overlapping put / receive tests 18*51c0b2f7Stbbdev 19*51c0b2f7Stbbdev #include "common/config.h" 20*51c0b2f7Stbbdev 21*51c0b2f7Stbbdev // TODO revamp: move parts dependent on __TBB_EXTRA_DEBUG into separate test(s) since having these 22*51c0b2f7Stbbdev // parts in all of tests might make testing of the product, which is different from what is actually 23*51c0b2f7Stbbdev // released. 24*51c0b2f7Stbbdev #define __TBB_EXTRA_DEBUG 1 25*51c0b2f7Stbbdev #include "tbb/flow_graph.h" 26*51c0b2f7Stbbdev 27*51c0b2f7Stbbdev #include "common/test.h" 28*51c0b2f7Stbbdev #include "common/utils.h" 29*51c0b2f7Stbbdev #include "common/utils_assert.h" 30*51c0b2f7Stbbdev #include "common/checktype.h" 31*51c0b2f7Stbbdev #include "common/graph_utils.h" 32*51c0b2f7Stbbdev #include "common/test_follows_and_precedes_api.h" 33*51c0b2f7Stbbdev 34*51c0b2f7Stbbdev #include <cstdio> 35*51c0b2f7Stbbdev 36*51c0b2f7Stbbdev 37*51c0b2f7Stbbdev //! \file test_queue_node.cpp 38*51c0b2f7Stbbdev //! \brief Test for [flow_graph.queue_node] specification 39*51c0b2f7Stbbdev 40*51c0b2f7Stbbdev 41*51c0b2f7Stbbdev #define N 1000 42*51c0b2f7Stbbdev #define C 10 43*51c0b2f7Stbbdev 44*51c0b2f7Stbbdev template< typename T > 45*51c0b2f7Stbbdev void spin_try_get( tbb::flow::queue_node<T> &q, T &value ) { 46*51c0b2f7Stbbdev while ( q.try_get(value) != true ) ; 47*51c0b2f7Stbbdev } 48*51c0b2f7Stbbdev 49*51c0b2f7Stbbdev template< typename T > 50*51c0b2f7Stbbdev void check_item( T* next_value, T &value ) { 51*51c0b2f7Stbbdev int tid = value / N; 52*51c0b2f7Stbbdev int offset = value % N; 53*51c0b2f7Stbbdev CHECK_MESSAGE( next_value[tid] == T(offset), "" ); 54*51c0b2f7Stbbdev ++next_value[tid]; 55*51c0b2f7Stbbdev } 56*51c0b2f7Stbbdev 57*51c0b2f7Stbbdev template< typename T > 58*51c0b2f7Stbbdev struct parallel_puts : utils::NoAssign { 59*51c0b2f7Stbbdev 60*51c0b2f7Stbbdev tbb::flow::queue_node<T> &my_q; 61*51c0b2f7Stbbdev 62*51c0b2f7Stbbdev parallel_puts( tbb::flow::queue_node<T> &q ) : my_q(q) {} 63*51c0b2f7Stbbdev 64*51c0b2f7Stbbdev void operator()(int i) const { 65*51c0b2f7Stbbdev for (int j = 0; j < N; ++j) { 66*51c0b2f7Stbbdev bool msg = my_q.try_put( T(N*i + j) ); 67*51c0b2f7Stbbdev CHECK_MESSAGE( msg == true, "" ); 68*51c0b2f7Stbbdev } 69*51c0b2f7Stbbdev } 70*51c0b2f7Stbbdev 71*51c0b2f7Stbbdev }; 72*51c0b2f7Stbbdev 73*51c0b2f7Stbbdev 74*51c0b2f7Stbbdev 75*51c0b2f7Stbbdev template< typename T > 76*51c0b2f7Stbbdev struct touches { 77*51c0b2f7Stbbdev 78*51c0b2f7Stbbdev bool **my_touches; 79*51c0b2f7Stbbdev T **my_last_touch; 80*51c0b2f7Stbbdev int my_num_threads; 81*51c0b2f7Stbbdev 82*51c0b2f7Stbbdev touches( int num_threads ) : my_num_threads(num_threads) { 83*51c0b2f7Stbbdev my_last_touch = new T* [my_num_threads]; 84*51c0b2f7Stbbdev my_touches = new bool* [my_num_threads]; 85*51c0b2f7Stbbdev for ( int p = 0; p < my_num_threads; ++p) { 86*51c0b2f7Stbbdev my_last_touch[p] = new T[my_num_threads]; 87*51c0b2f7Stbbdev for ( int p2 = 0; p2 < my_num_threads; ++p2) 88*51c0b2f7Stbbdev my_last_touch[p][p2] = -1; 89*51c0b2f7Stbbdev 90*51c0b2f7Stbbdev my_touches[p] = new bool[N*my_num_threads]; 91*51c0b2f7Stbbdev for ( int n = 0; n < N*my_num_threads; ++n) 92*51c0b2f7Stbbdev my_touches[p][n] = false; 93*51c0b2f7Stbbdev } 94*51c0b2f7Stbbdev } 95*51c0b2f7Stbbdev 96*51c0b2f7Stbbdev ~touches() { 97*51c0b2f7Stbbdev for ( int p = 0; p < my_num_threads; ++p) { 98*51c0b2f7Stbbdev delete [] my_touches[p]; 99*51c0b2f7Stbbdev delete [] my_last_touch[p]; 100*51c0b2f7Stbbdev } 101*51c0b2f7Stbbdev delete [] my_touches; 102*51c0b2f7Stbbdev delete [] my_last_touch; 103*51c0b2f7Stbbdev } 104*51c0b2f7Stbbdev 105*51c0b2f7Stbbdev bool check( int tid, T v ) { 106*51c0b2f7Stbbdev int v_tid = v / N; 107*51c0b2f7Stbbdev if ( my_touches[tid][v] != false ) { 108*51c0b2f7Stbbdev printf("Error: value seen twice by local thread\n"); 109*51c0b2f7Stbbdev return false; 110*51c0b2f7Stbbdev } 111*51c0b2f7Stbbdev if ( v <= my_last_touch[tid][v_tid] ) { 112*51c0b2f7Stbbdev printf("Error: value seen in wrong order by local thread\n"); 113*51c0b2f7Stbbdev return false; 114*51c0b2f7Stbbdev } 115*51c0b2f7Stbbdev my_last_touch[tid][v_tid] = v; 116*51c0b2f7Stbbdev my_touches[tid][v] = true; 117*51c0b2f7Stbbdev return true; 118*51c0b2f7Stbbdev } 119*51c0b2f7Stbbdev 120*51c0b2f7Stbbdev bool validate_touches() { 121*51c0b2f7Stbbdev bool *all_touches = new bool[N*my_num_threads]; 122*51c0b2f7Stbbdev for ( int n = 0; n < N*my_num_threads; ++n) 123*51c0b2f7Stbbdev all_touches[n] = false; 124*51c0b2f7Stbbdev 125*51c0b2f7Stbbdev for ( int p = 0; p < my_num_threads; ++p) { 126*51c0b2f7Stbbdev for ( int n = 0; n < N*my_num_threads; ++n) { 127*51c0b2f7Stbbdev if ( my_touches[p][n] == true ) { 128*51c0b2f7Stbbdev CHECK_MESSAGE( ( all_touches[n] == false), "value see by more than one thread\n" ); 129*51c0b2f7Stbbdev all_touches[n] = true; 130*51c0b2f7Stbbdev } 131*51c0b2f7Stbbdev } 132*51c0b2f7Stbbdev } 133*51c0b2f7Stbbdev for ( int n = 0; n < N*my_num_threads; ++n) { 134*51c0b2f7Stbbdev if ( !all_touches[n] ) 135*51c0b2f7Stbbdev printf("No touch at %d, my_num_threads = %d\n", n, my_num_threads); 136*51c0b2f7Stbbdev //CHECK_MESSAGE( ( all_touches[n] == true), "value not seen by any thread\n" ); 137*51c0b2f7Stbbdev } 138*51c0b2f7Stbbdev delete [] all_touches; 139*51c0b2f7Stbbdev return true; 140*51c0b2f7Stbbdev } 141*51c0b2f7Stbbdev 142*51c0b2f7Stbbdev }; 143*51c0b2f7Stbbdev 144*51c0b2f7Stbbdev template< typename T > 145*51c0b2f7Stbbdev struct parallel_gets : utils::NoAssign { 146*51c0b2f7Stbbdev 147*51c0b2f7Stbbdev tbb::flow::queue_node<T> &my_q; 148*51c0b2f7Stbbdev touches<T> &my_touches; 149*51c0b2f7Stbbdev 150*51c0b2f7Stbbdev parallel_gets( tbb::flow::queue_node<T> &q, touches<T> &t) : my_q(q), my_touches(t) {} 151*51c0b2f7Stbbdev 152*51c0b2f7Stbbdev void operator()(int tid) const { 153*51c0b2f7Stbbdev for (int j = 0; j < N; ++j) { 154*51c0b2f7Stbbdev T v; 155*51c0b2f7Stbbdev spin_try_get( my_q, v ); 156*51c0b2f7Stbbdev my_touches.check( tid, v ); 157*51c0b2f7Stbbdev } 158*51c0b2f7Stbbdev } 159*51c0b2f7Stbbdev 160*51c0b2f7Stbbdev }; 161*51c0b2f7Stbbdev 162*51c0b2f7Stbbdev template< typename T > 163*51c0b2f7Stbbdev struct parallel_put_get : utils::NoAssign { 164*51c0b2f7Stbbdev 165*51c0b2f7Stbbdev tbb::flow::queue_node<T> &my_q; 166*51c0b2f7Stbbdev touches<T> &my_touches; 167*51c0b2f7Stbbdev 168*51c0b2f7Stbbdev parallel_put_get( tbb::flow::queue_node<T> &q, touches<T> &t ) : my_q(q), my_touches(t) {} 169*51c0b2f7Stbbdev 170*51c0b2f7Stbbdev void operator()(int tid) const { 171*51c0b2f7Stbbdev 172*51c0b2f7Stbbdev for ( int i = 0; i < N; i+=C ) { 173*51c0b2f7Stbbdev int j_end = ( N < i + C ) ? N : i + C; 174*51c0b2f7Stbbdev // dump about C values into the Q 175*51c0b2f7Stbbdev for ( int j = i; j < j_end; ++j ) { 176*51c0b2f7Stbbdev CHECK_MESSAGE( my_q.try_put( T (N*tid + j ) ) == true, "" ); 177*51c0b2f7Stbbdev } 178*51c0b2f7Stbbdev // receiver about C values from the Q 179*51c0b2f7Stbbdev for ( int j = i; j < j_end; ++j ) { 180*51c0b2f7Stbbdev T v; 181*51c0b2f7Stbbdev spin_try_get( my_q, v ); 182*51c0b2f7Stbbdev my_touches.check( tid, v ); 183*51c0b2f7Stbbdev } 184*51c0b2f7Stbbdev } 185*51c0b2f7Stbbdev } 186*51c0b2f7Stbbdev 187*51c0b2f7Stbbdev }; 188*51c0b2f7Stbbdev 189*51c0b2f7Stbbdev // 190*51c0b2f7Stbbdev // Tests 191*51c0b2f7Stbbdev // 192*51c0b2f7Stbbdev // Item can be reserved, released, consumed ( single serial receiver ) 193*51c0b2f7Stbbdev // 194*51c0b2f7Stbbdev template< typename T > 195*51c0b2f7Stbbdev int test_reservation() { 196*51c0b2f7Stbbdev tbb::flow::graph g; 197*51c0b2f7Stbbdev T bogus_value(-1); 198*51c0b2f7Stbbdev 199*51c0b2f7Stbbdev // Simple tests 200*51c0b2f7Stbbdev tbb::flow::queue_node<T> q(g); 201*51c0b2f7Stbbdev 202*51c0b2f7Stbbdev q.try_put(T(1)); 203*51c0b2f7Stbbdev q.try_put(T(2)); 204*51c0b2f7Stbbdev q.try_put(T(3)); 205*51c0b2f7Stbbdev 206*51c0b2f7Stbbdev T v; 207*51c0b2f7Stbbdev CHECK_MESSAGE( q.reserve_item(v) == true, "" ); 208*51c0b2f7Stbbdev CHECK_MESSAGE( v == T(1), "" ); 209*51c0b2f7Stbbdev CHECK_MESSAGE( q.release_reservation() == true, "" ); 210*51c0b2f7Stbbdev v = bogus_value; 211*51c0b2f7Stbbdev g.wait_for_all(); 212*51c0b2f7Stbbdev CHECK_MESSAGE( q.reserve_item(v) == true, "" ); 213*51c0b2f7Stbbdev CHECK_MESSAGE( v == T(1), "" ); 214*51c0b2f7Stbbdev CHECK_MESSAGE( q.consume_reservation() == true, "" ); 215*51c0b2f7Stbbdev v = bogus_value; 216*51c0b2f7Stbbdev g.wait_for_all(); 217*51c0b2f7Stbbdev 218*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_get(v) == true, "" ); 219*51c0b2f7Stbbdev CHECK_MESSAGE( v == T(2), "" ); 220*51c0b2f7Stbbdev v = bogus_value; 221*51c0b2f7Stbbdev g.wait_for_all(); 222*51c0b2f7Stbbdev 223*51c0b2f7Stbbdev CHECK_MESSAGE( q.reserve_item(v) == true, "" ); 224*51c0b2f7Stbbdev CHECK_MESSAGE( v == T(3), "" ); 225*51c0b2f7Stbbdev CHECK_MESSAGE( q.release_reservation() == true, "" ); 226*51c0b2f7Stbbdev v = bogus_value; 227*51c0b2f7Stbbdev g.wait_for_all(); 228*51c0b2f7Stbbdev CHECK_MESSAGE( q.reserve_item(v) == true, "" ); 229*51c0b2f7Stbbdev CHECK_MESSAGE( v == T(3), "" ); 230*51c0b2f7Stbbdev CHECK_MESSAGE( q.consume_reservation() == true, "" ); 231*51c0b2f7Stbbdev v = bogus_value; 232*51c0b2f7Stbbdev g.wait_for_all(); 233*51c0b2f7Stbbdev 234*51c0b2f7Stbbdev return 0; 235*51c0b2f7Stbbdev } 236*51c0b2f7Stbbdev 237*51c0b2f7Stbbdev // 238*51c0b2f7Stbbdev // Tests 239*51c0b2f7Stbbdev // 240*51c0b2f7Stbbdev // multiple parallel senders, items in FIFO (relatively to sender) order 241*51c0b2f7Stbbdev // multiple parallel senders, multiple parallel receivers, items in FIFO order (relative to sender/receiver) and all items received 242*51c0b2f7Stbbdev // * overlapped puts / gets 243*51c0b2f7Stbbdev // * all puts finished before any getS 244*51c0b2f7Stbbdev // 245*51c0b2f7Stbbdev template< typename T > 246*51c0b2f7Stbbdev int test_parallel(int num_threads) { 247*51c0b2f7Stbbdev tbb::flow::graph g; 248*51c0b2f7Stbbdev tbb::flow::queue_node<T> q(g); 249*51c0b2f7Stbbdev tbb::flow::queue_node<T> q2(g); 250*51c0b2f7Stbbdev tbb::flow::queue_node<T> q3(g); 251*51c0b2f7Stbbdev { 252*51c0b2f7Stbbdev Checker< T > my_check; 253*51c0b2f7Stbbdev T bogus_value(-1); 254*51c0b2f7Stbbdev T j = bogus_value; 255*51c0b2f7Stbbdev utils::NativeParallelFor( num_threads, parallel_puts<T>(q) ); 256*51c0b2f7Stbbdev 257*51c0b2f7Stbbdev T *next_value = new T[num_threads]; 258*51c0b2f7Stbbdev for (int tid = 0; tid < num_threads; ++tid) next_value[tid] = T(0); 259*51c0b2f7Stbbdev 260*51c0b2f7Stbbdev for (int i = 0; i < num_threads * N; ++i ) { 261*51c0b2f7Stbbdev spin_try_get( q, j ); 262*51c0b2f7Stbbdev check_item( next_value, j ); 263*51c0b2f7Stbbdev j = bogus_value; 264*51c0b2f7Stbbdev } 265*51c0b2f7Stbbdev for (int tid = 0; tid < num_threads; ++tid) { 266*51c0b2f7Stbbdev CHECK_MESSAGE( next_value[tid] == T(N), "" ); 267*51c0b2f7Stbbdev } 268*51c0b2f7Stbbdev delete[] next_value; 269*51c0b2f7Stbbdev 270*51c0b2f7Stbbdev j = bogus_value; 271*51c0b2f7Stbbdev g.wait_for_all(); 272*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_get( j ) == false, "" ); 273*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 274*51c0b2f7Stbbdev 275*51c0b2f7Stbbdev utils::NativeParallelFor( num_threads, parallel_puts<T>(q) ); 276*51c0b2f7Stbbdev 277*51c0b2f7Stbbdev { 278*51c0b2f7Stbbdev touches< T > t( num_threads ); 279*51c0b2f7Stbbdev utils::NativeParallelFor( num_threads, parallel_gets<T>(q, t) ); 280*51c0b2f7Stbbdev g.wait_for_all(); 281*51c0b2f7Stbbdev CHECK_MESSAGE( t.validate_touches(), "" ); 282*51c0b2f7Stbbdev } 283*51c0b2f7Stbbdev j = bogus_value; 284*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_get( j ) == false, "" ); 285*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 286*51c0b2f7Stbbdev 287*51c0b2f7Stbbdev g.wait_for_all(); 288*51c0b2f7Stbbdev { 289*51c0b2f7Stbbdev touches< T > t2( num_threads ); 290*51c0b2f7Stbbdev utils::NativeParallelFor( num_threads, parallel_put_get<T>(q, t2) ); 291*51c0b2f7Stbbdev g.wait_for_all(); 292*51c0b2f7Stbbdev CHECK_MESSAGE( t2.validate_touches(), "" ); 293*51c0b2f7Stbbdev } 294*51c0b2f7Stbbdev j = bogus_value; 295*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_get( j ) == false, "" ); 296*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 297*51c0b2f7Stbbdev 298*51c0b2f7Stbbdev tbb::flow::make_edge( q, q2 ); 299*51c0b2f7Stbbdev tbb::flow::make_edge( q2, q3 ); 300*51c0b2f7Stbbdev 301*51c0b2f7Stbbdev utils::NativeParallelFor( num_threads, parallel_puts<T>(q) ); 302*51c0b2f7Stbbdev { 303*51c0b2f7Stbbdev touches< T > t3( num_threads ); 304*51c0b2f7Stbbdev utils::NativeParallelFor( num_threads, parallel_gets<T>(q3, t3) ); 305*51c0b2f7Stbbdev g.wait_for_all(); 306*51c0b2f7Stbbdev CHECK_MESSAGE( t3.validate_touches(), "" ); 307*51c0b2f7Stbbdev } 308*51c0b2f7Stbbdev j = bogus_value; 309*51c0b2f7Stbbdev g.wait_for_all(); 310*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_get( j ) == false, "" ); 311*51c0b2f7Stbbdev g.wait_for_all(); 312*51c0b2f7Stbbdev CHECK_MESSAGE( q2.try_get( j ) == false, "" ); 313*51c0b2f7Stbbdev g.wait_for_all(); 314*51c0b2f7Stbbdev CHECK_MESSAGE( q3.try_get( j ) == false, "" ); 315*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 316*51c0b2f7Stbbdev 317*51c0b2f7Stbbdev // test copy constructor 318*51c0b2f7Stbbdev CHECK_MESSAGE( remove_successor( q, q2 ), "" ); 319*51c0b2f7Stbbdev utils::NativeParallelFor( num_threads, parallel_puts<T>(q) ); 320*51c0b2f7Stbbdev tbb::flow::queue_node<T> q_copy(q); 321*51c0b2f7Stbbdev j = bogus_value; 322*51c0b2f7Stbbdev g.wait_for_all(); 323*51c0b2f7Stbbdev CHECK_MESSAGE( q_copy.try_get( j ) == false, "" ); 324*51c0b2f7Stbbdev CHECK_MESSAGE( register_successor( q, q_copy ) == true, "" ); 325*51c0b2f7Stbbdev { 326*51c0b2f7Stbbdev touches< T > t( num_threads ); 327*51c0b2f7Stbbdev utils::NativeParallelFor( num_threads, parallel_gets<T>(q_copy, t) ); 328*51c0b2f7Stbbdev g.wait_for_all(); 329*51c0b2f7Stbbdev CHECK_MESSAGE( t.validate_touches(), "" ); 330*51c0b2f7Stbbdev } 331*51c0b2f7Stbbdev j = bogus_value; 332*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_get( j ) == false, "" ); 333*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 334*51c0b2f7Stbbdev CHECK_MESSAGE( q_copy.try_get( j ) == false, "" ); 335*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 336*51c0b2f7Stbbdev } 337*51c0b2f7Stbbdev 338*51c0b2f7Stbbdev return 0; 339*51c0b2f7Stbbdev } 340*51c0b2f7Stbbdev 341*51c0b2f7Stbbdev // 342*51c0b2f7Stbbdev // Tests 343*51c0b2f7Stbbdev // 344*51c0b2f7Stbbdev // Predecessors cannot be registered 345*51c0b2f7Stbbdev // Empty Q rejects item requests 346*51c0b2f7Stbbdev // Single serial sender, items in FIFO order 347*51c0b2f7Stbbdev // Chained Qs ( 2 & 3 ), single sender, items at last Q in FIFO order 348*51c0b2f7Stbbdev // 349*51c0b2f7Stbbdev 350*51c0b2f7Stbbdev template< typename T > 351*51c0b2f7Stbbdev int test_serial() { 352*51c0b2f7Stbbdev tbb::flow::graph g; 353*51c0b2f7Stbbdev tbb::flow::queue_node<T> q(g); 354*51c0b2f7Stbbdev tbb::flow::queue_node<T> q2(g); 355*51c0b2f7Stbbdev { // destroy the graph after manipulating it, and see if all the items in the buffers 356*51c0b2f7Stbbdev // have been destroyed before the graph 357*51c0b2f7Stbbdev Checker<T> my_check; // if CheckType< U > count constructions and destructions 358*51c0b2f7Stbbdev T bogus_value(-1); 359*51c0b2f7Stbbdev T j = bogus_value; 360*51c0b2f7Stbbdev 361*51c0b2f7Stbbdev // 362*51c0b2f7Stbbdev // Rejects attempts to add / remove predecessor 363*51c0b2f7Stbbdev // Rejects request from empty Q 364*51c0b2f7Stbbdev // 365*51c0b2f7Stbbdev CHECK_MESSAGE( register_predecessor( q, q2 ) == false, "" ); 366*51c0b2f7Stbbdev CHECK_MESSAGE( remove_predecessor( q, q2 ) == false, "" ); 367*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_get( j ) == false, "" ); 368*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 369*51c0b2f7Stbbdev 370*51c0b2f7Stbbdev // 371*51c0b2f7Stbbdev // Simple puts and gets 372*51c0b2f7Stbbdev // 373*51c0b2f7Stbbdev 374*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 375*51c0b2f7Stbbdev bool msg = q.try_put( T(i) ); 376*51c0b2f7Stbbdev CHECK_MESSAGE( msg == true, "" ); 377*51c0b2f7Stbbdev } 378*51c0b2f7Stbbdev 379*51c0b2f7Stbbdev 380*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 381*51c0b2f7Stbbdev j = bogus_value; 382*51c0b2f7Stbbdev spin_try_get( q, j ); 383*51c0b2f7Stbbdev CHECK_MESSAGE( i == j, "" ); 384*51c0b2f7Stbbdev } 385*51c0b2f7Stbbdev j = bogus_value; 386*51c0b2f7Stbbdev g.wait_for_all(); 387*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_get( j ) == false, "" ); 388*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 389*51c0b2f7Stbbdev 390*51c0b2f7Stbbdev tbb::flow::make_edge( q, q2 ); 391*51c0b2f7Stbbdev 392*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 393*51c0b2f7Stbbdev bool msg = q.try_put( T(i) ); 394*51c0b2f7Stbbdev CHECK_MESSAGE( msg == true, "" ); 395*51c0b2f7Stbbdev } 396*51c0b2f7Stbbdev 397*51c0b2f7Stbbdev 398*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 399*51c0b2f7Stbbdev j = bogus_value; 400*51c0b2f7Stbbdev spin_try_get( q2, j ); 401*51c0b2f7Stbbdev CHECK_MESSAGE( i == j, "" ); 402*51c0b2f7Stbbdev } 403*51c0b2f7Stbbdev j = bogus_value; 404*51c0b2f7Stbbdev g.wait_for_all(); 405*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_get( j ) == false, "" ); 406*51c0b2f7Stbbdev g.wait_for_all(); 407*51c0b2f7Stbbdev CHECK_MESSAGE( q2.try_get( j ) == false, "" ); 408*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 409*51c0b2f7Stbbdev 410*51c0b2f7Stbbdev tbb::flow::remove_edge( q, q2 ); 411*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_put( 1 ) == true, "" ); 412*51c0b2f7Stbbdev g.wait_for_all(); 413*51c0b2f7Stbbdev CHECK_MESSAGE( q2.try_get( j ) == false, "" ); 414*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 415*51c0b2f7Stbbdev g.wait_for_all(); 416*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_get( j ) == true, "" ); 417*51c0b2f7Stbbdev CHECK_MESSAGE( j == 1, "" ); 418*51c0b2f7Stbbdev 419*51c0b2f7Stbbdev tbb::flow::queue_node<T> q3(g); 420*51c0b2f7Stbbdev tbb::flow::make_edge( q, q2 ); 421*51c0b2f7Stbbdev tbb::flow::make_edge( q2, q3 ); 422*51c0b2f7Stbbdev 423*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 424*51c0b2f7Stbbdev bool msg = q.try_put( T(i) ); 425*51c0b2f7Stbbdev CHECK_MESSAGE( msg == true, "" ); 426*51c0b2f7Stbbdev } 427*51c0b2f7Stbbdev 428*51c0b2f7Stbbdev for (int i = 0; i < N; ++i) { 429*51c0b2f7Stbbdev j = bogus_value; 430*51c0b2f7Stbbdev spin_try_get( q3, j ); 431*51c0b2f7Stbbdev CHECK_MESSAGE( i == j, "" ); 432*51c0b2f7Stbbdev } 433*51c0b2f7Stbbdev j = bogus_value; 434*51c0b2f7Stbbdev g.wait_for_all(); 435*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_get( j ) == false, "" ); 436*51c0b2f7Stbbdev g.wait_for_all(); 437*51c0b2f7Stbbdev CHECK_MESSAGE( q2.try_get( j ) == false, "" ); 438*51c0b2f7Stbbdev g.wait_for_all(); 439*51c0b2f7Stbbdev CHECK_MESSAGE( q3.try_get( j ) == false, "" ); 440*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 441*51c0b2f7Stbbdev 442*51c0b2f7Stbbdev tbb::flow::remove_edge( q, q2 ); 443*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_put( 1 ) == true, "" ); 444*51c0b2f7Stbbdev g.wait_for_all(); 445*51c0b2f7Stbbdev CHECK_MESSAGE( q2.try_get( j ) == false, "" ); 446*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 447*51c0b2f7Stbbdev g.wait_for_all(); 448*51c0b2f7Stbbdev CHECK_MESSAGE( q3.try_get( j ) == false, "" ); 449*51c0b2f7Stbbdev CHECK_MESSAGE( j == bogus_value, "" ); 450*51c0b2f7Stbbdev g.wait_for_all(); 451*51c0b2f7Stbbdev CHECK_MESSAGE( q.try_get( j ) == true, "" ); 452*51c0b2f7Stbbdev CHECK_MESSAGE( j == 1, "" ); 453*51c0b2f7Stbbdev } 454*51c0b2f7Stbbdev 455*51c0b2f7Stbbdev return 0; 456*51c0b2f7Stbbdev } 457*51c0b2f7Stbbdev 458*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 459*51c0b2f7Stbbdev #include <array> 460*51c0b2f7Stbbdev #include <vector> 461*51c0b2f7Stbbdev void test_follows_and_precedes_api() { 462*51c0b2f7Stbbdev std::array<int, 3> messages_for_follows = { {0, 1, 2} }; 463*51c0b2f7Stbbdev std::vector<int> messages_for_precedes = {0, 1, 2}; 464*51c0b2f7Stbbdev 465*51c0b2f7Stbbdev follows_and_precedes_testing::test_follows <int, tbb::flow::queue_node<int>>(messages_for_follows); 466*51c0b2f7Stbbdev follows_and_precedes_testing::test_precedes <int, tbb::flow::queue_node<int>>(messages_for_precedes); 467*51c0b2f7Stbbdev } 468*51c0b2f7Stbbdev #endif 469*51c0b2f7Stbbdev 470*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 471*51c0b2f7Stbbdev void test_deduction_guides() { 472*51c0b2f7Stbbdev using namespace tbb::flow; 473*51c0b2f7Stbbdev graph g; 474*51c0b2f7Stbbdev broadcast_node<int> br(g); 475*51c0b2f7Stbbdev queue_node<int> q0(g); 476*51c0b2f7Stbbdev 477*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 478*51c0b2f7Stbbdev queue_node q1(follows(br)); 479*51c0b2f7Stbbdev static_assert(std::is_same_v<decltype(q1), queue_node<int>>); 480*51c0b2f7Stbbdev 481*51c0b2f7Stbbdev queue_node q2(precedes(br)); 482*51c0b2f7Stbbdev static_assert(std::is_same_v<decltype(q2), queue_node<int>>); 483*51c0b2f7Stbbdev #endif 484*51c0b2f7Stbbdev 485*51c0b2f7Stbbdev queue_node q3(q0); 486*51c0b2f7Stbbdev static_assert(std::is_same_v<decltype(q3), queue_node<int>>); 487*51c0b2f7Stbbdev g.wait_for_all(); 488*51c0b2f7Stbbdev } 489*51c0b2f7Stbbdev #endif 490*51c0b2f7Stbbdev 491*51c0b2f7Stbbdev //! Test serial, parallel behavior and reservation under parallelism 492*51c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing 493*51c0b2f7Stbbdev TEST_CASE("Parallel, serial test"){ 494*51c0b2f7Stbbdev for (int p = 2; p <= 4; ++p) { 495*51c0b2f7Stbbdev tbb::task_arena arena(p); 496*51c0b2f7Stbbdev arena.execute( 497*51c0b2f7Stbbdev [&]() { 498*51c0b2f7Stbbdev 499*51c0b2f7Stbbdev test_serial<int>(); 500*51c0b2f7Stbbdev test_serial<CheckType<int> >(); 501*51c0b2f7Stbbdev test_parallel<int>(p); 502*51c0b2f7Stbbdev test_parallel<CheckType<int> >(p); 503*51c0b2f7Stbbdev 504*51c0b2f7Stbbdev } 505*51c0b2f7Stbbdev ); 506*51c0b2f7Stbbdev } 507*51c0b2f7Stbbdev } 508*51c0b2f7Stbbdev 509*51c0b2f7Stbbdev //! Test reset and cancellation 510*51c0b2f7Stbbdev //! \brief \ref error_guessing 511*51c0b2f7Stbbdev TEST_CASE("Resets test"){ 512*51c0b2f7Stbbdev INFO("Testing resets\n"); 513*51c0b2f7Stbbdev test_resets<int, tbb::flow::queue_node<int> >(); 514*51c0b2f7Stbbdev test_resets<float, tbb::flow::queue_node<float> >(); 515*51c0b2f7Stbbdev } 516*51c0b2f7Stbbdev 517*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET 518*51c0b2f7Stbbdev //! Test follows and precedes API 519*51c0b2f7Stbbdev //! \brief \ref error_guessing 520*51c0b2f7Stbbdev TEST_CASE("Test follows and precedes API"){ 521*51c0b2f7Stbbdev test_follows_and_precedes_api(); 522*51c0b2f7Stbbdev } 523*51c0b2f7Stbbdev #endif 524*51c0b2f7Stbbdev 525*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 526*51c0b2f7Stbbdev //! Test decution guides 527*51c0b2f7Stbbdev //! \brief \ref requirement 528*51c0b2f7Stbbdev TEST_CASE("Deduction guides"){ 529*51c0b2f7Stbbdev test_deduction_guides(); 530*51c0b2f7Stbbdev } 531*51c0b2f7Stbbdev #endif 532*51c0b2f7Stbbdev 533*51c0b2f7Stbbdev //! Test operations on a reserved queue_node 534*51c0b2f7Stbbdev //! \brief \ref error_guessing 535*51c0b2f7Stbbdev TEST_CASE("queue_node with reservation"){ 536*51c0b2f7Stbbdev tbb::flow::graph g; 537*51c0b2f7Stbbdev 538*51c0b2f7Stbbdev tbb::flow::queue_node<int> q(g); 539*51c0b2f7Stbbdev 540*51c0b2f7Stbbdev bool res = q.try_put(42); 541*51c0b2f7Stbbdev CHECK_MESSAGE( res, "queue_node must accept input." ); 542*51c0b2f7Stbbdev 543*51c0b2f7Stbbdev int val = 1; 544*51c0b2f7Stbbdev res = q.try_reserve(val); 545*51c0b2f7Stbbdev CHECK_MESSAGE( res, "queue_node must reserve as it has an item." ); 546*51c0b2f7Stbbdev CHECK_MESSAGE( (val == 42), "queue_node must reserve once passed item." ); 547*51c0b2f7Stbbdev 548*51c0b2f7Stbbdev int out_arg = -1; 549*51c0b2f7Stbbdev CHECK_MESSAGE((q.try_reserve(out_arg) == false), "Reserving a reserved node should fail."); 550*51c0b2f7Stbbdev CHECK_MESSAGE((out_arg == -1), "Reserving a reserved node should not update its argument."); 551*51c0b2f7Stbbdev 552*51c0b2f7Stbbdev out_arg = -1; 553*51c0b2f7Stbbdev CHECK_MESSAGE((q.try_get(out_arg) == false), "Getting from reserved node should fail."); 554*51c0b2f7Stbbdev CHECK_MESSAGE((out_arg == -1), "Getting from reserved node should not update its argument."); 555*51c0b2f7Stbbdev g.wait_for_all(); 556*51c0b2f7Stbbdev 557*51c0b2f7Stbbdev } 558