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