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 34 #if __TBB_TEST_SECONDARY 35 // Test _DEBUG macro custom definitions. 36 #if TBB_USE_DEBUG 37 #ifdef _DEBUG 38 #undef _DEBUG 39 #endif /* _DEBUG */ 40 // Check that empty value successfully enables the debug mode. 41 #define _DEBUG 42 static bool isDebugExpected = true; 43 #else 44 // Check that zero value does not enable the debug mode. 45 #define _DEBUG 0x0 46 static bool isDebugExpected = false; 47 #endif /* TBB_USE_DEBUG */ 48 #define DO_TEST_DEBUG_MACRO 1 49 #else 50 // Test default definitions of _DEBUG. 51 #if _DEBUG 52 static bool isDebugExpected = true; 53 #define DO_TEST_DEBUG_MACRO 1 54 #elif _MSC_VER 55 // for MSVC, _DEBUG not defined indicates a release mode. 56 static bool isDebugExpected = false; 57 #define DO_TEST_DEBUG_MACRO 1 58 #endif /* _DEBUG */ 59 #endif /* __TBB_TEST_SECONDARY */ 60 61 #if DO_TEST_DEBUG_MACRO 62 // Reset TBB_USE_DEBUG defined in makefiles. 63 #undef TBB_USE_DEBUG 64 #endif /* DO_TEST_DEBUG_MACRO */ 65 #define __TBB_CONFIG_PREPROC_ONLY _MSC_VER // For MSVC, prevent including standard headers in tbb_config.h 66 #include "common/config.h" 67 68 #include "oneapi/tbb/detail/_config.h" 69 70 #if !TBB_USE_DEBUG && defined(_DEBUG) 71 // TBB_USE_DEBUG is 0 but _DEBUG is defined, it means that _DEBUG is 0 72 // MSVC C++ headers consider any definition of _DEBUG, including 0, as debug mode 73 #undef _DEBUG 74 #endif /* !TBB_USE_DEBUG && defined(_DEBUG) */ 75 76 #include "tbb/tbb.h" 77 78 #if !__TBB_TEST_SECONDARY 79 #include "common/test.h" 80 #endif 81 82 static volatile size_t g_sink; 83 84 #define TestTypeDefinitionPresence( Type ) g_sink = sizeof(tbb::Type); 85 #define TestTypeDefinitionPresence2(TypeStart, TypeEnd) g_sink = sizeof(tbb::TypeStart,TypeEnd); 86 #define TestTypeDefinitionPresence3(TypeStart, TypeMid, TypeEnd) g_sink = sizeof(tbb::TypeStart,TypeMid,TypeEnd); 87 #define TestFuncDefinitionPresence(Fn, Args, ReturnType) { ReturnType (*pfn)Args = &tbb::Fn; (void)pfn; } 88 89 struct Body { 90 void operator() () const {} 91 }; 92 struct Body1 { 93 void operator() ( int ) const {} 94 }; 95 struct Body1a { // feeder body for parallel_do 96 void operator() ( int, tbb::feeder<int>& ) const {} 97 }; 98 struct Body1b { // binary operator for reduction 99 int operator() ( const int, const int ) const { return 0; } 100 }; 101 struct Body1bc { // binary operator for comparison 102 bool operator() (const int, const int) const { return false; } 103 }; 104 struct Body2 { 105 Body2 () {} 106 Body2 ( const Body2&, tbb::split ) {} 107 void operator() ( const tbb::blocked_range<int>& ) const {} 108 void join( const Body2& ) {} 109 }; 110 struct Body2a { // for lambda-friendly parallel_reduce 111 int operator() ( const tbb::blocked_range<int>&, const int ) const { return 0; } 112 }; 113 struct Body3 { // for parallel_scan 114 Body3 () {} 115 Body3 ( const Body3&, tbb::split ) {} 116 void operator() ( const tbb::blocked_range2d<int>&, tbb::pre_scan_tag ) const {} 117 void operator() ( const tbb::blocked_range2d<int>&, tbb::final_scan_tag ) const {} 118 void reverse_join( Body3& ) {} 119 void assign( const Body3& ) {} 120 }; 121 struct Body3a { // for lambda-friednly parallel_scan 122 int operator() ( const tbb::blocked_range<int>&, const int, bool ) const { return 0; } 123 }; 124 struct Msg {}; 125 126 // Test if all the necessary symbols are exported for the exceptions thrown by TBB. 127 // Missing exports result either in link error or in runtime assertion failure. 128 #include <stdexcept> 129 130 template <typename E> 131 void TestExceptionClassExports ( const E& exc, tbb::detail::exception_id eid ) { 132 CHECK( eid < tbb::detail::exception_id::last_entry ); 133 #if TBB_USE_EXCEPTIONS 134 for ( int i = 0; i < 2; ++i ) { 135 try { 136 if ( i == 0 ) 137 throw exc; 138 else 139 tbb::detail::throw_exception( eid ); 140 } 141 catch ( E& e ) { 142 CHECK_MESSAGE( e.what(), "Missing what() string" ); 143 } 144 catch ( ... ) { 145 CHECK_MESSAGE( false, "Unrecognized exception. Likely RTTI related exports are missing" ); 146 } 147 } 148 #else /* TBB_USE_EXCEPTIONS */ 149 (void)exc; 150 #endif /* TBB_USE_EXCEPTIONS */ 151 } 152 153 static void TestExceptionClassesExports () { 154 TestExceptionClassExports( std::bad_alloc(), tbb::detail::exception_id::bad_alloc ); 155 TestExceptionClassExports( tbb::bad_last_alloc(), tbb::detail::exception_id::bad_last_alloc ); 156 TestExceptionClassExports( std::invalid_argument("test"), tbb::detail::exception_id::nonpositive_step ); 157 TestExceptionClassExports( std::out_of_range("test"), tbb::detail::exception_id::out_of_range ); 158 TestExceptionClassExports( tbb::missing_wait(), tbb::detail::exception_id::missing_wait ); 159 TestExceptionClassExports( std::out_of_range("test"), tbb::detail::exception_id::invalid_load_factor ); 160 TestExceptionClassExports( std::length_error("test"), tbb::detail::exception_id::reservation_length_error ); 161 TestExceptionClassExports( std::out_of_range("test"), tbb::detail::exception_id::invalid_key ); 162 TestExceptionClassExports( tbb::user_abort(), tbb::detail::exception_id::user_abort ); 163 TestExceptionClassExports( std::runtime_error("test"), tbb::detail::exception_id::bad_tagged_msg_cast ); 164 } 165 166 #if __TBB_CPF_BUILD 167 // These names are only tested in "preview" configuration 168 // When a feature becomes fully supported, its names should be moved to the main test 169 static void TestPreviewNames() { 170 TestTypeDefinitionPresence2( blocked_rangeNd<int,4> ); 171 TestTypeDefinitionPresence2( concurrent_lru_cache<int, int> ); 172 TestTypeDefinitionPresence( isolated_task_group ); 173 TestTypeDefinitionPresence( collaborative_once_flag ); 174 TestFuncDefinitionPresence( collaborative_call_once, (tbb::collaborative_once_flag&, const Body&), void ); 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 248 TestFuncDefinitionPresence( parallel_sort, (int*, int*), void ); 249 TestFuncDefinitionPresence( parallel_sort, (intarray&, const Body1bc&), void ); 250 TestFuncDefinitionPresence( parallel_pipeline, (size_t, const tbb::filter<void,void>&), void ); 251 TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&, tbb::task_group_context&), void ); 252 TestFuncDefinitionPresence( parallel_for_each, (const intarray&, const Body1a&, tbb::task_group_context&), void ); 253 TestFuncDefinitionPresence( parallel_for, (int, int, const Body1&, const tbb::auto_partitioner&, tbb::task_group_context&), void ); 254 TestFuncDefinitionPresence( parallel_for, (int, int, const Body1&, tbb::task_group_context&), void ); 255 TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::auto_partitioner&, tbb::task_group_context&), void ); 256 TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::task_group_context&), void ); 257 TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::simple_partitioner&, tbb::task_group_context&), void ); 258 TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::task_group_context&), void ); 259 TestTypeDefinitionPresence( proportional_split ); 260 261 TestTypeDefinitionPresence( task_arena ); 262 TestFuncDefinitionPresence( this_task_arena::current_thread_index, (), int ); 263 TestFuncDefinitionPresence( this_task_arena::max_concurrency, (), int ); 264 TestFuncDefinitionPresence( info::numa_nodes, (), std::vector<tbb::numa_node_id> ); 265 TestFuncDefinitionPresence( info::default_concurrency, (tbb::numa_node_id), int ); 266 TestTypeDefinitionPresence( task_scheduler_observer ); 267 TestTypeDefinitionPresence( tbb_allocator<int> ); 268 TestTypeDefinitionPresence( tick_count ); 269 TestTypeDefinitionPresence( global_control ); 270 271 #if __TBB_CPF_BUILD 272 TestPreviewNames(); 273 #endif 274 #ifdef DO_TEST_DEBUG_MACRO 275 #if TBB_USE_DEBUG 276 CHECK_MESSAGE( isDebugExpected, "Debug mode is observed while release mode is expected." ); 277 #else 278 CHECK_MESSAGE( !isDebugExpected, "Release mode is observed while debug mode is expected." ); 279 #endif /* TBB_USE_DEBUG */ 280 #endif /* DO_TEST_DEBUG_MACRO */ 281 TestExceptionClassesExports(); 282 } 283 284 #if __TBB_TEST_SECONDARY 285 /* This mode is used to produce a secondary object file that is linked with 286 the main one in order to detect "multiple definition" linker error. 287 */ 288 void Secondary() { 289 DefinitionPresence(); 290 } 291 #else 292 //! Test for deifinition presence 293 //! \brief \ref interface 294 TEST_CASE("Test for deifinition presence") { 295 DefinitionPresence(); 296 } 297 298 void Secondary(); 299 //! Test for "multiple definition" linker error 300 //! \brief \ref error_guessing 301 TEST_CASE("Test for multiple definition linker error") { 302 Secondary(); 303 } 304 #endif 305