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