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.
20 #include "tbb/tbb_stddef.h"
22 #include "scheduler_common.h"
23 #include "tbb/atomic.h"
24 #include "tbb/spin_rw_mutex.h"
25 #include "../rml/include/rml_tbb.h"
27 #include "intrusive_list.h"
29 #if defined(_MSC_VER) && defined(_Wp64)
30 // Workaround for overzealous compiler warnings in /Wp64 mode
31 #pragma warning (push)
32 #pragma warning (disable: 4244)
37 class task_group_context;
41 //------------------------------------------------------------------------
43 //------------------------------------------------------------------------
45 class market : no_copy, rml::tbb_client {
46 friend class generic_scheduler;
48 friend class tbb::interface7::internal::task_arena_base;
49 template<typename SchedulerTraits> friend class custom_scheduler;
50 friend class tbb::task_group_context;
52 friend void ITT_DoUnsafeOneTimeInitialization ();
54 typedef intrusive_list<arena> arena_list_type;
55 typedef intrusive_list<generic_scheduler> scheduler_list_type;
57 //! Currently active global market
58 static market* theMarket;
60 typedef scheduler_mutex_type global_market_mutex_type;
62 //! Mutex guarding creation/destruction of theMarket, insertions/deletions in my_arenas, and cancellation propagation
63 static global_market_mutex_type theMarketMutex;
65 //! Lightweight mutex guarding accounting operations with arenas list
66 typedef spin_rw_mutex arenas_list_mutex_type;
67 arenas_list_mutex_type my_arenas_list_mutex;
69 //! Pointer to the RML server object that services this TBB instance.
70 rml::tbb_server* my_server;
72 //! Maximal number of workers allowed for use by the underlying resource manager
73 /** It can't be changed after market creation. **/
74 unsigned my_num_workers_hard_limit;
76 //! Current application-imposed limit on the number of workers (see set_active_num_workers())
77 /** It can't be more than my_num_workers_hard_limit. **/
78 unsigned my_num_workers_soft_limit;
80 //! Number of workers currently requested from RML
81 int my_num_workers_requested;
83 //! First unused index of worker
84 /** Used to assign indices to the new workers coming from RML, and busy part
85 of my_workers array. **/
86 atomic<unsigned> my_first_unused_worker_idx;
88 //! Number of workers that were requested by all arenas
91 #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY
92 //! How many times mandatory concurrency was requested from the market
93 int my_mandatory_num_requested;
96 #if __TBB_TASK_PRIORITY
97 //! Highest priority among active arenas in the market.
98 /** Arena priority level is its tasks highest priority (specified by arena's
99 my_top_priority member).
100 Arena is active when it has outstanding request for workers. Note that
101 inactive arena may have workers lingering there for some time. **/
102 intptr_t my_global_top_priority;
104 //! Lowest priority among active arenas in the market.
105 /** See also my_global_top_priority **/
106 intptr_t my_global_bottom_priority;
108 //! Tracks events that may bring tasks in offload areas to the top priority level.
109 /** Incremented when global top priority is decremented or a task group priority
110 is elevated to the current top level. **/
111 uintptr_t my_global_reload_epoch;
113 //! Information about arenas at a particular priority level
114 struct priority_level_info {
115 //! List of arenas at this priority level
116 arena_list_type arenas;
118 //! The first arena to be checked when idle worker seeks for an arena to enter
119 /** The check happens in round-robin fashion. **/
122 //! Total amount of workers requested by arenas at this priority level.
123 int workers_requested;
125 //! Maximal amount of workers the market can tell off to this priority level.
126 int workers_available;
127 }; // struct priority_level_info
129 //! Information about arenas at different priority levels
130 priority_level_info my_priority_levels[num_priority_levels];
132 #else /* !__TBB_TASK_PRIORITY */
134 //! List of registered arenas
135 arena_list_type my_arenas;
137 //! The first arena to be checked when idle worker seeks for an arena to enter
138 /** The check happens in round-robin fashion. **/
139 arena *my_next_arena;
140 #endif /* !__TBB_TASK_PRIORITY */
142 //! ABA prevention marker to assign to newly created arenas
143 uintptr_t my_arenas_aba_epoch;
145 //! Reference count controlling market object lifetime
146 unsigned my_ref_count;
148 //! Count of master threads attached
149 unsigned my_public_ref_count;
151 //! Stack size of worker threads
152 size_t my_stack_size;
155 bool my_join_workers;
157 //! The value indicating that the soft limit warning is unnecessary
158 static const unsigned skip_soft_limit_warning = ~0U;
160 //! Either workers soft limit to be reported via runtime_warning() or skip_soft_limit_warning
161 unsigned my_workers_soft_limit_to_report;
162 #if __TBB_COUNT_TASK_NODES
163 //! Net number of nodes that have been allocated from heap.
164 /** Updated each time a scheduler or arena is destroyed. */
165 atomic<intptr_t> my_task_node_count;
166 #endif /* __TBB_COUNT_TASK_NODES */
169 market ( unsigned workers_soft_limit, unsigned workers_hard_limit, size_t stack_size );
171 //! Factory method creating new market object
172 static market& global_market ( bool is_public, unsigned max_num_workers = 0, size_t stack_size = 0 );
174 //! Destroys and deallocates market object created by market::create()
177 #if __TBB_TASK_PRIORITY
178 //! Returns next arena that needs more workers, or NULL.
179 arena* arena_in_need ( arena* prev_arena );
181 //! Recalculates the number of workers requested from RML and updates the allotment.
182 int update_workers_request();
184 //! Recalculates the number of workers assigned to each arena at and below the specified priority.
185 /** The actual number of workers servicing a particular arena may temporarily
186 deviate from the calculated value. **/
187 void update_allotment ( intptr_t highest_affected_priority );
189 //! Changes arena's top priority and updates affected priority levels info in the market.
190 void update_arena_top_priority ( arena& a, intptr_t newPriority );
192 //! Changes market's global top priority and related settings.
193 inline void update_global_top_priority ( intptr_t newPriority );
195 //! Resets empty market's global top and bottom priority to the normal level.
196 inline void reset_global_priority ();
198 inline void advance_global_reload_epoch () {
199 __TBB_store_with_release( my_global_reload_epoch, my_global_reload_epoch + 1 );
202 void assert_market_valid () const {
203 __TBB_ASSERT( (my_priority_levels[my_global_top_priority].workers_requested > 0
204 && !my_priority_levels[my_global_top_priority].arenas.empty())
205 || (my_global_top_priority == my_global_bottom_priority &&
206 my_global_top_priority == normalized_normal_priority), NULL );
209 #else /* !__TBB_TASK_PRIORITY */
211 //! Recalculates the number of workers assigned to each arena in the list.
212 /** The actual number of workers servicing a particular arena may temporarily
213 deviate from the calculated value. **/
214 void update_allotment () {
215 if ( my_total_demand )
216 update_allotment( my_arenas, my_total_demand, (int)my_num_workers_soft_limit );
219 // TODO: consider to rewrite the code with is_arena_in_list function
220 //! Returns next arena that needs more workers, or NULL.
221 arena* arena_in_need (arena*) {
222 if(__TBB_load_with_acquire(my_total_demand) <= 0)
224 arenas_list_mutex_type::scoped_lock lock(my_arenas_list_mutex, /*is_writer=*/false);
225 return arena_in_need(my_arenas, my_next_arena);
227 void assert_market_valid () const {}
228 #endif /* !__TBB_TASK_PRIORITY */
230 ////////////////////////////////////////////////////////////////////////////////
231 // Helpers to unify code branches dependent on priority feature presence
233 void insert_arena_into_list ( arena& a );
235 void remove_arena_from_list ( arena& a );
237 arena* arena_in_need ( arena_list_type &arenas, arena *hint );
239 int update_allotment ( arena_list_type& arenas, int total_demand, int max_workers );
241 bool is_arena_in_list( arena_list_type &arenas, arena *a );
244 ////////////////////////////////////////////////////////////////////////////////
245 // Implementation of rml::tbb_client interface methods
247 version_type version () const __TBB_override { return 0; }
249 unsigned max_job_count () const __TBB_override { return my_num_workers_hard_limit; }
251 size_t min_stack_size () const __TBB_override { return worker_stack_size(); }
253 policy_type policy () const __TBB_override { return throughput; }
255 job* create_one_job () __TBB_override;
257 void cleanup( job& j ) __TBB_override;
259 void acknowledge_close_connection () __TBB_override;
261 void process( job& j ) __TBB_override;
264 //! Creates an arena object
265 /** If necessary, also creates global market instance, and boosts its ref count.
266 Each call to create_arena() must be matched by the call to arena::free_arena(). **/
267 static arena* create_arena ( int num_slots, int num_reserved_slots, size_t stack_size );
269 //! Removes the arena from the market's list
270 void try_destroy_arena ( arena*, uintptr_t aba_epoch );
272 //! Removes the arena from the market's list
273 void detach_arena ( arena& );
275 //! Decrements market's refcount and destroys it in the end
276 bool release ( bool is_public, bool blocking_terminate );
278 #if __TBB_ENQUEUE_ENFORCED_CONCURRENCY
279 //! Imlpementation of mandatory concurrency enabling
280 void enable_mandatory_concurrency_impl ( arena *a );
282 //! Inform the master that there is an arena with mandatory concurrency
283 void enable_mandatory_concurrency ( arena *a );
285 //! Inform the master that the arena is no more interested in mandatory concurrency
286 void disable_mandatory_concurrency_impl(arena* a);
288 //! Inform the master that the arena is no more interested in mandatory concurrency
289 void mandatory_concurrency_disable ( arena *a );
290 #endif /* __TBB_ENQUEUE_ENFORCED_CONCURRENCY */
292 //! Request that arena's need in workers should be adjusted.
293 /** Concurrent invocations are possible only on behalf of different arenas. **/
294 void adjust_demand ( arena&, int delta );
296 //! Used when RML asks for join mode during workers termination.
297 bool must_join_workers () const { return my_join_workers; }
299 //! Returns the requested stack size of worker threads.
300 size_t worker_stack_size () const { return my_stack_size; }
302 //! Set number of active workers
303 static void set_active_num_workers( unsigned w );
305 //! Reports active parallelism level according to user's settings
306 static unsigned app_parallelism_limit();
309 //! register master with the resource manager
310 void register_master( ::rml::server::execution_resource_t& rsc_handle ) {
311 __TBB_ASSERT( my_server, "RML server not defined?" );
312 // the server may ignore registration and set master_exec_resource to NULL.
313 my_server->register_master( rsc_handle );
316 //! unregister master with the resource manager
317 void unregister_master( ::rml::server::execution_resource_t& rsc_handle ) const {
318 my_server->unregister_master( rsc_handle );
322 #if __TBB_TASK_GROUP_CONTEXT
323 //! Finds all contexts affected by the state change and propagates the new state to them.
324 /** The propagation is relayed to the market because tasks created by one
325 master thread can be passed to and executed by other masters. This means
326 that context trees can span several arenas at once and thus state change
327 propagation cannot be generally localized to one arena only. **/
328 template <typename T>
329 bool propagate_task_group_state ( T task_group_context::*mptr_state, task_group_context& src, T new_state );
330 #endif /* __TBB_TASK_GROUP_CONTEXT */
332 #if __TBB_TASK_PRIORITY
333 //! Lowers arena's priority is not higher than newPriority
334 /** Returns true if arena priority was actually elevated. **/
335 bool lower_arena_priority ( arena& a, intptr_t new_priority, uintptr_t old_reload_epoch );
337 //! Makes sure arena's priority is not lower than newPriority
338 /** Returns true if arena priority was elevated. Also updates arena's bottom
339 priority boundary if necessary.
341 This method is called whenever a user changes priority, because whether
342 it was hiked or sunk can be determined for sure only under the lock used
343 by this function. **/
344 bool update_arena_priority ( arena& a, intptr_t new_priority );
345 #endif /* __TBB_TASK_PRIORITY */
347 #if __TBB_COUNT_TASK_NODES
348 //! Net number of nodes that have been allocated from heap.
349 /** Updated each time a scheduler or arena is destroyed. */
350 void update_task_node_count( intptr_t delta ) { my_task_node_count += delta; }
351 #endif /* __TBB_COUNT_TASK_NODES */
353 #if __TBB_TASK_GROUP_CONTEXT
354 //! List of registered master threads
355 scheduler_list_type my_masters;
357 //! Array of pointers to the registered workers
358 /** Used by cancellation propagation mechanism.
359 Must be the last data member of the class market. **/
360 generic_scheduler* my_workers[1];
361 #endif /* __TBB_TASK_GROUP_CONTEXT */
363 static unsigned max_num_workers() {
364 global_market_mutex_type::scoped_lock lock( theMarketMutex );
365 return theMarket? theMarket->my_num_workers_hard_limit : 0;
369 } // namespace internal
372 #if defined(_MSC_VER) && defined(_Wp64)
373 // Workaround for overzealous compiler warnings in /Wp64 mode
374 #pragma warning (pop)
375 #endif // warning 4244 is back
377 #endif /* _TBB_market_H */