NUMA++ 0.12.0
Loading...
Searching...
No Matches
scheduler.cpp
1/**
2 * @cond Impl
3 * @file
4 * @ingroup numapp_sched
5 * @brief Definition of scheduler classes
6 * @@copyright
7 * SPDX-FileCopyrightText: 2020-2023 European Southern Observatory (ESO)
8 *
9 * SPDX-License-Identifier: LGPL-3.0-only
10 */
11#include <numapp/scheduler.hpp>
12
13#include <ostream>
14
15#include <pthread.h>
16#include <sys/resource.h>
17
18#include <numapp/lowlevel.hpp>
19
20namespace {
21template <class>
22inline constexpr bool ALWAYS_FALSE_V = false;
23}
24
25namespace numapp {
26namespace thisThread {
27
28std::error_code Apply(IdleScheduler const& scheduler) noexcept {
29 return Apply(0, scheduler);
30}
31
32std::error_code Apply(DynamicScheduler const& scheduler) noexcept {
33 return Apply(0, scheduler);
34}
35
36std::error_code Apply(StaticScheduler const& scheduler) noexcept {
37 return Apply(0, scheduler);
38}
39
40std::error_code Apply(Scheduler const& scheduler) noexcept {
41 return Apply(0, scheduler);
42}
43
44} // namespace thisThread
45
46std::error_code Apply(pid_t thread, IdleScheduler const&) noexcept {
47 return ll::SetSchedulerPolicy(thread, SCHED_IDLE, 0, 0);
48}
49
50std::error_code Apply(pid_t thread, DynamicScheduler const& scheduler) noexcept {
52 thread, static_cast<int>(scheduler.GetPolicy()), 0, scheduler.GetNice());
53}
54
55std::error_code Apply(pid_t thread, StaticScheduler const& scheduler) noexcept {
57 thread, static_cast<int>(scheduler.GetPolicy()), scheduler.GetPriority(), 0);
58}
59
60std::error_code Apply(pid_t thread, Scheduler const& scheduler) noexcept {
61 return std::visit([thread](auto const& sched) { return Apply(thread, sched); },
62 scheduler.Get());
63}
64
65std::ostream& operator<<(std::ostream& os, IdleScheduler const& scheduler) {
66 os << "Idle";
67 return os;
68}
69
70StaticScheduler::StaticScheduler(Policy policy, int prio) : m_policy(policy), m_prio(prio) {
71 if (auto err = SetPolicy(policy); err) {
72 throw std::system_error(err);
73 }
74 if (auto err = SetPriority(prio); err) {
75 throw std::system_error(err);
76 }
77}
78
79std::error_code StaticScheduler::SetPolicy(Policy policy) noexcept {
80 switch (policy) {
81 case Policy::Rr:
82 case Policy::Fifo:
83 m_policy = policy;
84 break;
85 default:
86 return std::make_error_code(std::errc::invalid_argument);
87 };
88 return {};
89}
90
91std::error_code StaticScheduler::SetPriority(int priority) {
92 if (priority < 1 || priority > 99) {
93 return std::make_error_code(std::errc::invalid_argument);
94 }
95 m_prio = priority;
96 return {};
97}
98
99std::ostream& operator<<(std::ostream& os, StaticScheduler::Policy const& policy) {
100 switch (policy) {
101 case StaticScheduler::Policy::Rr:
102 os << "Rr";
103 break;
104 case StaticScheduler::Policy::Fifo:
105 os << "Fifo";
106 break;
107 };
108 return os;
109}
110
111std::ostream& operator<<(std::ostream& os, StaticScheduler const& scheduler) {
112 os << "Static {policy=" << scheduler.GetPolicy() << ", priority=" << scheduler.GetPriority()
113 << "}";
114 return os;
115}
116
117DynamicScheduler::DynamicScheduler(Policy policy, int priority)
118 : m_policy(Policy::Other), m_priority(0) {
119 if (auto err = SetPolicy(policy); err) {
120 throw std::system_error(err);
121 }
122 if (auto err = SetNice(priority); err) {
123 throw std::system_error(err);
124 }
125}
126
127std::error_code DynamicScheduler::SetNice(int priority) noexcept {
128 if (priority < -20 || priority > 19) {
129 return std::make_error_code(std::errc::invalid_argument);
130 }
131 m_priority = priority;
132 return {};
133}
134
135int DynamicScheduler::GetNice() const noexcept {
136 return m_priority;
137}
138
139std::error_code DynamicScheduler::SetPolicy(Policy policy) noexcept {
140 switch (policy) {
141 case Policy::Other:
142 case Policy::Batch:
143 m_policy = policy;
144 break;
145 default:
146 return std::make_error_code(std::errc::invalid_argument);
147 };
148 return {};
149}
150
151std::ostream& operator<<(std::ostream& os, DynamicScheduler::Policy const& policy) {
152 switch (policy) {
153 case DynamicScheduler::Policy::Other:
154 os << "Other";
155 break;
156 case DynamicScheduler::Policy::Batch:
157 os << "Batch";
158 break;
159 };
160 return os;
161}
162
163std::ostream& operator<<(std::ostream& os, DynamicScheduler const& scheduler) {
164 os << "Dynamic {policy=" << scheduler.GetPolicy() << ", nice=" << scheduler.GetNice() << "}";
165 return os;
166}
167
168Scheduler::Scheduler(SchedulerVariant&& sched) noexcept : m_scheduler(sched) {
169}
170
171Scheduler::Scheduler(SchedulerVariant const& sched) : m_scheduler(sched) {
172}
173
174Scheduler::Scheduler(IdleScheduler sched) noexcept
175 : m_scheduler(std::in_place_type<IdleScheduler>, sched) {
176}
177
178Scheduler::Scheduler(StaticScheduler sched) noexcept
179 : m_scheduler(std::in_place_type<StaticScheduler>, sched) {
180}
181
182Scheduler::Scheduler(DynamicScheduler sched) noexcept
183 : m_scheduler(std::in_place_type<DynamicScheduler>, sched) {
184}
185Scheduler::operator SchedulerVariant() const noexcept {
186 return m_scheduler;
187}
188
189/**
190 * @throws std::system_error on error.
191 */
192Scheduler Scheduler::MakeFromActive() {
193 return MakeFromActive(0);
194}
195
196Scheduler Scheduler::MakeFromActive(pid_t pid) {
197 int policy;
198 int static_prio;
199 int dynamic_prio;
200 if (auto err = ll::GetSchedulerPolicy(pid, &policy, &static_prio, &dynamic_prio); err) {
201 throw std::system_error(err);
202 }
203 switch (policy) {
204 case SCHED_BATCH:
205 case SCHED_OTHER: {
206 return Scheduler(
207 DynamicScheduler(static_cast<DynamicScheduler::Policy>(policy), dynamic_prio));
208 }
209 case SCHED_RR:
210 case SCHED_FIFO:
211 return Scheduler(
212 StaticScheduler(static_cast<StaticScheduler::Policy>(policy), static_prio));
213 case SCHED_IDLE:
214 return Scheduler(IdleScheduler());
215 default:
216 throw std::system_error(std::make_error_code(std::errc::not_supported));
217 }
218}
219
220std::ostream& operator<<(std::ostream& os, Scheduler const& scheduler) {
221 std::visit(
222 [&](auto const& sched) {
223 using T = std::decay_t<decltype(sched)>;
224 if constexpr (std::is_same_v<T, IdleScheduler>) {
225 os << "Scheduler {IdleScheduler}";
226 } else if constexpr (std::is_same_v<T, DynamicScheduler>) {
227 os << "Scheduler {" << sched << "}";
228 } else if constexpr (std::is_same_v<T, StaticScheduler>) {
229 os << "Scheduler {" << sched << "}";
230 } else {
231 static_assert(ALWAYS_FALSE_V<T>, "non-exhaustive visitor!");
232 }
233 },
234 scheduler.Get());
235 return os;
236}
237
238} // namespace numapp
239/// @endcond Impl
Normal non-realtime scheduler that use dynamic priority (nice value).
Represents SCHED_IDLE scheduler policy.
A sum-type of all supported schedulers.
Static priority scheduler (real-time).
StaticScheduler(Policy policy, int priority)
Create with provided policy and priority.
std::error_code Apply(CpuAffinity const &affinity) noexcept
Apply policy to calling thread.
std::error_code Apply(pid_t thread, CpuAffinity const &affinity) noexcept
Apply policy to specified thread.
std::variant< DynamicScheduler, StaticScheduler, IdleScheduler > SchedulerVariant
Variant of possible schedulers.
Contains low-level functions.
std::error_code SetSchedulerPolicy(pid_t pid, int policy, int static_priority, int dynamic_priority) noexcept
A low-level, and error prone function to set policy.
Contains scheduler declarations.