xref: /oneTBB/test/tbb/test_write_once_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 
18*51c0b2f7Stbbdev #include "common/config.h"
19*51c0b2f7Stbbdev 
20*51c0b2f7Stbbdev // TODO revamp: move parts dependent on __TBB_EXTRA_DEBUG into separate test(s) since having these
21*51c0b2f7Stbbdev // parts in all of tests might make testing of the product, which is different from what is actually
22*51c0b2f7Stbbdev // released.
23*51c0b2f7Stbbdev #define __TBB_EXTRA_DEBUG 1
24*51c0b2f7Stbbdev #include "tbb/flow_graph.h"
25*51c0b2f7Stbbdev 
26*51c0b2f7Stbbdev #include "common/test.h"
27*51c0b2f7Stbbdev #include "common/utils.h"
28*51c0b2f7Stbbdev #include "common/utils_assert.h"
29*51c0b2f7Stbbdev #include "common/graph_utils.h"
30*51c0b2f7Stbbdev #include "common/test_follows_and_precedes_api.h"
31*51c0b2f7Stbbdev 
32*51c0b2f7Stbbdev #define N 300
33*51c0b2f7Stbbdev #define T 4
34*51c0b2f7Stbbdev #define M 4
35*51c0b2f7Stbbdev 
36*51c0b2f7Stbbdev 
37*51c0b2f7Stbbdev //! \file test_write_once_node.cpp
38*51c0b2f7Stbbdev //! \brief Test for [flow_graph.write_once_node] specification
39*51c0b2f7Stbbdev 
40*51c0b2f7Stbbdev 
41*51c0b2f7Stbbdev template< typename R >
42*51c0b2f7Stbbdev void simple_read_write_tests() {
43*51c0b2f7Stbbdev     tbb::flow::graph g;
44*51c0b2f7Stbbdev     tbb::flow::write_once_node<R> n(g);
45*51c0b2f7Stbbdev 
46*51c0b2f7Stbbdev     for ( int t = 0; t < T; ++t ) {
47*51c0b2f7Stbbdev         R v0(0);
48*51c0b2f7Stbbdev         std::vector< std::shared_ptr<harness_counting_receiver<R>> > r;
49*51c0b2f7Stbbdev         for (size_t i = 0; i < M; ++i) {
50*51c0b2f7Stbbdev             r.push_back( std::make_shared<harness_counting_receiver<R>>(g) );
51*51c0b2f7Stbbdev         }
52*51c0b2f7Stbbdev 
53*51c0b2f7Stbbdev 
54*51c0b2f7Stbbdev         CHECK_MESSAGE( n.is_valid() == false, "" );
55*51c0b2f7Stbbdev         CHECK_MESSAGE( n.try_get( v0 ) == false, "" );
56*51c0b2f7Stbbdev 
57*51c0b2f7Stbbdev         if ( t % 2 ) {
58*51c0b2f7Stbbdev             CHECK_MESSAGE( n.try_put( static_cast<R>(N+1) ), "" );
59*51c0b2f7Stbbdev             CHECK_MESSAGE( n.is_valid() == true, "" );
60*51c0b2f7Stbbdev             CHECK_MESSAGE( n.try_get( v0 ) == true, "" );
61*51c0b2f7Stbbdev             CHECK_MESSAGE( v0 == R(N+1), "" );
62*51c0b2f7Stbbdev         }
63*51c0b2f7Stbbdev 
64*51c0b2f7Stbbdev         for (int i = 0; i < M; ++i) {
65*51c0b2f7Stbbdev             tbb::flow::make_edge( n, *r[i] );
66*51c0b2f7Stbbdev         }
67*51c0b2f7Stbbdev 
68*51c0b2f7Stbbdev         if ( t%2 ) {
69*51c0b2f7Stbbdev             for (int i = 0; i < M; ++i) {
70*51c0b2f7Stbbdev                 size_t c = r[i]->my_count;
71*51c0b2f7Stbbdev                 CHECK_MESSAGE( int(c) == 1, "" );
72*51c0b2f7Stbbdev             }
73*51c0b2f7Stbbdev         }
74*51c0b2f7Stbbdev 
75*51c0b2f7Stbbdev         for (int i = 1; i <= N; ++i ) {
76*51c0b2f7Stbbdev             R v1(static_cast<R>(i));
77*51c0b2f7Stbbdev 
78*51c0b2f7Stbbdev             bool result = n.try_put( v1 );
79*51c0b2f7Stbbdev             if ( !(t%2) && i == 1 )
80*51c0b2f7Stbbdev                 CHECK_MESSAGE( result == true, "" );
81*51c0b2f7Stbbdev             else
82*51c0b2f7Stbbdev                 CHECK_MESSAGE( result == false, "" );
83*51c0b2f7Stbbdev 
84*51c0b2f7Stbbdev             CHECK_MESSAGE( n.is_valid() == true, "" );
85*51c0b2f7Stbbdev 
86*51c0b2f7Stbbdev             for (int j = 0; j < N; ++j ) {
87*51c0b2f7Stbbdev                 R v2(0);
88*51c0b2f7Stbbdev                 CHECK_MESSAGE( n.try_get( v2 ), "" );
89*51c0b2f7Stbbdev                 if ( t%2 )
90*51c0b2f7Stbbdev                     CHECK_MESSAGE( R(N+1) == v2, "" );
91*51c0b2f7Stbbdev                 else
92*51c0b2f7Stbbdev                     CHECK_MESSAGE( R(1) == v2, "" );
93*51c0b2f7Stbbdev             }
94*51c0b2f7Stbbdev         }
95*51c0b2f7Stbbdev         for (int i = 0; i < M; ++i) {
96*51c0b2f7Stbbdev             size_t c = r[i]->my_count;
97*51c0b2f7Stbbdev             CHECK_MESSAGE( int(c) == 1, "" );
98*51c0b2f7Stbbdev         }
99*51c0b2f7Stbbdev         for (int i = 0; i < M; ++i) {
100*51c0b2f7Stbbdev             tbb::flow::remove_edge( n, *r[i] );
101*51c0b2f7Stbbdev         }
102*51c0b2f7Stbbdev         CHECK_MESSAGE( n.try_put( R(0) ) == false, "" );
103*51c0b2f7Stbbdev         for (int i = 0; i < M; ++i) {
104*51c0b2f7Stbbdev             size_t c = r[i]->my_count;
105*51c0b2f7Stbbdev             CHECK_MESSAGE( int(c) == 1, "" );
106*51c0b2f7Stbbdev         }
107*51c0b2f7Stbbdev         n.clear();
108*51c0b2f7Stbbdev         CHECK_MESSAGE( n.is_valid() == false, "" );
109*51c0b2f7Stbbdev         CHECK_MESSAGE( n.try_get( v0 ) == false, "" );
110*51c0b2f7Stbbdev     }
111*51c0b2f7Stbbdev }
112*51c0b2f7Stbbdev 
113*51c0b2f7Stbbdev template< typename R >
114*51c0b2f7Stbbdev class native_body : utils::NoAssign {
115*51c0b2f7Stbbdev     tbb::flow::write_once_node<R> &my_node;
116*51c0b2f7Stbbdev 
117*51c0b2f7Stbbdev public:
118*51c0b2f7Stbbdev 
119*51c0b2f7Stbbdev     native_body( tbb::flow::write_once_node<R> &n ) : my_node(n) {}
120*51c0b2f7Stbbdev 
121*51c0b2f7Stbbdev     void operator()( int i ) const {
122*51c0b2f7Stbbdev         R v1(static_cast<R>(i));
123*51c0b2f7Stbbdev         CHECK_MESSAGE( my_node.try_put( v1 ) == false, "" );
124*51c0b2f7Stbbdev         CHECK_MESSAGE( my_node.is_valid() == true, "" );
125*51c0b2f7Stbbdev         CHECK_MESSAGE( my_node.try_get( v1 ) == true, "" );
126*51c0b2f7Stbbdev         CHECK_MESSAGE( v1 == R(-1), "" );
127*51c0b2f7Stbbdev     }
128*51c0b2f7Stbbdev };
129*51c0b2f7Stbbdev 
130*51c0b2f7Stbbdev template< typename R >
131*51c0b2f7Stbbdev void parallel_read_write_tests() {
132*51c0b2f7Stbbdev     tbb::flow::graph g;
133*51c0b2f7Stbbdev     tbb::flow::write_once_node<R> n(g);
134*51c0b2f7Stbbdev     //Create a vector of identical nodes
135*51c0b2f7Stbbdev     std::vector< tbb::flow::write_once_node<R> > wo_vec(2, n);
136*51c0b2f7Stbbdev 
137*51c0b2f7Stbbdev     for (size_t node_idx=0; node_idx<wo_vec.size(); ++node_idx) {
138*51c0b2f7Stbbdev         for ( int t = 0; t < T; ++t ) {
139*51c0b2f7Stbbdev             std::vector< std::shared_ptr<harness_counting_receiver<R>> > r;
140*51c0b2f7Stbbdev             for (size_t i = 0; i < M; ++i) {
141*51c0b2f7Stbbdev                 r.push_back( std::make_shared<harness_counting_receiver<R>>(g) );
142*51c0b2f7Stbbdev             }
143*51c0b2f7Stbbdev 
144*51c0b2f7Stbbdev 
145*51c0b2f7Stbbdev             for (int i = 0; i < M; ++i) {
146*51c0b2f7Stbbdev                 tbb::flow::make_edge( wo_vec[node_idx], *r[i] );
147*51c0b2f7Stbbdev             }
148*51c0b2f7Stbbdev             R v0;
149*51c0b2f7Stbbdev             CHECK_MESSAGE( wo_vec[node_idx].is_valid() == false, "" );
150*51c0b2f7Stbbdev             CHECK_MESSAGE( wo_vec[node_idx].try_get( v0 ) == false, "" );
151*51c0b2f7Stbbdev 
152*51c0b2f7Stbbdev             CHECK_MESSAGE( wo_vec[node_idx].try_put( R(-1) ), "" );
153*51c0b2f7Stbbdev #if TBB_TEST_LOW_WORKLOAD
154*51c0b2f7Stbbdev             const int nthreads = 30;
155*51c0b2f7Stbbdev #else
156*51c0b2f7Stbbdev             const int nthreads = N;
157*51c0b2f7Stbbdev #endif
158*51c0b2f7Stbbdev             utils::NativeParallelFor( nthreads, native_body<R>( wo_vec[node_idx] ) );
159*51c0b2f7Stbbdev 
160*51c0b2f7Stbbdev             for (int i = 0; i < M; ++i) {
161*51c0b2f7Stbbdev                 size_t c = r[i]->my_count;
162*51c0b2f7Stbbdev                 CHECK_MESSAGE( int(c) == 1, "" );
163*51c0b2f7Stbbdev             }
164*51c0b2f7Stbbdev             for (int i = 0; i < M; ++i) {
165*51c0b2f7Stbbdev                 tbb::flow::remove_edge( wo_vec[node_idx], *r[i] );
166*51c0b2f7Stbbdev             }
167*51c0b2f7Stbbdev             CHECK_MESSAGE( wo_vec[node_idx].try_put( R(0) ) == false, "" );
168*51c0b2f7Stbbdev             for (int i = 0; i < M; ++i) {
169*51c0b2f7Stbbdev                 size_t c = r[i]->my_count;
170*51c0b2f7Stbbdev                 CHECK_MESSAGE( int(c) == 1, "" );
171*51c0b2f7Stbbdev             }
172*51c0b2f7Stbbdev             wo_vec[node_idx].clear();
173*51c0b2f7Stbbdev             CHECK_MESSAGE( wo_vec[node_idx].is_valid() == false, "" );
174*51c0b2f7Stbbdev             CHECK_MESSAGE( wo_vec[node_idx].try_get( v0 ) == false, "" );
175*51c0b2f7Stbbdev         }
176*51c0b2f7Stbbdev     }
177*51c0b2f7Stbbdev }
178*51c0b2f7Stbbdev 
179*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
180*51c0b2f7Stbbdev #include <array>
181*51c0b2f7Stbbdev #include <vector>
182*51c0b2f7Stbbdev void test_follows_and_precedes_api() {
183*51c0b2f7Stbbdev     using msg_t = tbb::flow::continue_msg;
184*51c0b2f7Stbbdev 
185*51c0b2f7Stbbdev     std::array<msg_t, 3> messages_for_follows= {msg_t(), msg_t(), msg_t()};
186*51c0b2f7Stbbdev     std::vector<msg_t> messages_for_precedes = {msg_t()};
187*51c0b2f7Stbbdev 
188*51c0b2f7Stbbdev     follows_and_precedes_testing::test_follows<msg_t, tbb::flow::write_once_node<msg_t>>(messages_for_follows);
189*51c0b2f7Stbbdev     follows_and_precedes_testing::test_precedes<msg_t, tbb::flow::write_once_node<msg_t>>(messages_for_precedes);
190*51c0b2f7Stbbdev }
191*51c0b2f7Stbbdev #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
192*51c0b2f7Stbbdev 
193*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
194*51c0b2f7Stbbdev void test_deduction_guides() {
195*51c0b2f7Stbbdev     using namespace tbb::flow;
196*51c0b2f7Stbbdev 
197*51c0b2f7Stbbdev     graph g;
198*51c0b2f7Stbbdev     broadcast_node<int> b1(g);
199*51c0b2f7Stbbdev     write_once_node<int> wo0(g);
200*51c0b2f7Stbbdev 
201*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
202*51c0b2f7Stbbdev     write_once_node wo1(follows(b1));
203*51c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(wo1), write_once_node<int>>);
204*51c0b2f7Stbbdev 
205*51c0b2f7Stbbdev     write_once_node wo2(precedes(b1));
206*51c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(wo2), write_once_node<int>>);
207*51c0b2f7Stbbdev #endif
208*51c0b2f7Stbbdev 
209*51c0b2f7Stbbdev     write_once_node wo3(wo0);
210*51c0b2f7Stbbdev     static_assert(std::is_same_v<decltype(wo3), write_once_node<int>>);
211*51c0b2f7Stbbdev }
212*51c0b2f7Stbbdev #endif
213*51c0b2f7Stbbdev 
214*51c0b2f7Stbbdev //! Test read-write properties
215*51c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing
216*51c0b2f7Stbbdev TEST_CASE("Read-write tests"){
217*51c0b2f7Stbbdev     simple_read_write_tests<int>();
218*51c0b2f7Stbbdev     simple_read_write_tests<float>();
219*51c0b2f7Stbbdev }
220*51c0b2f7Stbbdev 
221*51c0b2f7Stbbdev //! Test read-write properties under parallelism
222*51c0b2f7Stbbdev //! \brief \ref requirement \ref error_guessing \ref stress
223*51c0b2f7Stbbdev TEST_CASE("Parallel read-write tests"){
224*51c0b2f7Stbbdev     for( unsigned int p=utils::MinThread; p<=utils::MaxThread; ++p ) {
225*51c0b2f7Stbbdev         tbb::task_arena arena(p);
226*51c0b2f7Stbbdev         arena.execute(
227*51c0b2f7Stbbdev             [&]() {
228*51c0b2f7Stbbdev                 parallel_read_write_tests<int>();
229*51c0b2f7Stbbdev                 parallel_read_write_tests<float>();
230*51c0b2f7Stbbdev                 test_reserving_nodes<tbb::flow::write_once_node, size_t>();
231*51c0b2f7Stbbdev             }
232*51c0b2f7Stbbdev         );
233*51c0b2f7Stbbdev 	}
234*51c0b2f7Stbbdev }
235*51c0b2f7Stbbdev 
236*51c0b2f7Stbbdev #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
237*51c0b2f7Stbbdev //! Test deprecated follows and precedes API
238*51c0b2f7Stbbdev //! \brief \ref error_guessing
239*51c0b2f7Stbbdev TEST_CASE("Test follows and precedes API"){
240*51c0b2f7Stbbdev     test_follows_and_precedes_api();
241*51c0b2f7Stbbdev }
242*51c0b2f7Stbbdev #endif
243*51c0b2f7Stbbdev 
244*51c0b2f7Stbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
245*51c0b2f7Stbbdev //! Test deduction guides
246*51c0b2f7Stbbdev //! \brief \ref requirement
247*51c0b2f7Stbbdev TEST_CASE("Deduction guides"){
248*51c0b2f7Stbbdev     test_deduction_guides();
249*51c0b2f7Stbbdev }
250*51c0b2f7Stbbdev #endif
251