Thread System 0.3.1
High-performance C++20 thread pool with work stealing and DAG scheduling
Loading...
Searching...
No Matches
steal_backoff_strategy.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
12#pragma once
13
14#include <algorithm>
15#include <chrono>
16#include <cstddef>
17#include <cstdint>
18#include <random>
19
20namespace kcenon::thread
21{
22
39enum class steal_backoff_strategy : std::uint8_t
40{
41 fixed,
42 linear,
45};
46
52{
54 std::chrono::microseconds initial_backoff{50};
55 std::chrono::microseconds max_backoff{1000};
56 double multiplier = 2.0;
57 double jitter_factor = 0.5;
58};
59
91{
92public:
98 : config_(config)
99 , rng_(std::random_device{}())
100 {
101 }
102
111 [[nodiscard]] auto calculate(std::size_t attempt) -> std::chrono::microseconds
112 {
113 auto delay = calculate_base_delay(attempt);
114
116 {
118 }
119
120 return cap_delay(delay);
121 }
122
127 [[nodiscard]] auto get_config() const -> const steal_backoff_config&
128 {
129 return config_;
130 }
131
137 {
138 config_ = config;
139 }
140
141private:
145 [[nodiscard]] auto calculate_base_delay(std::size_t attempt) const
146 -> std::chrono::microseconds
147 {
148 auto initial = static_cast<double>(config_.initial_backoff.count());
149 auto max_count = static_cast<double>(config_.max_backoff.count());
150
151 switch (config_.strategy)
152 {
155
157 return std::chrono::microseconds{
158 static_cast<std::int64_t>(initial * static_cast<double>(attempt + 1))};
159
162 {
163 // Calculate multiplier^attempt with overflow protection
164 double factor = 1.0;
165 for (std::size_t i = 0; i < attempt; ++i)
166 {
167 factor *= config_.multiplier;
168 // Early exit if we've exceeded max to avoid unnecessary computation
169 if (factor * initial > max_count)
170 {
171 return config_.max_backoff;
172 }
173 }
174 return std::chrono::microseconds{
175 static_cast<std::int64_t>(initial * factor)};
176 }
177
178 default:
180 }
181 }
182
186 [[nodiscard]] auto apply_jitter(std::chrono::microseconds delay)
187 -> std::chrono::microseconds
188 {
189 using rep = std::chrono::microseconds::rep;
190 rep base = delay.count();
191 rep jitter_range =
192 static_cast<rep>(static_cast<double>(base) * config_.jitter_factor);
193
194 if (jitter_range <= 0)
195 {
196 return delay;
197 }
198
199 std::uniform_int_distribution<rep> dist(-jitter_range, jitter_range);
200 rep jittered = base + dist(rng_);
201
202 // Ensure we don't go negative
203 return std::chrono::microseconds{std::max(rep{1}, jittered)};
204 }
205
209 [[nodiscard]] auto cap_delay(std::chrono::microseconds delay) const
210 -> std::chrono::microseconds
211 {
212 return std::min(delay, config_.max_backoff);
213 }
214
216 std::mt19937_64 rng_;
217};
218
224constexpr const char* to_string(steal_backoff_strategy strategy)
225{
226 switch (strategy)
227 {
229 return "fixed";
231 return "linear";
233 return "exponential";
235 return "adaptive_jitter";
236 default:
237 return "unknown";
238 }
239}
240
241} // namespace kcenon::thread
Calculates backoff delays for work-stealing operations.
void set_config(steal_backoff_config config)
Update the configuration.
auto apply_jitter(std::chrono::microseconds delay) -> std::chrono::microseconds
Apply random jitter to a delay.
auto calculate(std::size_t attempt) -> std::chrono::microseconds
Calculate backoff delay for a given attempt number.
auto cap_delay(std::chrono::microseconds delay) const -> std::chrono::microseconds
Cap delay at maximum.
auto get_config() const -> const steal_backoff_config &
Get the current configuration.
backoff_calculator(steal_backoff_config config={})
Construct a backoff calculator with given configuration.
auto calculate_base_delay(std::size_t attempt) const -> std::chrono::microseconds
Calculate base delay without jitter or capping.
@ delay
Delay processing (attempt later)
Core threading foundation of the thread system library.
Definition thread_impl.h:17
@ linear
Linearly increasing delay.
@ fixed
Fixed delay between retries.
@ exponential
Increasing boost over time.
steal_backoff_strategy
Backoff strategies for work-stealing operations.
@ adaptive_jitter
Exponential with random jitter for anti-correlation.
@ linear
Linear increase: delay = initial * (attempt + 1)
@ exponential
Exponential increase: delay = initial * 2^attempt.
@ fixed
Constant delay between steal attempts.
constexpr std::string_view to_string(log_level_v2 level) noexcept
Convert log_level_v2 to string representation.
Definition log_level.h:40
STL namespace.
Configuration for backoff behavior.
double jitter_factor
Jitter range as fraction of delay (0.0 - 1.0)
double multiplier
Multiplier for exponential backoff.