33 if (numa_nodes_.empty())
35 numa_nodes_.push_back(-1);
38 arenas_.reserve(numa_nodes_.size());
39 scheduled_counts_.assign(numa_nodes_.size(), 0);
41 for (std::size_t i = 0; i < numa_nodes_.size(); ++i)
43 auto node = numa_nodes_[i];
44 oneapi::tbb::task_arena::constraints constraints;
45 constraints.set_numa_id(node);
46 auto scheduler = std::make_unique<TbbScheduler>(constraints);
47 node_to_index_.emplace(node, arenas_.size());
48 arenas_.push_back(Arena{node, std::move(scheduler)});
51 fmt::print(
"[uni20] TbbNumaScheduler: initialized {} NUMA nodes\n", arenas_.size());
58 int target = task.preferred_numa_node().value_or(this->select_next_numa_node());
59 this->schedule_on_node(std::move(task), target);
68 this->schedule_on_node(std::move(task), numa_node);
74 for (
auto& arena : arenas_)
76 arena.scheduler->pause();
83 for (
auto& arena : arenas_)
85 arena.scheduler->resume();
92 for (
auto& arena : arenas_)
94 arena.scheduler->run_all();
100 [[nodiscard]]
const std::vector<int>&
numa_nodes() const noexcept {
return numa_nodes_; }
107 CHECK(!arenas_.empty(),
"TbbNumaScheduler must retain at least one arena");
108 auto idx = this->index_for_node(numa_node);
109 std::lock_guard<std::mutex> lock(counts_mutex_);
110 return scheduled_counts_[idx];
116 CHECK(!arenas_.empty(),
"TbbNumaScheduler must retain at least one arena");
117 arenas_[this->index_for_node(this->select_next_numa_node())].scheduler->execute_batch(
118 batch.
size(), [&batch](std::size_t index) { batch(index); });
121 bool accepts_route(TaskRoute route)
const noexcept override
128 bool can_direct_transfer(TaskHandle, TaskHandle)
const noexcept override {
return false; }
131 void reschedule(BasicTask&& task)
override
133 if (
auto preferred = task.preferred_numa_node())
135 this->reschedule_on_node(std::move(task), *preferred);
139 this->reschedule_on_node(std::move(task), this->select_next_numa_node());
146 std::unique_ptr<TbbScheduler> scheduler;
149 [[nodiscard]] std::size_t index_for_node(
int numa_node)
const noexcept
151 if (
auto it = node_to_index_.find(numa_node); it != node_to_index_.end())
158 [[nodiscard]]
int select_next_numa_node() noexcept
160 CHECK(!arenas_.empty(),
"TbbNumaScheduler must retain at least one arena");
161 auto index = next_index_.fetch_add(1, std::memory_order_relaxed) % arenas_.size();
162 return arenas_[index].numa_node;
165 void schedule_on_node(AsyncTask&& task,
int numa_node)
167 CHECK(!arenas_.empty(),
"TbbNumaScheduler must retain at least one arena");
168 auto index = this->index_for_node(numa_node);
169 auto& arena = arenas_[index];
170 auto actual_node = arena.numa_node;
171 task.set_preferred_numa_node(actual_node);
173 std::lock_guard<std::mutex> lock(counts_mutex_);
174 ++scheduled_counts_[index];
176 arena.scheduler->schedule(std::move(task));
179 void reschedule_on_node(BasicTask&& task,
int numa_node)
181 CHECK(!arenas_.empty(),
"TbbNumaScheduler must retain at least one arena");
182 auto index = this->index_for_node(numa_node);
183 auto& arena = arenas_[index];
184 auto actual_node = arena.numa_node;
185 task.set_preferred_numa_node(actual_node);
187 std::lock_guard<std::mutex> lock(counts_mutex_);
188 ++scheduled_counts_[index];
190 arena.scheduler->reschedule(std::move(task));
193 std::vector<int> numa_nodes_;
194 std::vector<Arena> arenas_;
195 std::unordered_map<int, std::size_t> node_to_index_;
196 std::vector<std::size_t> scheduled_counts_;
197 mutable std::mutex counts_mutex_;
198 std::atomic<std::size_t> next_index_{0};
void schedule(AsyncTask &&task, int numa_node)
Schedule a coroutine on a specific NUMA node.
Definition tbb_numa_scheduler.hpp:65
void schedule(AsyncTask &&task) override
Schedule a coroutine, choosing an arena based on NUMA preference.
Definition tbb_numa_scheduler.hpp:55
This represents the reverse-mode adjoint for functions of complex variables, assuming a real-valued s...
Definition async/async.hpp:26