Seastar
High performance C++ framework for concurrent servers
scheduling_specific.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) 2019 Scylla DB Ltd
20 */
21
22#ifndef SEASTAR_MODULE
24#include <seastar/core/map_reduce.hh>
25#include <seastar/util/modules.hh>
26#include <array>
27#include <typeindex>
28#include <vector>
29#include <ranges>
30#endif
31
32#pragma once
33
34namespace seastar {
35
36namespace internal {
37
38struct scheduling_group_specific_thread_local_data {
39 struct per_scheduling_group {
40 bool queue_is_initialized = false;
46 std::vector<void*> specific_vals;
47 };
48 std::array<per_scheduling_group, max_scheduling_groups()> per_scheduling_group_data;
49 std::vector<scheduling_group_key_config> scheduling_group_key_configs;
50};
51
52#ifdef SEASTAR_BUILD_SHARED_LIBS
53scheduling_group_specific_thread_local_data** get_scheduling_group_specific_thread_local_data_ptr() noexcept;
54#else
55inline
56scheduling_group_specific_thread_local_data** get_scheduling_group_specific_thread_local_data_ptr() noexcept {
57 static thread_local scheduling_group_specific_thread_local_data* data;
58 return &data;
59}
60#endif
61inline
62scheduling_group_specific_thread_local_data& get_scheduling_group_specific_thread_local_data() noexcept {
63 return **get_scheduling_group_specific_thread_local_data_ptr();
64}
65
66[[noreturn]] void no_such_scheduling_group(scheduling_group sg);
67
76template<typename T>
77T* scheduling_group_get_specific_ptr(scheduling_group sg, scheduling_group_key key) noexcept {
78 auto& data = internal::get_scheduling_group_specific_thread_local_data();
79#ifdef SEASTAR_DEBUG
80 assert(std::type_index(typeid(T)) == data.scheduling_group_key_configs[key.id()].type_index);
81#endif
82 auto sg_id = internal::scheduling_group_index(sg);
83 if (__builtin_expect(sg_id < data.per_scheduling_group_data.size() &&
84 data.per_scheduling_group_data[sg_id].queue_is_initialized, true)) {
85 return reinterpret_cast<T*>(data.per_scheduling_group_data[sg_id].specific_vals[key.id()]);
86 }
87 return nullptr;
88}
89
90}
91
92SEASTAR_MODULE_EXPORT_BEGIN
93
103template<typename T>
105 T* p = internal::scheduling_group_get_specific_ptr<T>(sg, std::move(key));
106 if (!p) {
107 internal::no_such_scheduling_group(sg);
108 }
109 return *p;
110}
111
119template<typename T>
121 // Unlike internal::scheduling_group_get_specific_ptr, this can
122 // return a reference to an element whose queue_is_initialized is
123 // false.
124 auto& data = internal::get_scheduling_group_specific_thread_local_data();
125 assert(std::type_index(typeid(T)) == data.scheduling_group_key_configs[key.id()].type_index);
126 auto sg_id = internal::scheduling_group_index(current_scheduling_group());
127 return *reinterpret_cast<T*>(data.per_scheduling_group_data[sg_id].specific_vals[key.id()]);
128}
129
145template<typename SpecificValType, typename Mapper, typename Reducer, typename Initial>
146requires requires(SpecificValType specific_val, Mapper mapper, Reducer reducer, Initial initial) {
147 {reducer(initial, mapper(specific_val))} -> std::convertible_to<Initial>;
148}
149future<typename function_traits<Reducer>::return_type>
150map_reduce_scheduling_group_specific(Mapper mapper, Reducer reducer,
151 Initial initial_val, scheduling_group_key key) {
152 using per_scheduling_group = internal::scheduling_group_specific_thread_local_data::per_scheduling_group;
153 auto& data = internal::get_scheduling_group_specific_thread_local_data();
154 auto wrapped_mapper = [key, mapper] (per_scheduling_group& psg) {
155 auto id = internal::scheduling_group_key_id(key);
156 return make_ready_future<typename function_traits<Mapper>::return_type>
157 (mapper(*reinterpret_cast<SpecificValType*>(psg.specific_vals[id])));
158 };
159
160 return map_reduce(
161 data.per_scheduling_group_data
162 | std::views::filter(std::mem_fn(&per_scheduling_group::queue_is_initialized)),
163 wrapped_mapper, std::move(initial_val), reducer);
164}
165
179template<typename SpecificValType, typename Reducer, typename Initial>
180requires requires(SpecificValType specific_val, Reducer reducer, Initial initial) {
181 {reducer(initial, specific_val)} -> std::convertible_to<Initial>;
182}
183future<typename function_traits<Reducer>::return_type>
184reduce_scheduling_group_specific(Reducer reducer, Initial initial_val, scheduling_group_key key) {
185 using per_scheduling_group = internal::scheduling_group_specific_thread_local_data::per_scheduling_group;
186 auto& data = internal::get_scheduling_group_specific_thread_local_data();
187
188 auto mapper = [key] (per_scheduling_group& psg) {
189 auto id = internal::scheduling_group_key_id(key);
190 return make_ready_future<SpecificValType>(*reinterpret_cast<SpecificValType*>(psg.specific_vals[id]));
191 };
192
193 return map_reduce(
194 data.per_scheduling_group_data
195 | std::views::filter(std::mem_fn(&per_scheduling_group::queue_is_initialized)),
196 mapper, std::move(initial_val), reducer);
197}
198
199SEASTAR_MODULE_EXPORT_END
200
201}
Definition: scheduling.hh:183
Identifies function calls that are accounted as a group.
Definition: scheduling.hh:285
auto map_reduce(Iterator begin, Iterator end, Mapper &&mapper, Reducer &&r) -> typename reducer_traits< Reducer >::future_type
Definition: map_reduce.hh:107
Seastar API namespace.
Definition: abort_on_ebadf.hh:26
future< typename function_traits< Reducer >::return_type > map_reduce_scheduling_group_specific(Mapper mapper, Reducer reducer, Initial initial_val, scheduling_group_key key)
Definition: scheduling_specific.hh:150
scheduling_group current_scheduling_group() noexcept
Returns the current scheduling group.
Definition: scheduling.hh:397
T & scheduling_group_get_specific(scheduling_group sg, scheduling_group_key key)
Definition: scheduling_specific.hh:104
future< typename function_traits< Reducer >::return_type > reduce_scheduling_group_specific(Reducer reducer, Initial initial_val, scheduling_group_key key)
Definition: scheduling_specific.hh:184