2 Copyright (c) 2005-2019 Intel Corporation
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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "tbb/tbb_config.h"
18 #include "tbb/global_control.h"
23 #include "itt_notify.h"
28 //------------------------------------------------------------------------
29 // Begin shared data layout.
30 // The following global data items are mostly read-only after initialization.
31 //------------------------------------------------------------------------
33 //! Padding in order to prevent false sharing.
34 static const char _pad[NFS_MaxLineSize - sizeof(int)] = {};
36 //------------------------------------------------------------------------
38 basic_tls<uintptr_t> governor::theTLS;
39 unsigned governor::DefaultNumberOfThreads;
40 size_t governor::DefaultPageSize;
41 rml::tbb_factory governor::theRMLServerFactory;
42 bool governor::UsePrivateRML;
43 bool governor::is_speculation_enabled;
44 bool governor::is_rethrow_broken;
46 //------------------------------------------------------------------------
48 market* market::theMarket;
49 market::global_market_mutex_type market::theMarketMutex;
51 //------------------------------------------------------------------------
52 // One time initialization data
54 //! Counter of references to global shared resources such as TLS.
55 atomic<int> __TBB_InitOnce::count;
57 __TBB_atomic_flag __TBB_InitOnce::InitializationLock;
59 //! Flag that is set to true after one-time initializations are done.
60 bool __TBB_InitOnce::InitializationDone;
63 static bool ITT_Present;
64 static atomic<bool> ITT_InitializationDone;
67 #if !(_WIN32||_WIN64) || __TBB_SOURCE_DIRECTLY_INCLUDED
68 static __TBB_InitOnce __TBB_InitOnceHiddenInstance;
71 //------------------------------------------------------------------------
72 // generic_scheduler data
74 //! Pointer to the scheduler factory function
75 generic_scheduler* (*AllocateSchedulerPtr)( market&, bool );
77 #if __TBB_OLD_PRIMES_RNG
78 //! Table of primes used by fast random-number generator (FastRandom).
79 /** Also serves to keep anything else from being placed in the same
80 cache line as the global data items preceding it. */
81 static const unsigned Primes[] = {
82 0x9e3779b1, 0xffe6cc59, 0x2109f6dd, 0x43977ab5,
83 0xba5703f5, 0xb495a877, 0xe1626741, 0x79695e6b,
84 0xbc98c09f, 0xd5bee2b3, 0x287488f9, 0x3af18231,
85 0x9677cd4d, 0xbe3a6929, 0xadc6a877, 0xdcf0674b,
86 0xbe4d6fe9, 0x5f15e201, 0x99afc3fd, 0xf3f16801,
87 0xe222cfff, 0x24ba5fdb, 0x0620452d, 0x79f149e3,
88 0xc8b93f49, 0x972702cd, 0xb07dd827, 0x6c97d5ed,
89 0x085a3d61, 0x46eb5ea7, 0x3d9910ed, 0x2e687b5b,
90 0x29609227, 0x6eb081f1, 0x0954c4e1, 0x9d114db9,
91 0x542acfa9, 0xb3e6bd7b, 0x0742d917, 0xe9f3ffa7,
92 0x54581edb, 0xf2480f45, 0x0bb9288f, 0xef1affc7,
93 0x85fa0ca7, 0x3ccc14db, 0xe6baf34b, 0x343377f7,
94 0x5ca19031, 0xe6d9293b, 0xf0a9f391, 0x5d2e980b,
95 0xfc411073, 0xc3749363, 0xb892d829, 0x3549366b,
96 0x629750ad, 0xb98294e5, 0x892d9483, 0xc235baf3,
97 0x3d2402a3, 0x6bdef3c9, 0xbec333cd, 0x40c9520f
100 //------------------------------------------------------------------------
101 // End of shared data layout
102 //------------------------------------------------------------------------
104 //------------------------------------------------------------------------
105 // Shared data accessors
106 //------------------------------------------------------------------------
108 unsigned GetPrime ( unsigned seed ) {
109 return Primes[seed%(sizeof(Primes)/sizeof(Primes[0]))];
111 #endif //__TBB_OLD_PRIMES_RNG
113 //------------------------------------------------------------------------
115 //------------------------------------------------------------------------
117 void __TBB_InitOnce::add_ref() {
119 governor::acquire_resources();
122 void __TBB_InitOnce::remove_ref() {
124 __TBB_ASSERT(k>=0,"removed __TBB_InitOnce ref that was not added?");
126 governor::release_resources();
131 //------------------------------------------------------------------------
132 // One-time Initializations
133 //------------------------------------------------------------------------
135 //! Defined in cache_aligned_allocator.cpp
136 void initialize_cache_aligned_allocator();
138 //! Defined in scheduler.cpp
139 void Scheduler_OneTimeInitialization ( bool itt_present );
143 static __itt_domain *tbb_domains[ITT_NUM_DOMAINS] = {};
145 struct resource_string {
147 __itt_string_handle *itt_str_handle;
151 // populate resource strings
153 #define TBB_STRING_RESOURCE( index_name, str ) { str, NULL },
154 static resource_string strings_for_itt[] = {
155 #include "tbb/internal/_tbb_strings.h"
156 { "num_resource_strings", NULL }
158 #undef TBB_STRING_RESOURCE
160 static __itt_string_handle *ITT_get_string_handle(int idx) {
161 __TBB_ASSERT( idx >= 0 && idx < NUM_STRINGS, "string handle out of valid range");
162 return (idx >= 0 && idx < NUM_STRINGS) ? strings_for_itt[idx].itt_str_handle : NULL;
165 static void ITT_init_domains() {
166 tbb_domains[ITT_DOMAIN_MAIN] = __itt_domain_create( _T("tbb") );
167 tbb_domains[ITT_DOMAIN_MAIN]->flags = 1;
168 tbb_domains[ITT_DOMAIN_FLOW] = __itt_domain_create( _T("tbb.flow") );
169 tbb_domains[ITT_DOMAIN_FLOW]->flags = 1;
170 tbb_domains[ITT_DOMAIN_ALGO] = __itt_domain_create( _T("tbb.algorithm") );
171 tbb_domains[ITT_DOMAIN_ALGO]->flags = 1;
174 static void ITT_init_strings() {
175 for ( int i = 0; i < NUM_STRINGS; ++i ) {
177 strings_for_itt[i].itt_str_handle = __itt_string_handle_createA( strings_for_itt[i].str );
179 strings_for_itt[i].itt_str_handle = __itt_string_handle_create( strings_for_itt[i].str );
184 static void ITT_init() {
189 /** Thread-unsafe lazy one-time initialization of tools interop.
190 Used by both dummy handlers and general TBB one-time initialization routine. **/
191 void ITT_DoUnsafeOneTimeInitialization () {
192 // Double check ITT_InitializationDone is necessary because the first check
193 // in ITT_DoOneTimeInitialization is not guarded with the __TBB_InitOnce lock.
194 if ( !ITT_InitializationDone ) {
195 ITT_Present = (__TBB_load_ittnotify()!=0);
196 if (ITT_Present) ITT_init();
197 ITT_InitializationDone = true;
198 ITT_SYNC_CREATE(&market::theMarketMutex, SyncType_GlobalLock, SyncObj_SchedulerInitialization);
202 /** Thread-safe lazy one-time initialization of tools interop.
203 Used by dummy handlers only. **/
205 void ITT_DoOneTimeInitialization() {
206 if ( !ITT_InitializationDone ) {
207 __TBB_InitOnce::lock();
208 ITT_DoUnsafeOneTimeInitialization();
209 __TBB_InitOnce::unlock();
212 #endif /* DO_ITT_NOTIFY */
214 //! Performs thread-safe lazy one-time general TBB initialization.
215 void DoOneTimeInitializations() {
216 suppress_unused_warning(_pad);
217 __TBB_InitOnce::lock();
218 // No fence required for load of InitializationDone, because we are inside a critical section.
219 if( !__TBB_InitOnce::InitializationDone ) {
220 __TBB_InitOnce::add_ref();
221 if( GetBoolEnvironmentVariable("TBB_VERSION") )
223 bool itt_present = false;
225 ITT_DoUnsafeOneTimeInitialization();
226 itt_present = ITT_Present;
227 #endif /* DO_ITT_NOTIFY */
228 initialize_cache_aligned_allocator();
229 governor::initialize_rml_factory();
230 Scheduler_OneTimeInitialization( itt_present );
231 // Force processor groups support detection
232 governor::default_num_threads();
233 // Force OS regular page size detection
234 governor::default_page_size();
236 governor::print_version_info();
237 PrintExtraVersionInfo( "Tools support", itt_present ? "enabled" : "disabled" );
238 __TBB_InitOnce::InitializationDone = true;
240 __TBB_InitOnce::unlock();
243 #if (_WIN32||_WIN64) && !__TBB_SOURCE_DIRECTLY_INCLUDED
244 //! Windows "DllMain" that handles startup and shutdown of dynamic library.
245 extern "C" bool WINAPI DllMain( HANDLE /*hinstDLL*/, DWORD reason, LPVOID lpvReserved ) {
247 case DLL_PROCESS_ATTACH:
248 __TBB_InitOnce::add_ref();
250 case DLL_PROCESS_DETACH:
251 // Since THREAD_DETACH is not called for the main thread, call auto-termination
252 // here as well - but not during process shutdown (due to risk of a deadlock).
253 if( lpvReserved==NULL ) // library unload
254 governor::terminate_auto_initialized_scheduler();
255 __TBB_InitOnce::remove_ref();
256 // It is assumed that InitializationDone is not set after DLL_PROCESS_DETACH,
257 // and thus no race on InitializationDone is possible.
258 if( __TBB_InitOnce::initialization_done() ) {
259 // Remove reference that we added in DoOneTimeInitializations.
260 __TBB_InitOnce::remove_ref();
263 case DLL_THREAD_DETACH:
264 governor::terminate_auto_initialized_scheduler();
269 #endif /* (_WIN32||_WIN64) && !__TBB_SOURCE_DIRECTLY_INCLUDED */
271 void itt_store_pointer_with_release_v3( void* dst, void* src ) {
272 ITT_NOTIFY(sync_releasing, dst);
273 __TBB_store_with_release(*static_cast<void**>(dst),src);
276 void* itt_load_pointer_with_acquire_v3( const void* src ) {
277 void* result = __TBB_load_with_acquire(*static_cast<void*const*>(src));
278 ITT_NOTIFY(sync_acquired, const_cast<void*>(src));
283 void call_itt_notify_v5(int t, void *ptr) {
285 case 0: ITT_NOTIFY(sync_prepare, ptr); break;
286 case 1: ITT_NOTIFY(sync_cancel, ptr); break;
287 case 2: ITT_NOTIFY(sync_acquired, ptr); break;
288 case 3: ITT_NOTIFY(sync_releasing, ptr); break;
292 void call_itt_notify_v5(int /*t*/, void* /*ptr*/) {}
296 const __itt_id itt_null_id = {0, 0, 0};
298 static inline __itt_domain* get_itt_domain( itt_domain_enum idx ) {
299 if (tbb_domains[idx] == NULL) {
300 ITT_DoOneTimeInitialization();
302 return tbb_domains[idx];
305 static inline void itt_id_make(__itt_id *id, void* addr, unsigned long long extra) {
306 *id = __itt_id_make(addr, extra);
309 static inline void itt_id_create(const __itt_domain *domain, __itt_id id) {
310 ITTNOTIFY_VOID_D1(id_create, domain, id);
313 void itt_make_task_group_v7( itt_domain_enum domain, void *group, unsigned long long group_extra,
314 void *parent, unsigned long long parent_extra, string_index name_index ) {
315 if ( __itt_domain *d = get_itt_domain( domain ) ) {
316 __itt_id group_id = itt_null_id;
317 __itt_id parent_id = itt_null_id;
318 itt_id_make( &group_id, group, group_extra );
319 itt_id_create( d, group_id );
321 itt_id_make( &parent_id, parent, parent_extra );
323 __itt_string_handle *n = ITT_get_string_handle(name_index);
324 ITTNOTIFY_VOID_D3(task_group, d, group_id, parent_id, n);
328 void itt_metadata_str_add_v7( itt_domain_enum domain, void *addr, unsigned long long addr_extra,
329 string_index key, const char *value ) {
330 if ( __itt_domain *d = get_itt_domain( domain ) ) {
331 __itt_id id = itt_null_id;
332 itt_id_make( &id, addr, addr_extra );
333 __itt_string_handle *k = ITT_get_string_handle(key);
334 size_t value_length = strlen( value );
336 ITTNOTIFY_VOID_D4(metadata_str_addA, d, id, k, value, value_length);
338 ITTNOTIFY_VOID_D4(metadata_str_add, d, id, k, value, value_length);
343 void itt_metadata_ptr_add_v11( itt_domain_enum domain, void *addr, unsigned long long addr_extra,
344 string_index key, void *value ) {
345 if ( __itt_domain *d = get_itt_domain( domain ) ) {
346 __itt_id id = itt_null_id;
347 itt_id_make( &id, addr, addr_extra );
348 __itt_string_handle *k = ITT_get_string_handle(key);
350 ITTNOTIFY_VOID_D5(metadata_add, d, id, k, __itt_metadata_u32, 1, value);
352 ITTNOTIFY_VOID_D5(metadata_add, d, id, k, __itt_metadata_u64, 1, value);
358 void itt_relation_add_v7( itt_domain_enum domain, void *addr0, unsigned long long addr0_extra,
359 itt_relation relation, void *addr1, unsigned long long addr1_extra ) {
360 if ( __itt_domain *d = get_itt_domain( domain ) ) {
361 __itt_id id0 = itt_null_id;
362 __itt_id id1 = itt_null_id;
363 itt_id_make( &id0, addr0, addr0_extra );
364 itt_id_make( &id1, addr1, addr1_extra );
365 ITTNOTIFY_VOID_D3(relation_add, d, id0, (__itt_relation)relation, id1);
369 void itt_task_begin_v7( itt_domain_enum domain, void *task, unsigned long long task_extra,
370 void *parent, unsigned long long parent_extra, string_index name_index ) {
371 if ( __itt_domain *d = get_itt_domain( domain ) ) {
372 __itt_id task_id = itt_null_id;
373 __itt_id parent_id = itt_null_id;
375 itt_id_make( &task_id, task, task_extra );
378 itt_id_make( &parent_id, parent, parent_extra );
380 __itt_string_handle *n = ITT_get_string_handle(name_index);
381 ITTNOTIFY_VOID_D3(task_begin, d, task_id, parent_id, n );
385 void itt_task_end_v7( itt_domain_enum domain ) {
386 if ( __itt_domain *d = get_itt_domain( domain ) ) {
387 ITTNOTIFY_VOID_D0(task_end, d);
391 void itt_region_begin_v9( itt_domain_enum domain, void *region, unsigned long long region_extra,
392 void *parent, unsigned long long parent_extra, string_index /* name_index */ ) {
393 if ( __itt_domain *d = get_itt_domain( domain ) ) {
394 __itt_id region_id = itt_null_id;
395 __itt_id parent_id = itt_null_id;
396 itt_id_make( ®ion_id, region, region_extra );
398 itt_id_make( &parent_id, parent, parent_extra );
400 ITTNOTIFY_VOID_D3(region_begin, d, region_id, parent_id, NULL );
404 void itt_region_end_v9( itt_domain_enum domain, void *region, unsigned long long region_extra ) {
405 if ( __itt_domain *d = get_itt_domain( domain ) ) {
406 __itt_id region_id = itt_null_id;
407 itt_id_make( ®ion_id, region, region_extra );
408 ITTNOTIFY_VOID_D1( region_end, d, region_id );
412 #else // DO_ITT_NOTIFY
414 void itt_make_task_group_v7( itt_domain_enum /*domain*/, void* /*group*/, unsigned long long /*group_extra*/,
415 void* /*parent*/, unsigned long long /*parent_extra*/, string_index /*name_index*/ ) { }
417 void itt_metadata_str_add_v7( itt_domain_enum /*domain*/, void* /*addr*/, unsigned long long /*addr_extra*/,
418 string_index /*key*/, const char* /*value*/ ) { }
420 void itt_relation_add_v7( itt_domain_enum /*domain*/, void* /*addr0*/, unsigned long long /*addr0_extra*/,
421 itt_relation /*relation*/, void* /*addr1*/, unsigned long long /*addr1_extra*/ ) { }
423 void itt_metadata_ptr_add_v11( itt_domain_enum /*domain*/, void * /*addr*/, unsigned long long /*addr_extra*/,
424 string_index /*key*/, void * /*value*/ ) {}
426 void itt_task_begin_v7( itt_domain_enum /*domain*/, void* /*task*/, unsigned long long /*task_extra*/,
427 void* /*parent*/, unsigned long long /*parent_extra*/, string_index /*name_index*/ ) { }
429 void itt_task_end_v7( itt_domain_enum /*domain*/ ) { }
431 void itt_region_begin_v9( itt_domain_enum /*domain*/, void* /*region*/, unsigned long long /*region_extra*/,
432 void* /*parent*/, unsigned long long /*parent_extra*/, string_index /*name_index*/ ) { }
434 void itt_region_end_v9( itt_domain_enum /*domain*/, void* /*region*/, unsigned long long /*region_extra*/ ) { }
436 #endif // DO_ITT_NOTIFY
438 void* itt_load_pointer_v3( const void* src ) {
439 //TODO: replace this with __TBB_load_relaxed
440 void* result = *static_cast<void*const*>(src);
444 void itt_set_sync_name_v3( void* obj, const tchar* name) {
445 ITT_SYNC_RENAME(obj, name);
446 suppress_unused_warning(obj, name);
450 class control_storage {
451 friend class tbb::interface9::global_control;
453 size_t my_active_value;
454 atomic<global_control*> my_head;
455 spin_mutex my_list_mutex;
457 virtual size_t default_value() const = 0;
458 virtual void apply_active() const {}
459 virtual bool is_first_arg_preferred(size_t a, size_t b) const {
460 return a>b; // prefer max by default
462 virtual size_t active_value() const {
463 return my_head? my_active_value : default_value();
467 class allowed_parallelism_control : public padded<control_storage> {
468 virtual size_t default_value() const __TBB_override {
469 return max(1U, governor::default_num_threads());
471 virtual bool is_first_arg_preferred(size_t a, size_t b) const __TBB_override {
472 return a<b; // prefer min allowed parallelism
474 virtual void apply_active() const __TBB_override {
475 __TBB_ASSERT( my_active_value>=1, NULL );
476 // -1 to take master into account
477 market::set_active_num_workers( my_active_value-1 );
479 virtual size_t active_value() const __TBB_override {
480 /* Reading of my_active_value is not synchronized with possible updating
481 of my_head by other thread. It's ok, as value of my_active_value became
482 not invalid, just obsolete. */
484 return default_value();
485 // non-zero, if market is active
486 const size_t workers = market::max_num_workers();
487 // We can't exceed market's maximal number of workers.
488 // +1 to take master into account
489 return workers? min(workers+1, my_active_value): my_active_value;
492 size_t active_value_if_present() const {
493 return my_head? my_active_value : 0;
497 class stack_size_control : public padded<control_storage> {
498 virtual size_t default_value() const __TBB_override {
499 return tbb::internal::ThreadStackSize;
501 virtual void apply_active() const __TBB_override {
502 #if __TBB_WIN8UI_SUPPORT && (_WIN32_WINNT < 0x0A00)
503 __TBB_ASSERT( false, "For Windows 8 Store* apps we must not set stack size" );
508 static allowed_parallelism_control allowed_parallelism_ctl;
509 static stack_size_control stack_size_ctl;
511 static control_storage *controls[] = {&allowed_parallelism_ctl, &stack_size_ctl};
513 unsigned market::app_parallelism_limit() {
514 return allowed_parallelism_ctl.active_value_if_present();
517 } // namespace internal
519 namespace interface9 {
521 using namespace internal;
522 using namespace tbb::internal;
524 void global_control::internal_create() {
525 __TBB_ASSERT_RELEASE( my_param < global_control::parameter_max, NULL );
526 control_storage *const c = controls[my_param];
528 spin_mutex::scoped_lock lock(c->my_list_mutex);
529 if (!c->my_head || c->is_first_arg_preferred(my_value, c->my_active_value)) {
530 c->my_active_value = my_value;
531 // to guarantee that apply_active() is called with current active value,
532 // calls it here and in internal_destroy() under my_list_mutex
535 my_next = c->my_head;
536 // publish my_head, at this point my_active_value must be valid
540 void global_control::internal_destroy() {
541 global_control *prev = 0;
543 __TBB_ASSERT_RELEASE( my_param < global_control::parameter_max, NULL );
544 control_storage *const c = controls[my_param];
545 __TBB_ASSERT( c->my_head, NULL );
547 // Concurrent reading and changing global parameter is possible.
548 // In this case, my_active_value may not match current state of parameters.
549 // This is OK because:
550 // 1) my_active_value is either current or previous
551 // 2) my_active_value is current on internal_destroy leave
552 spin_mutex::scoped_lock lock(c->my_list_mutex);
553 size_t new_active = (size_t)-1, old_active = c->my_active_value;
555 if ( c->my_head != this )
556 new_active = c->my_head->my_value;
557 else if ( c->my_head->my_next )
558 new_active = c->my_head->my_next->my_value;
559 // if there is only one element, new_active will be set later
560 for ( global_control *curr = c->my_head; curr; prev = curr, curr = curr->my_next )
561 if ( curr == this ) {
563 prev->my_next = my_next;
565 c->my_head = my_next;
567 if (c->is_first_arg_preferred(curr->my_value, new_active))
568 new_active = curr->my_value;
571 __TBB_ASSERT( new_active==(size_t)-1, NULL );
572 new_active = c->default_value();
574 if ( new_active != old_active ) {
575 c->my_active_value = new_active;
580 size_t global_control::active_value( int param ) {
581 __TBB_ASSERT_RELEASE( param < global_control::parameter_max, NULL );
582 return controls[param]->active_value();