xref: /oneTBB/test/tbb/test_tbb_header.cpp (revision b15aabb3)
1 /*
2     Copyright (c) 2005-2021 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 //! \file test_tbb_header.cpp
18 //! \brief Test for [all] specification
19 
20 /**
21     This test ensures that tbb.h brings in all the public TBB interface definitions,
22     and if all the necessary symbols are exported from the library.
23 
24     Most of the checks happen at the compilation or link phases.
25 **/
26 
27 #if __INTEL_COMPILER && _MSC_VER
28 #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
29 #endif
30 
31 #define __TBB_NO_IMPLICIT_LINKAGE 1
32 
33 #if __TBB_CPF_BUILD
34 // Add testing of preview features
35 #define TBB_PREVIEW_CONCURRENT_LRU_CACHE 1
36 #define TBB_PREVIEW_VARIADIC_PARALLEL_INVOKE 1
37 #define TBB_PREVIEW_BLOCKED_RANGE_ND 1
38 #define TBB_PREVIEW_ISOLATED_TASK_GROUP 1
39 #endif
40 
41 #if __TBB_TEST_SECONDARY
42     // Test _DEBUG macro custom definitions.
43     #if TBB_USE_DEBUG
44         #ifdef _DEBUG
45             #undef _DEBUG
46         #endif /* _DEBUG */
47         // Check that empty value successfully enables the debug mode.
48         #define _DEBUG
49         static bool isDebugExpected = true;
50     #else
51         // Check that zero value does not enable the debug mode.
52         #define _DEBUG 0x0
53         static bool isDebugExpected = false;
54     #endif /* TBB_USE_DEBUG */
55     #define DO_TEST_DEBUG_MACRO 1
56 #else
57     // Test default definitions of _DEBUG.
58     #if _DEBUG
59         static bool isDebugExpected = true;
60         #define DO_TEST_DEBUG_MACRO 1
61     #elif _MSC_VER
62         // for MSVC, _DEBUG not defined indicates a release mode.
63         static bool isDebugExpected = false;
64         #define DO_TEST_DEBUG_MACRO 1
65     #endif /* _DEBUG */
66 #endif /* __TBB_TEST_SECONDARY */
67 
68 #if DO_TEST_DEBUG_MACRO
69 // Reset TBB_USE_DEBUG defined in makefiles.
70 #undef TBB_USE_DEBUG
71 #endif /* DO_TEST_DEBUG_MACRO */
72 #define __TBB_CONFIG_PREPROC_ONLY _MSC_VER // For MSVC, prevent including standard headers in tbb_config.h
73 #include "oneapi/tbb/detail/_config.h"
74 
75 #if !TBB_USE_DEBUG && defined(_DEBUG)
76 // TBB_USE_DEBUG is 0 but _DEBUG is defined, it means that _DEBUG is 0
77 // MSVC C++ headers consider any definition of _DEBUG, including 0, as debug mode
78 #undef _DEBUG
79 #endif /* !TBB_USE_DEBUG && defined(_DEBUG) */
80 
81 #include "tbb/tbb.h"
82 
83 #if !__TBB_TEST_SECONDARY
84 #include "common/test.h"
85 #endif
86 
87 static volatile size_t g_sink;
88 
89 #define TestTypeDefinitionPresence( Type ) g_sink = sizeof(tbb::Type);
90 #define TestTypeDefinitionPresence2(TypeStart, TypeEnd) g_sink = sizeof(tbb::TypeStart,TypeEnd);
91 #define TestTypeDefinitionPresence3(TypeStart, TypeMid, TypeEnd) g_sink = sizeof(tbb::TypeStart,TypeMid,TypeEnd);
92 #define TestFuncDefinitionPresence(Fn, Args, ReturnType) { ReturnType (*pfn)Args = &tbb::Fn; (void)pfn; }
93 
94 struct Body {
95     void operator() () const {}
96 };
97 struct Body1 {
98     void operator() ( int ) const {}
99 };
100 struct Body1a { // feeder body for parallel_do
101     void operator() ( int, tbb::feeder<int>& ) const {}
102 };
103 struct Body1b { // binary operator for reduction and comparison
104     int operator() ( const int, const int ) const { return 0; }
105 };
106 struct Body2 {
107     Body2 () {}
108     Body2 ( const Body2&, tbb::split ) {}
109     void operator() ( const tbb::blocked_range<int>& ) const {}
110     void join( const Body2& ) {}
111 };
112 struct Body2a { // for lambda-friendly parallel_reduce
113     int operator() ( const tbb::blocked_range<int>&, const int ) const { return 0; }
114 };
115 struct Body3 { // for parallel_scan
116     Body3 () {}
117     Body3 ( const Body3&, tbb::split ) {}
118     void operator() ( const tbb::blocked_range2d<int>&, tbb::pre_scan_tag ) const {}
119     void operator() ( const tbb::blocked_range2d<int>&, tbb::final_scan_tag ) const {}
120     void reverse_join( Body3& ) {}
121     void assign( const Body3& ) {}
122 };
123 struct Body3a { // for lambda-friednly parallel_scan
124     int operator() ( const tbb::blocked_range<int>&, const int, bool ) const { return 0; }
125 };
126 struct Msg {};
127 
128 // Test if all the necessary symbols are exported for the exceptions thrown by TBB.
129 // Missing exports result either in link error or in runtime assertion failure.
130 #include <stdexcept>
131 
132 template <typename E>
133 void TestExceptionClassExports ( const E& exc, tbb::detail::exception_id eid ) {
134     CHECK( eid < tbb::detail::exception_id::last_entry );
135 #if TBB_USE_EXCEPTIONS
136     for ( int i = 0; i < 2; ++i ) {
137         try {
138             if ( i == 0 )
139                 throw exc;
140             else
141                 tbb::detail::throw_exception( eid );
142         }
143         catch ( E& e ) {
144             CHECK_MESSAGE( e.what(), "Missing what() string" );
145         }
146         catch ( ... ) {
147             CHECK_MESSAGE( false, "Unrecognized exception. Likely RTTI related exports are missing" );
148         }
149     }
150 #else /* TBB_USE_EXCEPTIONS */
151     (void)exc;
152 #endif /* TBB_USE_EXCEPTIONS */
153 }
154 
155 static void TestExceptionClassesExports () {
156     TestExceptionClassExports( std::bad_alloc(), tbb::detail::exception_id::bad_alloc );
157     TestExceptionClassExports( tbb::bad_last_alloc(), tbb::detail::exception_id::bad_last_alloc );
158     TestExceptionClassExports( std::invalid_argument("test"), tbb::detail::exception_id::nonpositive_step );
159     TestExceptionClassExports( std::out_of_range("test"), tbb::detail::exception_id::out_of_range );
160     TestExceptionClassExports( tbb::missing_wait(), tbb::detail::exception_id::missing_wait );
161     TestExceptionClassExports( std::out_of_range("test"), tbb::detail::exception_id::invalid_load_factor );
162     TestExceptionClassExports( std::length_error("test"), tbb::detail::exception_id::reservation_length_error );
163     TestExceptionClassExports( std::out_of_range("test"), tbb::detail::exception_id::invalid_key );
164     TestExceptionClassExports( tbb::user_abort(), tbb::detail::exception_id::user_abort );
165     TestExceptionClassExports( std::runtime_error("test"), tbb::detail::exception_id::bad_tagged_msg_cast );
166 }
167 
168 #if __TBB_CPF_BUILD
169 // These names are only tested in "preview" configuration
170 // When a feature becomes fully supported, its names should be moved to the main test
171 static void TestPreviewNames() {
172     TestTypeDefinitionPresence2( blocked_rangeNd<int,4> );
173     TestTypeDefinitionPresence2( concurrent_lru_cache<int, int> );
174     TestTypeDefinitionPresence( isolated_task_group );
175 }
176 #endif
177 
178 static void DefinitionPresence() {
179     TestTypeDefinitionPresence( cache_aligned_allocator<int> );
180     TestTypeDefinitionPresence( tbb_hash_compare<int> );
181     TestTypeDefinitionPresence2( concurrent_hash_map<int, int> );
182     TestTypeDefinitionPresence2( concurrent_unordered_map<int, int> );
183     TestTypeDefinitionPresence2( concurrent_unordered_multimap<int, int> );
184     TestTypeDefinitionPresence( concurrent_unordered_set<int> );
185     TestTypeDefinitionPresence( concurrent_unordered_multiset<int> );
186     TestTypeDefinitionPresence2( concurrent_map<int, int> );
187     TestTypeDefinitionPresence2( concurrent_multimap<int, int> );
188     TestTypeDefinitionPresence( concurrent_set<int> );
189     TestTypeDefinitionPresence( concurrent_multiset<int> );
190     TestTypeDefinitionPresence( concurrent_bounded_queue<int> );
191     TestTypeDefinitionPresence( concurrent_queue<int> );
192     TestTypeDefinitionPresence( concurrent_priority_queue<int> );
193     TestTypeDefinitionPresence( concurrent_vector<int> );
194     TestTypeDefinitionPresence( combinable<int> );
195     TestTypeDefinitionPresence( enumerable_thread_specific<int> );
196     /* Flow graph names */
197     TestTypeDefinitionPresence( flow::graph );
198     TestTypeDefinitionPresence( flow::continue_msg );
199     TestTypeDefinitionPresence2(flow::tagged_msg<int, int> );
200     TestFuncDefinitionPresence( flow::make_edge, (tbb::flow::sender<Msg>&, tbb::flow::receiver<Msg>&), void );
201     TestFuncDefinitionPresence( flow::remove_edge, (tbb::flow::sender<Msg>&, tbb::flow::receiver<Msg>&), void );
202     typedef std::tuple<int, int> intpair;
203     TestTypeDefinitionPresence( flow::input_node<int> );
204     TestTypeDefinitionPresence3(flow::function_node<int, int, tbb::flow::rejecting> );
205     TestTypeDefinitionPresence3(flow::multifunction_node<int, intpair, tbb::flow::queueing> );
206     TestTypeDefinitionPresence3(flow::async_node<int, int, tbb::flow::queueing_lightweight> );
207     TestTypeDefinitionPresence2(flow::continue_node<int, tbb::flow::lightweight> );
208     TestTypeDefinitionPresence2(flow::join_node<intpair, tbb::flow::reserving> );
209     TestTypeDefinitionPresence2(flow::join_node<intpair, tbb::flow::key_matching<int> > );
210     TestTypeDefinitionPresence( flow::split_node<intpair> );
211     TestTypeDefinitionPresence( flow::overwrite_node<int> );
212     TestTypeDefinitionPresence( flow::write_once_node<int> );
213     TestTypeDefinitionPresence( flow::broadcast_node<int> );
214     TestTypeDefinitionPresence( flow::buffer_node<int> );
215     TestTypeDefinitionPresence( flow::queue_node<int> );
216     TestTypeDefinitionPresence( flow::sequencer_node<int> );
217     TestTypeDefinitionPresence( flow::priority_queue_node<int> );
218     TestTypeDefinitionPresence( flow::limiter_node<int> );
219     TestTypeDefinitionPresence2(flow::indexer_node<int, int> );
220     TestTypeDefinitionPresence2(flow::composite_node<std::tuple<int>, std::tuple<int> > );
221     /* Mutex names */
222     TestTypeDefinitionPresence( null_mutex );
223     TestTypeDefinitionPresence( null_rw_mutex );
224     TestTypeDefinitionPresence( queuing_mutex );
225     TestTypeDefinitionPresence( queuing_rw_mutex );
226     TestTypeDefinitionPresence( spin_mutex );
227     TestTypeDefinitionPresence( spin_rw_mutex );
228     TestTypeDefinitionPresence( speculative_spin_mutex );
229     TestTypeDefinitionPresence( speculative_spin_rw_mutex );
230     TestTypeDefinitionPresence( task_group_context );
231     TestTypeDefinitionPresence( task_group );
232     /* Algorithm related names */
233     TestTypeDefinitionPresence( blocked_range<int> );
234     TestTypeDefinitionPresence( blocked_range2d<int> );
235     TestTypeDefinitionPresence( blocked_range3d<int> );
236     TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&, const Body&), void );
237     TestFuncDefinitionPresence( parallel_for_each, (int*, int*, const Body1&), void );
238     TestFuncDefinitionPresence( parallel_for, (int, int, int, const Body1&), void );
239     TestFuncDefinitionPresence( parallel_for, (const tbb::blocked_range<int>&, const Body2&, const tbb::simple_partitioner&), void );
240     TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, const int&, const Body2a&, const Body1b&), int );
241     TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::affinity_partitioner&), void );
242     TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, const int&, const Body2a&, const Body1b&), int );
243     TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::static_partitioner&), void );
244     TestFuncDefinitionPresence( parallel_scan, (const tbb::blocked_range2d<int>&, Body3&, const tbb::auto_partitioner&), void );
245     TestFuncDefinitionPresence( parallel_scan, (const tbb::blocked_range<int>&, const int&, const Body3a&, const Body1b&), int );
246     typedef int intarray[10];
247     TestFuncDefinitionPresence( parallel_sort, (int*, int*), void );
248     TestFuncDefinitionPresence( parallel_sort, (intarray&, const Body1b&), void );
249     TestFuncDefinitionPresence( parallel_pipeline, (size_t, const tbb::filter<void,void>&), void );
250     TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&, tbb::task_group_context&), void );
251     TestFuncDefinitionPresence( parallel_for_each, (const intarray&, const Body1a&, tbb::task_group_context&), void );
252     TestFuncDefinitionPresence( parallel_for, (int, int, const Body1&, const tbb::auto_partitioner&, tbb::task_group_context&), void );
253     TestFuncDefinitionPresence( parallel_for, (int, int, const Body1&, tbb::task_group_context&), void );
254     TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::auto_partitioner&, tbb::task_group_context&), void );
255     TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::task_group_context&), void );
256     TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::simple_partitioner&, tbb::task_group_context&), void );
257     TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::task_group_context&), void );
258     TestTypeDefinitionPresence( proportional_split );
259 
260     TestTypeDefinitionPresence( task_arena );
261     TestFuncDefinitionPresence( this_task_arena::current_thread_index, (), int );
262     TestFuncDefinitionPresence( this_task_arena::max_concurrency, (), int );
263     TestFuncDefinitionPresence( info::numa_nodes, (), std::vector<tbb::numa_node_id> );
264     TestFuncDefinitionPresence( info::default_concurrency, (tbb::numa_node_id), int );
265     TestTypeDefinitionPresence( task_scheduler_observer );
266     TestTypeDefinitionPresence( tbb_allocator<int> );
267     TestTypeDefinitionPresence( tick_count );
268     TestTypeDefinitionPresence( global_control );
269 
270 #if __TBB_CPF_BUILD
271     TestPreviewNames();
272 #endif
273 #ifdef DO_TEST_DEBUG_MACRO
274 #if TBB_USE_DEBUG
275     CHECK_MESSAGE( isDebugExpected, "Debug mode is observed while release mode is expected." );
276 #else
277     CHECK_MESSAGE( !isDebugExpected, "Release mode is observed while debug mode is expected." );
278 #endif /* TBB_USE_DEBUG */
279 #endif /* DO_TEST_DEBUG_MACRO */
280     TestExceptionClassesExports();
281 }
282 
283 #if __TBB_TEST_SECONDARY
284 /* This mode is used to produce a secondary object file that is linked with
285    the main one in order to detect "multiple definition" linker error.
286 */
287 void Secondary() {
288     DefinitionPresence();
289 }
290 #else
291 //! Test for deifinition presence
292 //! \brief \ref interface
293 TEST_CASE("Test for deifinition presence") {
294     DefinitionPresence();
295 }
296 
297 void Secondary();
298 //! Test for "multiple definition" linker error
299 //! \brief \ref error_guessing
300 TEST_CASE("Test for multiple definition linker error") {
301     Secondary();
302 }
303 #endif
304