mirror of
https://github.com/Zygo/bees.git
synced 2025-05-17 13:25:45 +02:00
We need to replace nanosleeps with condition variables so that we can implement BeesContext::stop. Export the time calculation from sleep_for() into a new method called sleep_time(). If the thread executing RateLimiter::sleep_for() is interrupted, it will no longer be able to restart, as the sleep_time() method is destructive. This calls for further refactoring of sleep_time() into destructive and non-destructive parts; however, there are currently no users of sleep_for() which rely on being able to restart after being interrupted by a signal. Signed-off-by: Zygo Blaxell <bees@furryterror.org>
106 lines
2.6 KiB
C++
106 lines
2.6 KiB
C++
#ifndef CRUCIBLE_TIME_H
|
|
#define CRUCIBLE_TIME_H
|
|
|
|
#include "crucible/error.h"
|
|
|
|
#include <chrono>
|
|
#include <condition_variable>
|
|
#include <limits>
|
|
#include <mutex>
|
|
#include <ostream>
|
|
|
|
namespace crucible {
|
|
|
|
double nanosleep(double secs);
|
|
|
|
class Timer {
|
|
chrono::high_resolution_clock::time_point m_start;
|
|
|
|
public:
|
|
Timer();
|
|
double age() const;
|
|
chrono::high_resolution_clock::time_point get() const;
|
|
double report(int precision = 1000) const;
|
|
void reset();
|
|
double lap();
|
|
bool operator<(double d) const;
|
|
bool operator>(double d) const;
|
|
};
|
|
|
|
ostream &operator<<(ostream &os, const Timer &t);
|
|
|
|
class RateLimiter {
|
|
Timer m_timer;
|
|
double m_rate;
|
|
double m_burst;
|
|
double m_tokens = 0.0;
|
|
mutex m_mutex;
|
|
|
|
void update_tokens();
|
|
RateLimiter() = delete;
|
|
public:
|
|
RateLimiter(double rate, double burst);
|
|
RateLimiter(double rate);
|
|
void sleep_for(double cost = 1.0);
|
|
double sleep_time(double cost = 1.0);
|
|
bool is_ready();
|
|
void borrow(double cost = 1.0);
|
|
};
|
|
|
|
class RateEstimator {
|
|
mutable mutex m_mutex;
|
|
mutable condition_variable m_condvar;
|
|
Timer m_timer;
|
|
double m_num = 0.0;
|
|
double m_den = 0.0;
|
|
uint64_t m_last_count = numeric_limits<uint64_t>::max();
|
|
Timer m_last_update;
|
|
const double m_decay = 0.99;
|
|
Timer m_last_decay;
|
|
double m_min_delay;
|
|
double m_max_delay;
|
|
|
|
chrono::duration<double> duration_unlocked(uint64_t relative_count) const;
|
|
chrono::high_resolution_clock::time_point time_point_unlocked(uint64_t absolute_count) const;
|
|
double rate_unlocked() const;
|
|
pair<double, double> ratio_unlocked() const;
|
|
void update_unlocked(uint64_t new_count);
|
|
public:
|
|
RateEstimator(double min_delay = 1, double max_delay = 3600);
|
|
|
|
// Block until count reached
|
|
void wait_for(uint64_t new_count_relative) const;
|
|
void wait_until(uint64_t new_count_absolute) const;
|
|
|
|
// Computed rates and ratios
|
|
double rate() const;
|
|
pair<double, double> ratio() const;
|
|
|
|
// Inspect raw num/den
|
|
pair<double, double> raw() const;
|
|
|
|
// Write count
|
|
void update(uint64_t new_count);
|
|
|
|
// Ignore counts that go backwards
|
|
void update_monotonic(uint64_t new_count);
|
|
|
|
// Read count
|
|
uint64_t count() const;
|
|
|
|
// Convert counts to chrono types
|
|
chrono::high_resolution_clock::time_point time_point(uint64_t absolute_count) const;
|
|
chrono::duration<double> duration(uint64_t relative_count) const;
|
|
|
|
// Polling delay until count reached (limited by min/max delay)
|
|
double seconds_for(uint64_t new_count_relative) const;
|
|
double seconds_until(uint64_t new_count_absolute) const;
|
|
};
|
|
|
|
ostream &
|
|
operator<<(ostream &os, const RateEstimator &re);
|
|
|
|
}
|
|
|
|
#endif // CRUCIBLE_TIME_H
|