xref: /oneTBB/test/tbb/test_tbb_header.cpp (revision 6caecf96)
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
104     int operator() ( const int, const int ) const { return 0; }
105 };
106 struct Body1bc { // binary operator for comparison
107     bool operator() (const int, const int) const { return false; }
108 };
109 struct Body2 {
110     Body2 () {}
111     Body2 ( const Body2&, tbb::split ) {}
112     void operator() ( const tbb::blocked_range<int>& ) const {}
113     void join( const Body2& ) {}
114 };
115 struct Body2a { // for lambda-friendly parallel_reduce
116     int operator() ( const tbb::blocked_range<int>&, const int ) const { return 0; }
117 };
118 struct Body3 { // for parallel_scan
119     Body3 () {}
120     Body3 ( const Body3&, tbb::split ) {}
121     void operator() ( const tbb::blocked_range2d<int>&, tbb::pre_scan_tag ) const {}
122     void operator() ( const tbb::blocked_range2d<int>&, tbb::final_scan_tag ) const {}
123     void reverse_join( Body3& ) {}
124     void assign( const Body3& ) {}
125 };
126 struct Body3a { // for lambda-friednly parallel_scan
127     int operator() ( const tbb::blocked_range<int>&, const int, bool ) const { return 0; }
128 };
129 struct Msg {};
130 
131 // Test if all the necessary symbols are exported for the exceptions thrown by TBB.
132 // Missing exports result either in link error or in runtime assertion failure.
133 #include <stdexcept>
134 
135 template <typename E>
136 void TestExceptionClassExports ( const E& exc, tbb::detail::exception_id eid ) {
137     CHECK( eid < tbb::detail::exception_id::last_entry );
138 #if TBB_USE_EXCEPTIONS
139     for ( int i = 0; i < 2; ++i ) {
140         try {
141             if ( i == 0 )
142                 throw exc;
143             else
144                 tbb::detail::throw_exception( eid );
145         }
146         catch ( E& e ) {
147             CHECK_MESSAGE( e.what(), "Missing what() string" );
148         }
149         catch ( ... ) {
150             CHECK_MESSAGE( false, "Unrecognized exception. Likely RTTI related exports are missing" );
151         }
152     }
153 #else /* TBB_USE_EXCEPTIONS */
154     (void)exc;
155 #endif /* TBB_USE_EXCEPTIONS */
156 }
157 
158 static void TestExceptionClassesExports () {
159     TestExceptionClassExports( std::bad_alloc(), tbb::detail::exception_id::bad_alloc );
160     TestExceptionClassExports( tbb::bad_last_alloc(), tbb::detail::exception_id::bad_last_alloc );
161     TestExceptionClassExports( std::invalid_argument("test"), tbb::detail::exception_id::nonpositive_step );
162     TestExceptionClassExports( std::out_of_range("test"), tbb::detail::exception_id::out_of_range );
163     TestExceptionClassExports( tbb::missing_wait(), tbb::detail::exception_id::missing_wait );
164     TestExceptionClassExports( std::out_of_range("test"), tbb::detail::exception_id::invalid_load_factor );
165     TestExceptionClassExports( std::length_error("test"), tbb::detail::exception_id::reservation_length_error );
166     TestExceptionClassExports( std::out_of_range("test"), tbb::detail::exception_id::invalid_key );
167     TestExceptionClassExports( tbb::user_abort(), tbb::detail::exception_id::user_abort );
168     TestExceptionClassExports( std::runtime_error("test"), tbb::detail::exception_id::bad_tagged_msg_cast );
169 }
170 
171 #if __TBB_CPF_BUILD
172 // These names are only tested in "preview" configuration
173 // When a feature becomes fully supported, its names should be moved to the main test
174 static void TestPreviewNames() {
175     TestTypeDefinitionPresence2( blocked_rangeNd<int,4> );
176     TestTypeDefinitionPresence2( concurrent_lru_cache<int, int> );
177     TestTypeDefinitionPresence( isolated_task_group );
178 }
179 #endif
180 
181 static void DefinitionPresence() {
182     TestTypeDefinitionPresence( cache_aligned_allocator<int> );
183     TestTypeDefinitionPresence( tbb_hash_compare<int> );
184     TestTypeDefinitionPresence2( concurrent_hash_map<int, int> );
185     TestTypeDefinitionPresence2( concurrent_unordered_map<int, int> );
186     TestTypeDefinitionPresence2( concurrent_unordered_multimap<int, int> );
187     TestTypeDefinitionPresence( concurrent_unordered_set<int> );
188     TestTypeDefinitionPresence( concurrent_unordered_multiset<int> );
189     TestTypeDefinitionPresence2( concurrent_map<int, int> );
190     TestTypeDefinitionPresence2( concurrent_multimap<int, int> );
191     TestTypeDefinitionPresence( concurrent_set<int> );
192     TestTypeDefinitionPresence( concurrent_multiset<int> );
193     TestTypeDefinitionPresence( concurrent_bounded_queue<int> );
194     TestTypeDefinitionPresence( concurrent_queue<int> );
195     TestTypeDefinitionPresence( concurrent_priority_queue<int> );
196     TestTypeDefinitionPresence( concurrent_vector<int> );
197     TestTypeDefinitionPresence( combinable<int> );
198     TestTypeDefinitionPresence( enumerable_thread_specific<int> );
199     /* Flow graph names */
200     TestTypeDefinitionPresence( flow::graph );
201     TestTypeDefinitionPresence( flow::continue_msg );
202     TestTypeDefinitionPresence2(flow::tagged_msg<int, int> );
203     TestFuncDefinitionPresence( flow::make_edge, (tbb::flow::sender<Msg>&, tbb::flow::receiver<Msg>&), void );
204     TestFuncDefinitionPresence( flow::remove_edge, (tbb::flow::sender<Msg>&, tbb::flow::receiver<Msg>&), void );
205     typedef std::tuple<int, int> intpair;
206     TestTypeDefinitionPresence( flow::input_node<int> );
207     TestTypeDefinitionPresence3(flow::function_node<int, int, tbb::flow::rejecting> );
208     TestTypeDefinitionPresence3(flow::multifunction_node<int, intpair, tbb::flow::queueing> );
209     TestTypeDefinitionPresence3(flow::async_node<int, int, tbb::flow::queueing_lightweight> );
210     TestTypeDefinitionPresence2(flow::continue_node<int, tbb::flow::lightweight> );
211     TestTypeDefinitionPresence2(flow::join_node<intpair, tbb::flow::reserving> );
212     TestTypeDefinitionPresence2(flow::join_node<intpair, tbb::flow::key_matching<int> > );
213     TestTypeDefinitionPresence( flow::split_node<intpair> );
214     TestTypeDefinitionPresence( flow::overwrite_node<int> );
215     TestTypeDefinitionPresence( flow::write_once_node<int> );
216     TestTypeDefinitionPresence( flow::broadcast_node<int> );
217     TestTypeDefinitionPresence( flow::buffer_node<int> );
218     TestTypeDefinitionPresence( flow::queue_node<int> );
219     TestTypeDefinitionPresence( flow::sequencer_node<int> );
220     TestTypeDefinitionPresence( flow::priority_queue_node<int> );
221     TestTypeDefinitionPresence( flow::limiter_node<int> );
222     TestTypeDefinitionPresence2(flow::indexer_node<int, int> );
223     TestTypeDefinitionPresence2(flow::composite_node<std::tuple<int>, std::tuple<int> > );
224     /* Mutex names */
225     TestTypeDefinitionPresence( null_mutex );
226     TestTypeDefinitionPresence( null_rw_mutex );
227     TestTypeDefinitionPresence( queuing_mutex );
228     TestTypeDefinitionPresence( queuing_rw_mutex );
229     TestTypeDefinitionPresence( spin_mutex );
230     TestTypeDefinitionPresence( spin_rw_mutex );
231     TestTypeDefinitionPresence( speculative_spin_mutex );
232     TestTypeDefinitionPresence( speculative_spin_rw_mutex );
233     TestTypeDefinitionPresence( task_group_context );
234     TestTypeDefinitionPresence( task_group );
235     /* Algorithm related names */
236     TestTypeDefinitionPresence( blocked_range<int> );
237     TestTypeDefinitionPresence( blocked_range2d<int> );
238     TestTypeDefinitionPresence( blocked_range3d<int> );
239     TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&, const Body&), void );
240     TestFuncDefinitionPresence( parallel_for_each, (int*, int*, const Body1&), void );
241     TestFuncDefinitionPresence( parallel_for, (int, int, int, const Body1&), void );
242     TestFuncDefinitionPresence( parallel_for, (const tbb::blocked_range<int>&, const Body2&, const tbb::simple_partitioner&), void );
243     TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, const int&, const Body2a&, const Body1b&), int );
244     TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::affinity_partitioner&), void );
245     TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, const int&, const Body2a&, const Body1b&), int );
246     TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::static_partitioner&), void );
247     TestFuncDefinitionPresence( parallel_scan, (const tbb::blocked_range2d<int>&, Body3&, const tbb::auto_partitioner&), void );
248     TestFuncDefinitionPresence( parallel_scan, (const tbb::blocked_range<int>&, const int&, const Body3a&, const Body1b&), int );
249     typedef int intarray[10];
250 
251     TestFuncDefinitionPresence( parallel_sort, (int*, int*), void );
252     TestFuncDefinitionPresence( parallel_sort, (intarray&, const Body1bc&), void );
253     TestFuncDefinitionPresence( parallel_pipeline, (size_t, const tbb::filter<void,void>&), void );
254     TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&, tbb::task_group_context&), void );
255     TestFuncDefinitionPresence( parallel_for_each, (const intarray&, const Body1a&, tbb::task_group_context&), void );
256     TestFuncDefinitionPresence( parallel_for, (int, int, const Body1&, const tbb::auto_partitioner&, tbb::task_group_context&), void );
257     TestFuncDefinitionPresence( parallel_for, (int, int, const Body1&, tbb::task_group_context&), void );
258     TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::auto_partitioner&, tbb::task_group_context&), void );
259     TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::task_group_context&), void );
260     TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::simple_partitioner&, tbb::task_group_context&), void );
261     TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::task_group_context&), void );
262     TestTypeDefinitionPresence( proportional_split );
263 
264     TestTypeDefinitionPresence( task_arena );
265     TestFuncDefinitionPresence( this_task_arena::current_thread_index, (), int );
266     TestFuncDefinitionPresence( this_task_arena::max_concurrency, (), int );
267     TestFuncDefinitionPresence( info::numa_nodes, (), std::vector<tbb::numa_node_id> );
268     TestFuncDefinitionPresence( info::default_concurrency, (tbb::numa_node_id), int );
269     TestTypeDefinitionPresence( task_scheduler_observer );
270     TestTypeDefinitionPresence( tbb_allocator<int> );
271     TestTypeDefinitionPresence( tick_count );
272     TestTypeDefinitionPresence( global_control );
273 
274 #if __TBB_CPF_BUILD
275     TestPreviewNames();
276 #endif
277 #ifdef DO_TEST_DEBUG_MACRO
278 #if TBB_USE_DEBUG
279     CHECK_MESSAGE( isDebugExpected, "Debug mode is observed while release mode is expected." );
280 #else
281     CHECK_MESSAGE( !isDebugExpected, "Release mode is observed while debug mode is expected." );
282 #endif /* TBB_USE_DEBUG */
283 #endif /* DO_TEST_DEBUG_MACRO */
284     TestExceptionClassesExports();
285 }
286 
287 #if __TBB_TEST_SECONDARY
288 /* This mode is used to produce a secondary object file that is linked with
289    the main one in order to detect "multiple definition" linker error.
290 */
291 void Secondary() {
292     DefinitionPresence();
293 }
294 #else
295 //! Test for deifinition presence
296 //! \brief \ref interface
297 TEST_CASE("Test for deifinition presence") {
298     DefinitionPresence();
299 }
300 
301 void Secondary();
302 //! Test for "multiple definition" linker error
303 //! \brief \ref error_guessing
304 TEST_CASE("Test for multiple definition linker error") {
305     Secondary();
306 }
307 #endif
308