join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
clock.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_CLOCK_HPP
26#define JOIN_CORE_CLOCK_HPP
27
28// C++.
29#include <stdexcept>
30#include <chrono>
31#include <mutex>
32
33// C.
34#if defined(__x86_64__) || defined(__i386__)
35#include <cpuid.h>
36#endif
37#include <ctime>
38
39namespace join
40{
41 template <class ClockPolicy>
42 class BasicStats;
43
44#ifdef JOIN_HAS_IO_URING
45 struct IoDefaultPolicy;
46
47 template <typename IoPolicy>
48 class BasicProactor;
49
50 template <class ClockPolicy, class ProactorType = BasicProactor<IoDefaultPolicy>>
51 class BasicTimer;
52#else
53 class BasicProactor;
54
55 template <class ClockPolicy, class ProactorType = BasicProactor>
56 class BasicTimer;
57#endif
58
59 template <class ClockPolicy>
60 class SpinPolicy;
61
62 template <class ClockPolicy, class RunPolicy, size_t Capacity, uint64_t TickNs>
63 class BasicWheel;
64
68 struct NanoClock
69 {
70 using rep = int64_t;
71 using period = std::nano;
72 using duration = std::chrono::nanoseconds;
73 using time_point = std::chrono::time_point<NanoClock>;
74 static constexpr bool is_steady = true;
75 static time_point now () noexcept = delete;
76 };
77
82 {
83 public:
85
89 constexpr RealTime () noexcept = default;
90
95 static constexpr int type () noexcept
96 {
97 return CLOCK_REALTIME;
98 }
99 };
100
105 {
106 public:
107 using Duration = std::chrono::nanoseconds;
108 using TimePoint = std::chrono::time_point<NanoClock>;
111
112 template <size_t Capacity, uint64_t TickNs = 100>
114
118 constexpr Monotonic () noexcept = default;
119
124 static constexpr int type () noexcept
125 {
126 return CLOCK_MONOTONIC;
127 }
128
133 static TimePoint now () noexcept
134 {
135 timespec ts{};
136 ::clock_gettime (CLOCK_MONOTONIC, &ts);
137 return TimePoint (Duration (static_cast<int64_t> (ts.tv_sec) * 1'000'000'000LL + ts.tv_nsec));
138 }
139 };
140
145 {
146 public:
147 using Duration = std::chrono::nanoseconds;
148 using TimePoint = std::chrono::time_point<NanoClock>;
150
151 template <size_t Capacity, uint64_t TickNs = 100>
153
157 constexpr MonotonicRaw () noexcept = default;
158
163 static constexpr int type () noexcept
164 {
165 return CLOCK_MONOTONIC_RAW;
166 }
167
172 static TimePoint now () noexcept
173 {
174 timespec ts{};
175 ::clock_gettime (CLOCK_MONOTONIC_RAW, &ts);
176 return TimePoint (Duration (static_cast<int64_t> (ts.tv_sec) * 1'000'000'000LL + ts.tv_nsec));
177 }
178 };
179
183 class Rdtsc
184 {
185 public:
186 using Duration = std::chrono::nanoseconds;
187 using TimePoint = std::chrono::time_point<NanoClock>;
189
190 template <size_t Capacity, uint64_t TickNs = 100>
191 using Wheel = BasicWheel<Rdtsc, SpinPolicy<Rdtsc>, Capacity, TickNs>;
192
198 {
199#if defined(__x86_64__) || defined(__i386__)
200 if (!invariant ())
201 {
202 throw std::runtime_error ("cycle counter is not invariant"); // LCOV_EXCL_LINE
203 }
204#endif
205 calibrate ();
206 }
207
212 static bool invariant () noexcept
213 {
214#if defined(__x86_64__) || defined(__i386__)
215 unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
216 if (__get_cpuid_max (0x80000000, nullptr) < 0x80000007)
217 {
218 return false; // LCOV_EXCL_LINE
219 }
220 __cpuid (0x80000007, eax, ebx, ecx, edx);
221 return (edx & (1U << 8)) != 0;
222#else
223 return true;
224#endif
225 }
226
230 static void calibrate () noexcept
231 {
232 static std::once_flag flag;
233
234 std::call_once (flag, [] {
235#if defined(__aarch64__)
236 uint64_t freq;
237 __asm__ volatile ("mrs %0, cntfrq_el0" : "=r"(freq));
238 cycleToNs () = (1'000'000'000ULL << 32) / freq;
239#elif defined(__arm__)
240 uint32_t freq;
241 __asm__ volatile ("mrc p15, 0, %0, c14, c0, 0" : "=r"(freq));
242 cycleToNs () = (1'000'000'000ULL << 32) / freq;
243#else
244 timespec t0{}, t1{};
245 ::clock_gettime (CLOCK_MONOTONIC, &t0);
246 const uint64_t c0 = readCycles ();
247
248 const timespec delay{0, 100'000'000};
249 ::nanosleep (&delay, nullptr);
250
251 ::clock_gettime (CLOCK_MONOTONIC, &t1);
252 const uint64_t c1 = readCycles ();
253
254 const int64_t ns = (t1.tv_sec - t0.tv_sec) * 1'000'000'000LL + (t1.tv_nsec - t0.tv_nsec);
255 const uint64_t cycles = c1 - c0;
256
257 cycleToNs () = (static_cast<uint64_t> (ns) << 32) / cycles;
258#endif
259 });
260 }
261
266 static TimePoint now () noexcept
267 {
268#if defined(__SIZEOF_INT128__)
269 const uint64_t ns = static_cast<uint64_t> ((static_cast<__uint128_t> (readCycles ()) * cycleToNs ()) >> 32);
270#else
271 const uint64_t M32 = 0xFFFFFFFFU;
272
273 const uint64_t cycles = readCycles ();
274 const uint64_t multiplier = cycleToNs ();
275
276 const uint64_t ch = cycles >> 32;
277 const uint64_t cl = cycles & M32;
278 const uint64_t mh = multiplier >> 32;
279 const uint64_t ml = multiplier & M32;
280
281 const uint64_t ns = ((ch * mh) << 32) + ch * ml + cl * mh + ((cl * ml) >> 32);
282#endif
283 return TimePoint (Duration (static_cast<int64_t> (ns)));
284 }
285
286 private:
291 static uint64_t readCycles () noexcept
292 {
293#if defined(__x86_64__) || defined(__i386__)
294 uint32_t lo, hi;
295 __asm__ volatile ("rdtsc" : "=a"(lo), "=d"(hi) : : "memory");
296 return (static_cast<uint64_t> (hi) << 32) | lo;
297#elif defined(__aarch64__)
298 uint64_t val;
299 __asm__ volatile ("mrs %0, cntvct_el0" : "=r"(val) : : "memory");
300 return val;
301#elif defined(__arm__)
302 uint64_t val;
303 __asm__ volatile ("mrrc p15, 1, %Q0, %R0, c14" : "=r"(val) : : "memory");
304 return val;
305#else
306#error "Rdtsc: unsupported architecture"
307#endif
308 }
309
314 static uint64_t& cycleToNs () noexcept
315 {
316 static uint64_t value = 0;
317 return value;
318 }
319 };
320}
321
322#endif
lock-free, multi-producer-safe performance statistics collector.
Definition statistics.hpp:50
base timer class.
Definition timer.hpp:53
timing wheel.
Definition wheel.hpp:58
raw monotonic clock policy (raw hardware clock, may drift).
Definition clock.hpp:145
std::chrono::time_point< NanoClock > TimePoint
Definition clock.hpp:148
constexpr MonotonicRaw() noexcept=default
default constructor.
static TimePoint now() noexcept
read the current time.
Definition clock.hpp:172
std::chrono::nanoseconds Duration
Definition clock.hpp:147
monotonic clock policy (stable, adjusted, recommended default).
Definition clock.hpp:105
constexpr Monotonic() noexcept=default
default constructor.
std::chrono::nanoseconds Duration
Definition clock.hpp:107
static TimePoint now() noexcept
read the current time.
Definition clock.hpp:133
std::chrono::time_point< NanoClock > TimePoint
Definition clock.hpp:108
rdtsc clock policy (invariant TSC, CPU pinning, no NTP slewing).
Definition clock.hpp:184
static void calibrate() noexcept
calibrate against CLOCK_MONOTONIC, or CNTFRQ on ARM.
Definition clock.hpp:230
static bool invariant() noexcept
check if the cycle counter is invariant.
Definition clock.hpp:212
std::chrono::time_point< NanoClock > TimePoint
Definition clock.hpp:187
std::chrono::nanoseconds Duration
Definition clock.hpp:186
Rdtsc()
default constructor.
Definition clock.hpp:197
static TimePoint now() noexcept
read the current time, requires calibrate ().
Definition clock.hpp:266
real-time clock policy.
Definition clock.hpp:82
constexpr RealTime() noexcept=default
default constructor.
Definition acceptor.hpp:32
minimal clock type used as a type tag for time_point parameterization.
Definition clock.hpp:69
int64_t rep
Definition clock.hpp:70
static constexpr bool is_steady
Definition clock.hpp:74
std::nano period
Definition clock.hpp:71
static time_point now() noexcept=delete
std::chrono::time_point< NanoClock > time_point
Definition clock.hpp:73
std::chrono::nanoseconds duration
Definition clock.hpp:72