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