]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/include/seastar/core/scheduling.hh
import quincy beta 17.1.0
[ceph.git] / ceph / src / seastar / include / seastar / core / scheduling.hh
1 /*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 /*
19 * Copyright (C) 2016 Scylla DB Ltd
20 */
21
22 #pragma once
23
24 #include <chrono>
25 #include <typeindex>
26 #include <seastar/core/sstring.hh>
27 #include <seastar/core/function_traits.hh>
28 #include <seastar/util/concepts.hh>
29
30 /// \file
31
32 namespace seastar {
33
34 constexpr unsigned max_scheduling_groups() { return SEASTAR_SCHEDULING_GROUPS_COUNT; }
35
36 #if SEASTAR_API_LEVEL < 6
37 #define SEASTAR_ELLIPSIS ...
38 template <typename SEASTAR_ELLIPSIS T>
39 #else
40 #define SEASTAR_ELLIPSIS
41 template <typename T = void>
42 #endif
43 class future;
44
45 class reactor;
46
47 class scheduling_group;
48 class scheduling_group_key;
49
50 using sched_clock = std::chrono::steady_clock;
51
52 namespace internal {
53
54 // Returns an index between 0 and max_scheduling_groups()
55 unsigned scheduling_group_index(scheduling_group sg) noexcept;
56 scheduling_group scheduling_group_from_index(unsigned index) noexcept;
57
58 unsigned long scheduling_group_key_id(scheduling_group_key) noexcept;
59
60 template<typename T>
61 T* scheduling_group_get_specific_ptr(scheduling_group sg, scheduling_group_key key) noexcept;
62
63 }
64
65
66 /// Creates a scheduling group with a specified number of shares.
67 ///
68 /// The operation is global and affects all shards. The returned scheduling
69 /// group can then be used in any shard.
70 ///
71 /// \param name A name that identifiers the group; will be used as a label
72 /// in the group's metrics
73 /// \param shares number of shares of the CPU time allotted to the group;
74 /// Use numbers in the 1-1000 range (but can go above).
75 /// \return a scheduling group that can be used on any shard
76 future<scheduling_group> create_scheduling_group(sstring name, float shares) noexcept;
77
78 /// Destroys a scheduling group.
79 ///
80 /// Destroys a \ref scheduling_group previously created with create_scheduling_group().
81 /// The destroyed group must not be currently in use and must not be used later.
82 ///
83 /// The operation is global and affects all shards.
84 ///
85 /// \param sg The scheduling group to be destroyed
86 /// \return a future that is ready when the scheduling group has been torn down
87 future<> destroy_scheduling_group(scheduling_group sg) noexcept;
88
89 /// Rename scheduling group.
90 ///
91 /// Renames a \ref scheduling_group previously created with create_scheduling_group().
92 ///
93 /// The operation is global and affects all shards.
94 /// The operation affects the exported statistics labels.
95 ///
96 /// \param sg The scheduling group to be renamed
97 /// \param new_name The new name for the scheduling group.
98 /// \return a future that is ready when the scheduling group has been renamed
99 future<> rename_scheduling_group(scheduling_group sg, sstring new_name) noexcept;
100
101
102 /**
103 * Represents a configuration for a specific scheduling group value,
104 * it contains all that is needed to maintain a scheduling group specific
105 * value when it needs to be created, due to, for example, a new
106 * \ref scheduling_group being created.
107 *
108 * @note is is recomended to use @ref make_scheduling_group_key_config in order to
109 * create and configure this syructure. The only reason that one might want to not use
110 * this method is because of a need for specific intervention in the construction or
111 * destruction of the value. Even then, it is recommended to first create the configuration
112 * with @ref make_scheduling_group_key_config and only the change it.
113 *
114 */
115 struct scheduling_group_key_config {
116 /**
117 * Constructs a default configuration
118 */
119 scheduling_group_key_config() :
120 scheduling_group_key_config(typeid(void)) {}
121 /**
122 * Creates a configuration that is made for a specific type.
123 * It does not contain the right alignment and allocation sizes
124 * neither the correct construction or destruction logic, but only
125 * the indication for the intended type which is used in debug mode
126 * to make sure that the correct type is reffered to when accessing
127 * the value.
128 * @param type_info - the type information class (create with typeid(T)).
129 */
130 scheduling_group_key_config(const std::type_info& type_info) :
131 type_index(type_info) {}
132 /// The allocation size for the value (usually: sizeof(T))
133 size_t allocation_size;
134 /// The required alignment of the value (usually: alignof(T))
135 size_t alignment;
136 /// Holds the type information for debug mode runtime validation
137 std::type_index type_index;
138 /// A function that will be called for each newly allocated value
139 std::function<void (void*)> constructor;
140 /// A function that will be called for each element that is about
141 /// to be dealocated.
142 std::function<void (void*)> destructor;
143
144 };
145
146
147 /**
148 * A class that is intended to encapsulate the scheduling group specific
149 * key and "hide" it implementation concerns and details.
150 *
151 * @note this object can be copied accross shards and scheduling groups.
152 */
153 class scheduling_group_key {
154 public:
155 /// The only user allowed operation on a key is copying.
156 scheduling_group_key(const scheduling_group_key&) noexcept = default;
157 scheduling_group_key(scheduling_group_key&&) noexcept = default;
158 private:
159 scheduling_group_key(unsigned long id) noexcept :
160 _id(id) {}
161 unsigned long _id;
162 unsigned long id() const noexcept {
163 return _id;
164 }
165 friend class reactor;
166 friend future<scheduling_group_key> scheduling_group_key_create(scheduling_group_key_config cfg) noexcept;
167 template<typename T>
168 friend T* internal::scheduling_group_get_specific_ptr(scheduling_group sg, scheduling_group_key key) noexcept;
169 template<typename T>
170 friend T& scheduling_group_get_specific(scheduling_group_key key) noexcept;
171
172 friend unsigned long internal::scheduling_group_key_id(scheduling_group_key key) noexcept;
173 };
174
175 namespace internal {
176
177 inline unsigned long scheduling_group_key_id(scheduling_group_key key) noexcept {
178 return key.id();
179 }
180
181 /**
182 * @brief A function in the spirit of Cpp17 apply, but specifically for constructors.
183 * This function is used in order to preserve support in Cpp14.
184
185 * @tparam ConstructorType - the constructor type or in other words the type to be constructed
186 * @tparam Tuple - T params tuple type (should be deduced)
187 * @tparam size_t...Idx - a sequence of indexes in order to access the typpels members in compile time.
188 * (should be deduced)
189 *
190 * @param pre_alocated_mem - a pointer to the pre allocated memory chunk that will hold the
191 * the initialized object.
192 * @param args - A tupple that holds the prarameters for the constructor
193 * @param idx_seq - An index sequence that will be used to access the members of the tuple in compile
194 * time.
195 *
196 * @note this function was not intended to be called by users and it is only a utility function
197 * for suporting \ref make_scheduling_group_key_config
198 */
199 template<typename ConstructorType, typename Tuple, size_t...Idx>
200 void apply_constructor(void* pre_alocated_mem, Tuple args, std::index_sequence<Idx...> idx_seq) {
201 new (pre_alocated_mem) ConstructorType(std::get<Idx>(args)...);
202 }
203 }
204
205 /**
206 * A template function that builds a scheduling group specific value configuration.
207 * This configuration is used by the infrastructure to allocate memory for the values
208 * and initialize or deinitialize them when they are created or destroyed.
209 *
210 * @tparam T - the type for the newly created value.
211 * @tparam ...ConstructorArgs - the types for the constructor parameters (should be deduced)
212 * @param args - The parameters for the constructor.
213 * @return a fully initialized \ref scheduling_group_key_config object.
214 */
215 template <typename T, typename... ConstructorArgs>
216 scheduling_group_key_config
217 make_scheduling_group_key_config(ConstructorArgs... args) {
218 scheduling_group_key_config sgkc(typeid(T));
219 sgkc.allocation_size = sizeof(T);
220 sgkc.alignment = alignof(T);
221 sgkc.constructor = [args = std::make_tuple(args...)] (void* p) {
222 internal::apply_constructor<T>(p, args, std::make_index_sequence<sizeof...(ConstructorArgs)>());
223 };
224 sgkc.destructor = [] (void* p) {
225 static_cast<T*>(p)->~T();
226 };
227 return sgkc;
228 }
229
230 /**
231 * Returns a future that holds a scheduling key and resolves when this key can be used
232 * to access the scheduling group specific value it represents.
233 * @param cfg - A \ref scheduling_group_key_config object (by recomendation: initialized with
234 * \ref make_scheduling_group_key_config )
235 * @return A future containing \ref scheduling_group_key for the newly created specific value.
236 */
237 future<scheduling_group_key> scheduling_group_key_create(scheduling_group_key_config cfg) noexcept;
238
239 /**
240 * Returnes a reference to the given scheduling group specific value
241 * @tparam T - the type of the scheduling specific type (cannot be deduced)
242 * @param sg - the scheduling group which it's specific value to retrieve
243 * @param key - the key of the value to retrieve.
244 * @return A reference to the scheduling specific value.
245 */
246 template<typename T>
247 T& scheduling_group_get_specific(scheduling_group sg, scheduling_group_key key);
248
249
250 /// \brief Identifies function calls that are accounted as a group
251 ///
252 /// A `scheduling_group` is a tag that can be used to mark a function call.
253 /// Executions of such tagged calls are accounted as a group.
254 class scheduling_group {
255 unsigned _id;
256 private:
257 explicit scheduling_group(unsigned id) noexcept : _id(id) {}
258 public:
259 /// Creates a `scheduling_group` object denoting the default group
260 constexpr scheduling_group() noexcept : _id(0) {} // must be constexpr for current_scheduling_group_holder
261 bool active() const noexcept;
262 const sstring& name() const noexcept;
263 bool operator==(scheduling_group x) const noexcept { return _id == x._id; }
264 bool operator!=(scheduling_group x) const noexcept { return _id != x._id; }
265 bool is_main() const noexcept { return _id == 0; }
266 template<typename T>
267 /**
268 * Returnes a reference to this scheduling group specific value
269 * @tparam T - the type of the scheduling specific type (cannot be deduced)
270 * @param key - the key of the value to retrieve.
271 * @return A reference to this scheduling specific value.
272 */
273 T& get_specific(scheduling_group_key key) noexcept {
274 return *internal::scheduling_group_get_specific_ptr<T>(*this, key);
275 }
276 /// Adjusts the number of shares allotted to the group.
277 ///
278 /// Dynamically adjust the number of shares allotted to the group, increasing or
279 /// decreasing the amount of CPU bandwidth it gets. The adjustment is local to
280 /// the shard.
281 ///
282 /// This can be used to reduce a background job's interference with a foreground
283 /// load: the shares can be started at a low value, increased when the background
284 /// job's backlog increases, and reduced again when the backlog decreases.
285 ///
286 /// \param shares number of shares allotted to the group. Use numbers
287 /// in the 1-1000 range.
288 void set_shares(float shares) noexcept;
289 friend future<scheduling_group> create_scheduling_group(sstring name, float shares) noexcept;
290 friend future<> destroy_scheduling_group(scheduling_group sg) noexcept;
291 friend future<> rename_scheduling_group(scheduling_group sg, sstring new_name) noexcept;
292 friend class reactor;
293 friend unsigned internal::scheduling_group_index(scheduling_group sg) noexcept;
294 friend scheduling_group internal::scheduling_group_from_index(unsigned index) noexcept;
295
296 template<typename SpecificValType, typename Mapper, typename Reducer, typename Initial>
297 SEASTAR_CONCEPT( requires requires(SpecificValType specific_val, Mapper mapper, Reducer reducer, Initial initial) {
298 {reducer(initial, mapper(specific_val))} -> std::convertible_to<Initial>;
299 })
300 friend future<typename function_traits<Reducer>::return_type>
301 map_reduce_scheduling_group_specific(Mapper mapper, Reducer reducer, Initial initial_val, scheduling_group_key key);
302
303 template<typename SpecificValType, typename Reducer, typename Initial>
304 SEASTAR_CONCEPT( requires requires(SpecificValType specific_val, Reducer reducer, Initial initial) {
305 {reducer(initial, specific_val)} -> std::convertible_to<Initial>;
306 })
307 friend future<typename function_traits<Reducer>::return_type>
308 reduce_scheduling_group_specific(Reducer reducer, Initial initial_val, scheduling_group_key key);
309
310
311 };
312
313 /// \cond internal
314 namespace internal {
315
316 inline
317 unsigned
318 scheduling_group_index(scheduling_group sg) noexcept {
319 return sg._id;
320 }
321
322 inline
323 scheduling_group
324 scheduling_group_from_index(unsigned index) noexcept {
325 return scheduling_group(index);
326 }
327
328 inline
329 scheduling_group*
330 current_scheduling_group_ptr() noexcept {
331 // Slow unless constructor is constexpr
332 static thread_local scheduling_group sg;
333 return &sg;
334 }
335
336 }
337 /// \endcond
338
339 /// Returns the current scheduling group
340 inline
341 scheduling_group
342 current_scheduling_group() noexcept {
343 return *internal::current_scheduling_group_ptr();
344 }
345
346 inline
347 scheduling_group
348 default_scheduling_group() noexcept {
349 return scheduling_group();
350 }
351
352 inline
353 bool
354 scheduling_group::active() const noexcept {
355 return *this == current_scheduling_group();
356 }
357
358 }
359
360 namespace std {
361
362 template <>
363 struct hash<seastar::scheduling_group> {
364 size_t operator()(seastar::scheduling_group sg) const noexcept {
365 return seastar::internal::scheduling_group_index(sg);
366 }
367 };
368
369 }