1 /*
2     Copyright (c) 2005-2020 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 #if __TBB_CPF_BUILD
18 #define TBB_DEPRECATED_FLOW_NODE_EXTRACTION 1
19 #endif
20 
21 #include "harness.h"
22 #include "harness_graph.h"
23 
24 #include "tbb/flow_graph.h"
25 #include "tbb/task_scheduler_init.h"
26 #include "test_follows_and_precedes_api.h"
27 
28 #define N 300
29 #define T 4
30 #define M 4
31 
32 template< typename R >
simple_read_write_tests()33 void simple_read_write_tests() {
34     tbb::flow::graph g;
35     tbb::flow::write_once_node<R> n(g);
36 
37     for ( int t = 0; t < T; ++t ) {
38         R v0(0);
39         std::vector< harness_counting_receiver<R> > r(M, harness_counting_receiver<R>(g));
40 
41         ASSERT( n.is_valid() == false, NULL );
42         ASSERT( n.try_get( v0 ) == false, NULL );
43 
44         if ( t % 2 ) {
45             ASSERT( n.try_put( static_cast<R>(N+1) ), NULL );
46             ASSERT( n.is_valid() == true, NULL );
47             ASSERT( n.try_get( v0 ) == true, NULL );
48             ASSERT( v0 == R(N+1), NULL );
49         }
50 
51         for (int i = 0; i < M; ++i) {
52            tbb::flow::make_edge( n, r[i] );
53         }
54 
55         if ( t%2 ) {
56             for (int i = 0; i < M; ++i) {
57                  size_t c = r[i].my_count;
58                  ASSERT( int(c) == 1, NULL );
59             }
60         }
61 
62         for (int i = 1; i <= N; ++i ) {
63             R v1(static_cast<R>(i));
64 
65             bool result = n.try_put( v1 );
66             if ( !(t%2) && i == 1 )
67                 ASSERT( result == true, NULL );
68             else
69                 ASSERT( result == false, NULL );
70 
71             ASSERT( n.is_valid() == true, NULL );
72 
73             for (int j = 0; j < N; ++j ) {
74                 R v2(0);
75                 ASSERT( n.try_get( v2 ), NULL );
76                 if ( t%2 )
77                     ASSERT( R(N+1) == v2, NULL );
78                 else
79                     ASSERT( R(1) == v2, NULL );
80             }
81         }
82         for (int i = 0; i < M; ++i) {
83              size_t c = r[i].my_count;
84              ASSERT( int(c) == 1, NULL );
85         }
86         for (int i = 0; i < M; ++i) {
87            tbb::flow::remove_edge( n, r[i] );
88         }
89         ASSERT( n.try_put( R(0) ) == false, NULL );
90         for (int i = 0; i < M; ++i) {
91              size_t c = r[i].my_count;
92              ASSERT( int(c) == 1, NULL );
93         }
94         n.clear();
95         ASSERT( n.is_valid() == false, NULL );
96         ASSERT( n.try_get( v0 ) == false, NULL );
97     }
98 }
99 
100 template< typename R >
101 class native_body : NoAssign {
102     tbb::flow::write_once_node<R> &my_node;
103 
104 public:
105 
native_body(tbb::flow::write_once_node<R> & n)106      native_body( tbb::flow::write_once_node<R> &n ) : my_node(n) {}
107 
operator ()(int i) const108      void operator()( int i ) const {
109          R v1(static_cast<R>(i));
110          ASSERT( my_node.try_put( v1 ) == false, NULL );
111          ASSERT( my_node.is_valid() == true, NULL );
112          ASSERT( my_node.try_get( v1 ) == true, NULL );
113          ASSERT( v1 == R(-1), NULL );
114      }
115 };
116 
117 template< typename R >
parallel_read_write_tests()118 void parallel_read_write_tests() {
119     tbb::flow::graph g;
120     tbb::flow::write_once_node<R> n(g);
121     //Create a vector of identical nodes
122     std::vector< tbb::flow::write_once_node<R> > wo_vec(2, n);
123 
124     for (size_t node_idx=0; node_idx<wo_vec.size(); ++node_idx) {
125     for ( int t = 0; t < T; ++t ) {
126         std::vector< harness_counting_receiver<R> > r(M, harness_counting_receiver<R>(g));
127 
128         for (int i = 0; i < M; ++i) {
129            tbb::flow::make_edge( wo_vec[node_idx], r[i] );
130         }
131         R v0;
132         ASSERT( wo_vec[node_idx].is_valid() == false, NULL );
133         ASSERT( wo_vec[node_idx].try_get( v0 ) == false, NULL );
134 
135         ASSERT( wo_vec[node_idx].try_put( R(-1) ), NULL );
136 
137         NativeParallelFor( N, native_body<R>( wo_vec[node_idx] ) );
138 
139         for (int i = 0; i < M; ++i) {
140              size_t c = r[i].my_count;
141              ASSERT( int(c) == 1, NULL );
142         }
143         for (int i = 0; i < M; ++i) {
144            tbb::flow::remove_edge( wo_vec[node_idx], r[i] );
145         }
146         ASSERT( wo_vec[node_idx].try_put( R(0) ) == false, NULL );
147         for (int i = 0; i < M; ++i) {
148              size_t c = r[i].my_count;
149              ASSERT( int(c) == 1, NULL );
150         }
151         wo_vec[node_idx].clear();
152         ASSERT( wo_vec[node_idx].is_valid() == false, NULL );
153         ASSERT( wo_vec[node_idx].try_get( v0 ) == false, NULL );
154     }
155     }
156 }
157 
158 #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
159 #include <array>
160 #include <vector>
test_follows_and_precedes_api()161 void test_follows_and_precedes_api() {
162     using msg_t = tbb::flow::continue_msg;
163 
164     std::array<msg_t, 3> messages_for_follows= {msg_t(), msg_t(), msg_t()};
165     std::vector<msg_t> messages_for_precedes = {msg_t()};
166 
167     follows_and_precedes_testing::test_follows<msg_t, tbb::flow::write_once_node<msg_t>>(messages_for_follows);
168     follows_and_precedes_testing::test_precedes<msg_t, tbb::flow::write_once_node<msg_t>>(messages_for_precedes);
169 }
170 #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
171 
172 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
test_deduction_guides()173 void test_deduction_guides() {
174     using namespace tbb::flow;
175 
176     graph g;
177     broadcast_node<int> b1(g);
178     write_once_node<int> wo0(g);
179 
180 #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
181     write_once_node wo1(follows(b1));
182     static_assert(std::is_same_v<decltype(wo1), write_once_node<int>>);
183 
184     write_once_node wo2(precedes(b1));
185     static_assert(std::is_same_v<decltype(wo2), write_once_node<int>>);
186 #endif
187 
188     write_once_node wo3(wo0);
189     static_assert(std::is_same_v<decltype(wo3), write_once_node<int>>);
190 }
191 #endif
192 
TestMain()193 int TestMain() {
194     simple_read_write_tests<int>();
195     simple_read_write_tests<float>();
196     for( int p=MinThread; p<=MaxThread; ++p ) {
197         tbb::task_scheduler_init init(p);
198         parallel_read_write_tests<int>();
199         parallel_read_write_tests<float>();
200         test_reserving_nodes<tbb::flow::write_once_node, size_t>();
201     }
202 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
203     test_extract_on_node<tbb::flow::write_once_node, int>();
204 #endif
205 #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET
206     test_follows_and_precedes_api();
207 #endif
208 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
209     test_deduction_guides();
210 #endif
211     return Harness::Done;
212 }
213