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 #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 TestTypeDefinitionPresence( collaborative_once_flag ); 178 TestFuncDefinitionPresence( collaborative_call_once, (tbb::collaborative_once_flag&, const Body&), void ); 179 } 180 #endif 181 182 static void DefinitionPresence() { 183 TestTypeDefinitionPresence( cache_aligned_allocator<int> ); 184 TestTypeDefinitionPresence( tbb_hash_compare<int> ); 185 TestTypeDefinitionPresence2( concurrent_hash_map<int, int> ); 186 TestTypeDefinitionPresence2( concurrent_unordered_map<int, int> ); 187 TestTypeDefinitionPresence2( concurrent_unordered_multimap<int, int> ); 188 TestTypeDefinitionPresence( concurrent_unordered_set<int> ); 189 TestTypeDefinitionPresence( concurrent_unordered_multiset<int> ); 190 TestTypeDefinitionPresence2( concurrent_map<int, int> ); 191 TestTypeDefinitionPresence2( concurrent_multimap<int, int> ); 192 TestTypeDefinitionPresence( concurrent_set<int> ); 193 TestTypeDefinitionPresence( concurrent_multiset<int> ); 194 TestTypeDefinitionPresence( concurrent_bounded_queue<int> ); 195 TestTypeDefinitionPresence( concurrent_queue<int> ); 196 TestTypeDefinitionPresence( concurrent_priority_queue<int> ); 197 TestTypeDefinitionPresence( concurrent_vector<int> ); 198 TestTypeDefinitionPresence( combinable<int> ); 199 TestTypeDefinitionPresence( enumerable_thread_specific<int> ); 200 /* Flow graph names */ 201 TestTypeDefinitionPresence( flow::graph ); 202 TestTypeDefinitionPresence( flow::continue_msg ); 203 TestTypeDefinitionPresence2(flow::tagged_msg<int, int> ); 204 TestFuncDefinitionPresence( flow::make_edge, (tbb::flow::sender<Msg>&, tbb::flow::receiver<Msg>&), void ); 205 TestFuncDefinitionPresence( flow::remove_edge, (tbb::flow::sender<Msg>&, tbb::flow::receiver<Msg>&), void ); 206 typedef std::tuple<int, int> intpair; 207 TestTypeDefinitionPresence( flow::input_node<int> ); 208 TestTypeDefinitionPresence3(flow::function_node<int, int, tbb::flow::rejecting> ); 209 TestTypeDefinitionPresence3(flow::multifunction_node<int, intpair, tbb::flow::queueing> ); 210 TestTypeDefinitionPresence3(flow::async_node<int, int, tbb::flow::queueing_lightweight> ); 211 TestTypeDefinitionPresence2(flow::continue_node<int, tbb::flow::lightweight> ); 212 TestTypeDefinitionPresence2(flow::join_node<intpair, tbb::flow::reserving> ); 213 TestTypeDefinitionPresence2(flow::join_node<intpair, tbb::flow::key_matching<int> > ); 214 TestTypeDefinitionPresence( flow::split_node<intpair> ); 215 TestTypeDefinitionPresence( flow::overwrite_node<int> ); 216 TestTypeDefinitionPresence( flow::write_once_node<int> ); 217 TestTypeDefinitionPresence( flow::broadcast_node<int> ); 218 TestTypeDefinitionPresence( flow::buffer_node<int> ); 219 TestTypeDefinitionPresence( flow::queue_node<int> ); 220 TestTypeDefinitionPresence( flow::sequencer_node<int> ); 221 TestTypeDefinitionPresence( flow::priority_queue_node<int> ); 222 TestTypeDefinitionPresence( flow::limiter_node<int> ); 223 TestTypeDefinitionPresence2(flow::indexer_node<int, int> ); 224 TestTypeDefinitionPresence2(flow::composite_node<std::tuple<int>, std::tuple<int> > ); 225 /* Mutex names */ 226 TestTypeDefinitionPresence( null_mutex ); 227 TestTypeDefinitionPresence( null_rw_mutex ); 228 TestTypeDefinitionPresence( queuing_mutex ); 229 TestTypeDefinitionPresence( queuing_rw_mutex ); 230 TestTypeDefinitionPresence( spin_mutex ); 231 TestTypeDefinitionPresence( spin_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 TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&, const Body&), void ); 241 TestFuncDefinitionPresence( parallel_for_each, (int*, int*, const Body1&), void ); 242 TestFuncDefinitionPresence( parallel_for, (int, int, int, const Body1&), void ); 243 TestFuncDefinitionPresence( parallel_for, (const tbb::blocked_range<int>&, const Body2&, const tbb::simple_partitioner&), void ); 244 TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, const int&, const Body2a&, const Body1b&), int ); 245 TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::affinity_partitioner&), void ); 246 TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, const int&, const Body2a&, const Body1b&), int ); 247 TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::static_partitioner&), void ); 248 TestFuncDefinitionPresence( parallel_scan, (const tbb::blocked_range2d<int>&, Body3&, const tbb::auto_partitioner&), void ); 249 TestFuncDefinitionPresence( parallel_scan, (const tbb::blocked_range<int>&, const int&, const Body3a&, const Body1b&), int ); 250 typedef int intarray[10]; 251 252 TestFuncDefinitionPresence( parallel_sort, (int*, int*), void ); 253 TestFuncDefinitionPresence( parallel_sort, (intarray&, const Body1bc&), void ); 254 TestFuncDefinitionPresence( parallel_pipeline, (size_t, const tbb::filter<void,void>&), void ); 255 TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&, tbb::task_group_context&), void ); 256 TestFuncDefinitionPresence( parallel_for_each, (const intarray&, const Body1a&, tbb::task_group_context&), void ); 257 TestFuncDefinitionPresence( parallel_for, (int, int, const Body1&, const tbb::auto_partitioner&, tbb::task_group_context&), void ); 258 TestFuncDefinitionPresence( parallel_for, (int, int, const Body1&, tbb::task_group_context&), void ); 259 TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::auto_partitioner&, tbb::task_group_context&), void ); 260 TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::task_group_context&), void ); 261 TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::simple_partitioner&, tbb::task_group_context&), void ); 262 TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::task_group_context&), void ); 263 TestTypeDefinitionPresence( proportional_split ); 264 265 TestTypeDefinitionPresence( task_arena ); 266 TestFuncDefinitionPresence( this_task_arena::current_thread_index, (), int ); 267 TestFuncDefinitionPresence( this_task_arena::max_concurrency, (), int ); 268 TestFuncDefinitionPresence( info::numa_nodes, (), std::vector<tbb::numa_node_id> ); 269 TestFuncDefinitionPresence( info::default_concurrency, (tbb::numa_node_id), int ); 270 TestTypeDefinitionPresence( task_scheduler_observer ); 271 TestTypeDefinitionPresence( tbb_allocator<int> ); 272 TestTypeDefinitionPresence( tick_count ); 273 TestTypeDefinitionPresence( global_control ); 274 275 #if __TBB_CPF_BUILD 276 TestPreviewNames(); 277 #endif 278 #ifdef DO_TEST_DEBUG_MACRO 279 #if TBB_USE_DEBUG 280 CHECK_MESSAGE( isDebugExpected, "Debug mode is observed while release mode is expected." ); 281 #else 282 CHECK_MESSAGE( !isDebugExpected, "Release mode is observed while debug mode is expected." ); 283 #endif /* TBB_USE_DEBUG */ 284 #endif /* DO_TEST_DEBUG_MACRO */ 285 TestExceptionClassesExports(); 286 } 287 288 #if __TBB_TEST_SECONDARY 289 /* This mode is used to produce a secondary object file that is linked with 290 the main one in order to detect "multiple definition" linker error. 291 */ 292 void Secondary() { 293 DefinitionPresence(); 294 } 295 #else 296 //! Test for deifinition presence 297 //! \brief \ref interface 298 TEST_CASE("Test for deifinition presence") { 299 DefinitionPresence(); 300 } 301 302 void Secondary(); 303 //! Test for "multiple definition" linker error 304 //! \brief \ref error_guessing 305 TEST_CASE("Test for multiple definition linker error") { 306 Secondary(); 307 } 308 #endif 309