10#include "fastmm/core/config_macros.hpp"
11#include "fastmm/core/seqlock.hpp"
27 [[nodiscard]]
constexpr std::int64_t
millis() const noexcept {
return ns / 1'000'000; }
28 [[nodiscard]]
constexpr std::int64_t
micros() const noexcept {
return ns / 1'000; }
33[[nodiscard]]
constexpr Duration
microseconds(std::int64_t v)
noexcept {
36[[nodiscard]]
constexpr Duration
milliseconds(std::int64_t v)
noexcept {
37 return {v * 1'000'000};
39[[nodiscard]]
constexpr Duration
seconds(std::int64_t v)
noexcept {
40 return {v * 1'000'000'000};
53 [[nodiscard]]
constexpr bool valid() const noexcept {
return ns != 0; }
54 [[nodiscard]]
static constexpr Timestamp
max() noexcept {
return {INT64_MAX}; }
68FASTMM_FORCE_INLINE Cycles
rdtsc() noexcept {
69 return Cycles{__rdtsc()};
73[[nodiscard]] Timestamp
wall_now() noexcept;
87struct TscCalibration {
88 std::uint64_t
tsc0 = 0;
100 std::uint64_t cycles)
noexcept {
101 return static_cast<std::uint64_t
>((
static_cast<Uint128
>(cycles) * c.ns_per_cycle_q32) >> 32);
106struct ClockReadings {
107 std::uint64_t (*
tsc)()
noexcept =
nullptr;
123 std::uint64_t tsc = 0;
124 std::int64_t realtime_ns = 0;
125 std::int64_t raw_ns = 0;
157 [[nodiscard]]
TscAnchor sample() const noexcept;
189[[nodiscard]] FASTMM_FORCE_INLINE std::int64_t
tsc_to_ns(
const TscCalibration& c,
190 std::uint64_t tsc)
noexcept {
191 const auto dc =
static_cast<std::int64_t
>(tsc - c.tsc0);
192 return c.
ns0 +
static_cast<std::int64_t
>(
193 (
static_cast<Int128
>(dc) *
static_cast<Int128
>(c.ns_per_cycle_q32)) >> 32);
223 seen_version_ = kNoVersion;
234 if (FASTMM_LIKELY(src_ ==
nullptr || src_->version() == seen_version_))
return TscRefresh::None;
235 return refresh_slow();
246 if (!fresh.use_tsc || fresh.ns_per_cycle_q32 == 0) {
255 const std::int64_t old_ns =
tsc_to_ns(calib_, at.v);
256 last_offset_ns_ =
tsc_to_ns(fresh, at.v) - old_ns;
257 if (last_offset_ns_ > step_threshold_ns_ || last_offset_ns_ < -step_threshold_ns_) {
262 std::uint64_t rate = fresh.ns_per_cycle_q32;
264 if (slew_horizon_ns_ > 0 && last_offset_ns_ != 0) {
265 const Int128 max_adj =
static_cast<Int128
>(rate) *
kMaxSlewPpm / 1'000'000;
266 Int128 adj =
static_cast<Int128
>(last_offset_ns_) *
static_cast<Int128
>(rate) /
267 static_cast<Int128
>(slew_horizon_ns_);
268 if (adj > max_adj) adj = max_adj;
269 if (adj < -max_adj) adj = -max_adj;
270 rate =
static_cast<std::uint64_t
>(
static_cast<Int128
>(rate) + adj);
271 slew_ppb_ =
static_cast<std::int64_t
>(adj * 1'000'000'000 /
272 static_cast<Int128
>(fresh.ns_per_cycle_q32));
277 calib_.
ghz = fresh.ghz;
283 [[nodiscard]] std::uint64_t
steps() const noexcept {
return steps_; }
284 [[nodiscard]] std::uint64_t
reanchors() const noexcept {
return reanchors_; }
286 [[nodiscard]] std::int64_t
last_offset_ns() const noexcept {
return last_offset_ns_; }
290 [[nodiscard]] std::int64_t
slew_ppb() const noexcept {
return slew_ppb_; }
302 [[nodiscard]] FASTMM_FORCE_INLINE Timestamp
to_timestamp(Cycles c)
const noexcept {
306 [[nodiscard]] FASTMM_FORCE_INLINE std::int64_t
cycles_to_ns(std::uint64_t dc)
const noexcept {
307 if (FASTMM_LIKELY(calib_.
has_rate()))
309 return static_cast<std::int64_t
>(dc);
313 static constexpr std::uint32_t kNoVersion = UINT32_MAX;
315 FASTMM_NOINLINE
TscRefresh refresh_slow() noexcept {
317 std::uint32_t version = 0;
319 seen_version_ = version;
323 TscCalibration calib_{};
324 const Seqlocked<TscCalibration>* src_ =
nullptr;
325 std::uint32_t seen_version_ = kNoVersion;
327 std::int64_t slew_horizon_ns_ =
329 std::int64_t slew_ppb_ = 0;
330 std::int64_t last_offset_ns_ = 0;
331 std::uint64_t steps_ = 0;
332 std::uint64_t reanchors_ = 0;
342 return Cycles{
static_cast<std::uint64_t
>(now_.
ns)};
345 return Timestamp{
static_cast<std::int64_t
>(c.v)};
347 [[nodiscard]] std::int64_t
cycles_to_ns(std::uint64_t dc)
const noexcept {
348 return static_cast<std::int64_t
>(dc);
351 FASTMM_ASSERT(t >= now_);
363concept ClockLike =
requires(
const C& c, Cycles cy, std::uint64_t dc) {
364 { c.now() }
noexcept -> std::same_as<Timestamp>;
365 { c.cycles() }
noexcept -> std::same_as<Cycles>;
366 { c.to_timestamp(cy) }
noexcept -> std::same_as<Timestamp>;
367 { c.cycles_to_ns(dc) }
noexcept -> std::same_as<std::int64_t>;
369static_assert(ClockLike<TscClock> && ClockLike<SimClock>);
Deterministic clock for sim/backtest/replay. 1 cycle == 1 ns.
Definition time.hpp:338
SimClock() noexcept=default
Timestamp to_timestamp(Cycles c) const noexcept
Definition time.hpp:346
std::int64_t cycles_to_ns(std::uint64_t dc) const noexcept
Definition time.hpp:349
void advance(Duration d) noexcept
Definition time.hpp:356
void jump(Timestamp t) noexcept
Replay only: follows a recorded engine clock, which may have stepped backwards.
Definition time.hpp:358
Cycles cycles() const noexcept
Definition time.hpp:343
void set(Timestamp t) noexcept
Definition time.hpp:352
Timestamp now() const noexcept
Definition time.hpp:342
Long-baseline TSC calibration for the calibrator (control) thread.
Definition time.hpp:148
TscRecalibration update() noexcept
TscCalibration start(Duration window=milliseconds(50)) noexcept
const TscCalibration & current() const noexcept
Definition time.hpp:156
static constexpr Duration kMinBaseline
Definition time.hpp:150
Periodic recalibration (see docs/explanation/architecture.md, "Clock calibration"): a calibrator thre...
Definition time.hpp:202
static constexpr std::int64_t kMaxSlewPpm
Upper bound on the rate adjustment used to absorb an offset (a clock servo, not a jump).
Definition time.hpp:207
void attach_calibration_source(const Seqlocked< TscCalibration > *src, Duration step_threshold=kDefaultStepThreshold, Duration slew_horizon=kDefaultSlewHorizon) noexcept
Subscribes to published calibrations.
Definition time.hpp:221
void set_calibration(const TscCalibration &c) noexcept
Definition time.hpp:214
const TscCalibration & calibration() const noexcept
Definition time.hpp:215
std::int64_t last_offset_ns() const noexcept
fresh - old at the last re-anchor or step, in ns.
Definition time.hpp:288
FASTMM_FORCE_INLINE std::int64_t cycles_to_ns(std::uint64_t dc) const noexcept
Definition time.hpp:308
std::uint64_t reanchors() const noexcept
Definition time.hpp:286
Duration slew_horizon() const noexcept
Definition time.hpp:290
static constexpr Duration kDefaultStepThreshold
Definition time.hpp:204
std::int64_t slew_ppb() const noexcept
Rate correction applied at the last re-anchor, in parts per billion of the fresh rate.
Definition time.hpp:292
TscClock() noexcept=default
FASTMM_FORCE_INLINE Timestamp to_timestamp(Cycles c) const noexcept
Definition time.hpp:304
Duration step_threshold() const noexcept
Definition time.hpp:289
FASTMM_FORCE_INLINE TscRefresh refresh() noexcept
Cheap when nothing changed (one atomic load); copies and re-anchors on a new version.
Definition time.hpp:235
FASTMM_FORCE_INLINE Cycles cycles() const noexcept
TSC cycles whenever the rate is known (also without an invariant TSC), so that they share a time base...
Definition time.hpp:300
void calibrate(Duration window=milliseconds(50)) noexcept
Blocking; call once at startup, before the clock is shared with another thread.
Definition time.hpp:213
static constexpr Duration kDefaultSlewHorizon
Definition time.hpp:205
std::uint64_t steps() const noexcept
Diagnostics (owner thread, or after the owner stopped).
Definition time.hpp:285
FASTMM_FORCE_INLINE Timestamp now() const noexcept
Definition time.hpp:294
const Seqlocked< TscCalibration > * calibration_source() const noexcept
Definition time.hpp:229
TscRefresh reanchor(const TscCalibration &fresh, Cycles at) noexcept
Switches to fresh at TSC reading at (refresh() passes rdtsc()).
Definition time.hpp:247
Definition strategy.hpp:16
constexpr Duration milliseconds(std::int64_t v) noexcept
Definition time.hpp:38
constexpr Duration nanoseconds(std::int64_t v) noexcept
Definition time.hpp:32
ClockReadings system_clock_readings() noexcept
Timestamp wall_now() noexcept
CLOCK_REALTIME via vDSO (~20 ns). Implemented in src/core/time.cpp.
FASTMM_FORCE_INLINE std::uint64_t tsc_interval_ns(const TscCalibration &c, std::uint64_t cycles) noexcept
A TSC cycle interval in ns; 0 without a rate.
Definition time.hpp:101
bool has_invariant_tsc() noexcept
Definition time.hpp:85
FASTMM_FORCE_INLINE Cycles rdtscp() noexcept
Serialising read (rdtscp) is what latency hops want: it waits for prior loads to retire.
Definition time.hpp:66
FASTMM_FORCE_INLINE Cycles rdtsc() noexcept
Definition time.hpp:70
TscKind tsc_kind() noexcept
FASTMM_FORCE_INLINE std::int64_t tsc_to_ns(const TscCalibration &c, std::uint64_t tsc) noexcept
TSC reading -> wall ns under c.
Definition time.hpp:191
Timestamp steady_now() noexcept
TscRefresh
Outcome of TscClock::refresh() / reanchor().
Definition time.hpp:166
@ Reanchored
continuous: same time at the refresh point, new rate from there on
@ Stepped
old mapping disagreed with the measurement by more than the threshold
@ None
no new calibration published (the common case)
@ Adopted
the clock had no TSC mapping yet: took the published one as is
@ Rejected
the published calibration is unusable (no TSC); kept the current mapping
TscCalibration calibrate_tsc(Duration window=milliseconds(50)) noexcept
Startup calibration (spins for window): TscCalibrator::start(), so the rate is measured against CLOCK...
constexpr std::string_view to_string(ParamType t) noexcept
Definition params.hpp:63
TscKind
What /proc/cpuinfo says about the TSC (cached after the first call): Invariant constant_tsc + nonstop...
Definition time.hpp:83
constexpr Duration seconds(std::int64_t v) noexcept
Definition time.hpp:41
constexpr Duration microseconds(std::int64_t v) noexcept
Definition time.hpp:35
Clock readings used by TscCalibrator.
Definition time.hpp:108
bool check_invariant_tsc
false for injected clocks
Definition time.hpp:112
TscKind assumed_kind
injected clocks (check_invariant_tsc false)
Definition time.hpp:113
std::int64_t(* realtime_ns)() noexcept
Definition time.hpp:110
std::int64_t(* monotonic_raw_ns)() noexcept
Definition time.hpp:111
std::uint64_t(* tsc)() noexcept
Definition time.hpp:109
constexpr auto operator<=>(const Cycles &) const noexcept=default
friend constexpr std::uint64_t operator-(Cycles a, Cycles b) noexcept
Definition time.hpp:62
std::uint64_t v
Definition time.hpp:60
friend constexpr Duration operator-(Duration a, Duration b) noexcept
Definition time.hpp:26
constexpr std::int64_t micros() const noexcept
Definition time.hpp:30
std::int64_t ns
Definition time.hpp:23
friend constexpr Duration operator+(Duration a, Duration b) noexcept
Definition time.hpp:25
friend constexpr Duration operator*(Duration a, std::int64_t k) noexcept
Definition time.hpp:27
constexpr std::int64_t millis() const noexcept
Definition time.hpp:29
constexpr auto operator<=>(const Duration &) const noexcept=default
friend constexpr Duration operator/(Duration a, std::int64_t k) noexcept
Definition time.hpp:28
constexpr Timestamp & operator+=(Duration d) noexcept
Definition time.hpp:51
constexpr auto operator<=>(const Timestamp &) const noexcept=default
friend constexpr Timestamp operator+(Timestamp a, Duration d) noexcept
Definition time.hpp:49
friend constexpr Duration operator-(Timestamp a, Timestamp b) noexcept
Definition time.hpp:48
std::int64_t ns
Definition time.hpp:46
static constexpr Timestamp max() noexcept
Definition time.hpp:56
constexpr bool valid() const noexcept
Definition time.hpp:55
One simultaneous reading of the three clocks (the TSC is the midpoint of a tight bracket).
Definition time.hpp:124
std::uint64_t tsc0
TSC reading at the anchor.
Definition time.hpp:90
double ghz
diagnostics only
Definition time.hpp:93
std::uint64_t ns_per_cycle_q32
32.32 fixed point; 0: no TSC rate
Definition time.hpp:92
std::int64_t ns0
wall time at the anchor
Definition time.hpp:91
constexpr bool has_rate() const noexcept
Definition time.hpp:97
bool use_tsc
Wall time from the TSC.
Definition time.hpp:96
bool ok
false: no TSC, or the baseline since the previous anchor is too short
Definition time.hpp:136
std::int64_t host_step_ns
realtime change minus monotonic-raw change over the baseline
Definition time.hpp:133
double elapsed_s
baseline length
Definition time.hpp:134
TscCalibration calibration
to publish
Definition time.hpp:131
std::int64_t drift_ns
CLOCK_REALTIME at the new anchor minus the old mapping's value.
Definition time.hpp:132
double rate_change_ppm
Definition time.hpp:135