xref: /oneTBB/src/tbb/market.cpp (revision 71e1bb8e)
151c0b2f7Stbbdev /*
2c4568449SPavel Kumbrasev     Copyright (c) 2005-2023 Intel Corporation
351c0b2f7Stbbdev 
451c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev     you may not use this file except in compliance with the License.
651c0b2f7Stbbdev     You may obtain a copy of the License at
751c0b2f7Stbbdev 
851c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev 
1051c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev     See the License for the specific language governing permissions and
1451c0b2f7Stbbdev     limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev 
1751c0b2f7Stbbdev #include "arena.h"
18c4568449SPavel Kumbrasev #include "market.h"
1951c0b2f7Stbbdev 
20c4568449SPavel Kumbrasev #include <algorithm> // std::find
2151c0b2f7Stbbdev 
2251c0b2f7Stbbdev namespace tbb {
2351c0b2f7Stbbdev namespace detail {
2451c0b2f7Stbbdev namespace r1 {
2551c0b2f7Stbbdev 
2651c0b2f7Stbbdev 
27c4568449SPavel Kumbrasev class tbb_permit_manager_client : public pm_client {
28c4568449SPavel Kumbrasev public:
tbb_permit_manager_client(arena & a)29c4568449SPavel Kumbrasev     tbb_permit_manager_client(arena& a) : pm_client(a) {}
3051c0b2f7Stbbdev 
register_thread()31*71e1bb8eSPavel Kumbrasev     void register_thread() override {}
32*71e1bb8eSPavel Kumbrasev 
unregister_thread()33*71e1bb8eSPavel Kumbrasev     void unregister_thread() override {}
34*71e1bb8eSPavel Kumbrasev 
set_allotment(unsigned allotment)35c4568449SPavel Kumbrasev     void set_allotment(unsigned allotment) {
36c4568449SPavel Kumbrasev         my_arena.set_allotment(allotment);
3751c0b2f7Stbbdev     }
38c4568449SPavel Kumbrasev };
3951c0b2f7Stbbdev 
4051c0b2f7Stbbdev //------------------------------------------------------------------------
4151c0b2f7Stbbdev // market
4251c0b2f7Stbbdev //------------------------------------------------------------------------
4351c0b2f7Stbbdev 
market(unsigned workers_soft_limit)44c4568449SPavel Kumbrasev market::market(unsigned workers_soft_limit)
45c4568449SPavel Kumbrasev     : my_num_workers_soft_limit(workers_soft_limit)
46c4568449SPavel Kumbrasev {}
47c4568449SPavel Kumbrasev 
create_client(arena & a)48c4568449SPavel Kumbrasev pm_client* market::create_client(arena& a) {
49c4568449SPavel Kumbrasev     return new (cache_aligned_allocate(sizeof(tbb_permit_manager_client))) tbb_permit_manager_client(a);
50c4568449SPavel Kumbrasev }
51c4568449SPavel Kumbrasev 
register_client(pm_client * c,d1::constraints &)52*71e1bb8eSPavel Kumbrasev void market::register_client(pm_client* c, d1::constraints&) {
53c4568449SPavel Kumbrasev     mutex_type::scoped_lock lock(my_mutex);
54c4568449SPavel Kumbrasev     my_clients[c->priority_level()].push_back(c);
55c4568449SPavel Kumbrasev }
56c4568449SPavel Kumbrasev 
unregister_and_destroy_client(pm_client & c)57c4568449SPavel Kumbrasev void market::unregister_and_destroy_client(pm_client& c) {
5851c0b2f7Stbbdev     {
59c4568449SPavel Kumbrasev         mutex_type::scoped_lock lock(my_mutex);
60c4568449SPavel Kumbrasev         auto& clients = my_clients[c.priority_level()];
61c4568449SPavel Kumbrasev         auto it = std::find(clients.begin(), clients.end(), &c);
62c4568449SPavel Kumbrasev         __TBB_ASSERT(it != clients.end(), "Destroying of an unregistered client");
63c4568449SPavel Kumbrasev         clients.erase(it);
6451c0b2f7Stbbdev     }
6551c0b2f7Stbbdev 
66c4568449SPavel Kumbrasev     auto client = static_cast<tbb_permit_manager_client*>(&c);
67c4568449SPavel Kumbrasev     client->~tbb_permit_manager_client();
68c4568449SPavel Kumbrasev     cache_aligned_deallocate(client);
6931cba51fSAlex }
7031cba51fSAlex 
update_allotment()71c4568449SPavel Kumbrasev void market::update_allotment() {
72c4568449SPavel Kumbrasev     int effective_soft_limit = my_mandatory_num_requested > 0 && my_num_workers_soft_limit == 0 ? 1 : my_num_workers_soft_limit;
73c4568449SPavel Kumbrasev     int max_workers = min(my_total_demand, effective_soft_limit);
74c4568449SPavel Kumbrasev     __TBB_ASSERT(max_workers >= 0, nullptr);
7551c0b2f7Stbbdev 
7651c0b2f7Stbbdev     int unassigned_workers = max_workers;
7751c0b2f7Stbbdev     int assigned = 0;
7851c0b2f7Stbbdev     int carry = 0;
7951c0b2f7Stbbdev     unsigned max_priority_level = num_priority_levels;
8051c0b2f7Stbbdev     for (unsigned list_idx = 0; list_idx < num_priority_levels; ++list_idx ) {
81b15aabb3Stbbdev         int assigned_per_priority = min(my_priority_level_demand[list_idx], unassigned_workers);
82b15aabb3Stbbdev         unassigned_workers -= assigned_per_priority;
83c4568449SPavel Kumbrasev         // We use reverse iterator there to serve last added clients first
84c4568449SPavel Kumbrasev         for (auto it = my_clients[list_idx].rbegin(); it != my_clients[list_idx].rend(); ++it) {
85c4568449SPavel Kumbrasev             tbb_permit_manager_client& client = static_cast<tbb_permit_manager_client&>(**it);
86c4568449SPavel Kumbrasev             if (client.max_workers() == 0) {
87c4568449SPavel Kumbrasev                 client.set_allotment(0);
8851c0b2f7Stbbdev                 continue;
8951c0b2f7Stbbdev             }
9051c0b2f7Stbbdev 
9151c0b2f7Stbbdev             if (max_priority_level == num_priority_levels) {
9251c0b2f7Stbbdev                 max_priority_level = list_idx;
9351c0b2f7Stbbdev             }
9451c0b2f7Stbbdev 
9551c0b2f7Stbbdev             int allotted = 0;
96c4568449SPavel Kumbrasev             if (my_num_workers_soft_limit == 0) {
9751c0b2f7Stbbdev                 __TBB_ASSERT(max_workers == 0 || max_workers == 1, nullptr);
98c4568449SPavel Kumbrasev                 allotted = client.min_workers() > 0 && assigned < max_workers ? 1 : 0;
99c4568449SPavel Kumbrasev             } else {
100c4568449SPavel Kumbrasev                 int tmp = client.max_workers() * assigned_per_priority + carry;
10151c0b2f7Stbbdev                 allotted = tmp / my_priority_level_demand[list_idx];
10251c0b2f7Stbbdev                 carry = tmp % my_priority_level_demand[list_idx];
103c4568449SPavel Kumbrasev                 __TBB_ASSERT(allotted <= client.max_workers(), nullptr);
10451c0b2f7Stbbdev             }
105c4568449SPavel Kumbrasev             client.set_allotment(allotted);
106c4568449SPavel Kumbrasev             client.set_top_priority(list_idx == max_priority_level);
10751c0b2f7Stbbdev             assigned += allotted;
10851c0b2f7Stbbdev         }
10951c0b2f7Stbbdev     }
110c4568449SPavel Kumbrasev     __TBB_ASSERT(assigned == max_workers, nullptr);
11151c0b2f7Stbbdev }
11251c0b2f7Stbbdev 
set_active_num_workers(int soft_limit)113c4568449SPavel Kumbrasev void market::set_active_num_workers(int soft_limit) {
114c4568449SPavel Kumbrasev     mutex_type::scoped_lock lock(my_mutex);
115c4568449SPavel Kumbrasev     if (my_num_workers_soft_limit != soft_limit) {
116c4568449SPavel Kumbrasev         my_num_workers_soft_limit = soft_limit;
117c4568449SPavel Kumbrasev         update_allotment();
118c4568449SPavel Kumbrasev     }
11951c0b2f7Stbbdev }
12051c0b2f7Stbbdev 
adjust_demand(pm_client & c,int mandatory_delta,int workers_delta)121c4568449SPavel Kumbrasev void market::adjust_demand(pm_client& c, int mandatory_delta, int workers_delta) {
122c4568449SPavel Kumbrasev     __TBB_ASSERT(-1 <= mandatory_delta && mandatory_delta <= 1, nullptr);
12351c0b2f7Stbbdev 
124c4568449SPavel Kumbrasev     int delta{};
12551c0b2f7Stbbdev     {
126c4568449SPavel Kumbrasev         mutex_type::scoped_lock lock(my_mutex);
127c4568449SPavel Kumbrasev         // Update client's state
128c4568449SPavel Kumbrasev         delta = c.update_request(mandatory_delta, workers_delta);
12951c0b2f7Stbbdev 
130c4568449SPavel Kumbrasev         // Update market's state
131c4568449SPavel Kumbrasev         my_total_demand += delta;
132c4568449SPavel Kumbrasev         my_priority_level_demand[c.priority_level()] += delta;
133c4568449SPavel Kumbrasev         my_mandatory_num_requested += mandatory_delta;
134c4568449SPavel Kumbrasev 
135c4568449SPavel Kumbrasev         update_allotment();
13651c0b2f7Stbbdev     }
13751c0b2f7Stbbdev 
138c4568449SPavel Kumbrasev     notify_thread_request(delta);
13951c0b2f7Stbbdev }
14051c0b2f7Stbbdev 
14151c0b2f7Stbbdev } // namespace r1
14251c0b2f7Stbbdev } // namespace detail
14351c0b2f7Stbbdev } // namespace tbb
144