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