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