1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
#include "Time.hpp"
#define chr std::chrono
#define TIMESPEC_NSEC_PER_SEC 1000000000L
using s_ns = std::pair<uint64_t, uint64_t>;
static s_ns timediff(const s_ns& a, const s_ns& b) {
s_ns d;
d.first = a.first - b.first;
if (a.second >= b.second)
d.second = a.second - b.second;
else {
d.second = (TIMESPEC_NSEC_PER_SEC + a.second) - b.second;
d.first -= 1;
}
return d;
}
static s_ns timeadd(const s_ns& a, const s_ns& b) {
s_ns d;
d.first = a.first + b.first;
if (a.second + b.second >= TIMESPEC_NSEC_PER_SEC) {
d.second = a.second + b.second - TIMESPEC_NSEC_PER_SEC;
d.first += 1;
} else
d.second = a.second + b.second;
return d;
}
Time::steady_tp Time::steadyNow() {
return chr::steady_clock::now();
}
Time::system_tp Time::systemNow() {
return chr::system_clock::now();
}
uint64_t Time::millis(const steady_tp& tp) {
return chr::duration_cast<chr::milliseconds>(tp.time_since_epoch()).count();
}
s_ns Time::secNsec(const steady_tp& tp) {
const uint64_t sec = chr::duration_cast<chr::seconds>(tp.time_since_epoch()).count();
const auto nsecdur = tp - chr::steady_clock::time_point(chr::seconds(sec));
return {sec, chr::duration_cast<chr::nanoseconds>(nsecdur).count()};
}
uint64_t Time::millis(const system_tp& tp) {
return chr::duration_cast<chr::milliseconds>(tp.time_since_epoch()).count();
}
s_ns Time::secNsec(const system_tp& tp) {
const uint64_t sec = chr::duration_cast<chr::seconds>(tp.time_since_epoch()).count();
const auto nsecdur = tp - chr::system_clock::time_point(chr::seconds(sec));
return {sec, chr::duration_cast<chr::nanoseconds>(nsecdur).count()};
}
// TODO: this is a mess, but C++ doesn't define what steady_clock is.
// At least on Linux, system_clock == CLOCK_REALTIME
// and steady_clock == CLOCK_MONOTONIC,
// or at least it seems so with gcc and gcc's stl.
// but, since we can't *ever* be sure, we have to guess.
// In general, this may shift the time around by a couple hundred ns. Doesn't matter, realistically.
Time::steady_tp Time::fromTimespec(const timespec* ts) {
timespec mono{}, real{};
clock_gettime(CLOCK_MONOTONIC, &mono);
clock_gettime(CLOCK_REALTIME, &real);
auto now = Time::steadyNow();
auto nowSys = Time::systemNow();
s_ns stdSteady, stdReal;
stdSteady = Time::secNsec(now);
stdReal = Time::secNsec(nowSys);
// timespec difference, REAL - MONO
s_ns diff;
diff.first = real.tv_sec - mono.tv_sec;
if (real.tv_nsec >= mono.tv_nsec)
diff.second = real.tv_nsec - mono.tv_nsec;
else {
diff.second = TIMESPEC_NSEC_PER_SEC + real.tv_nsec - mono.tv_nsec;
diff.first -= 1;
}
// STD difference, REAL - MONO
s_ns diff2 = timediff(stdReal, stdSteady);
s_ns diffFinal;
s_ns monotime = {ts->tv_sec, ts->tv_nsec};
if (diff.first >= diff2.first || (diff.first == diff2.first && diff.second >= diff2.second))
diffFinal = timediff(diff, diff2);
else
diffFinal = timediff(diff2, diff);
auto sum = timeadd(monotime, diffFinal);
return chr::steady_clock::time_point(std::chrono::seconds(sum.first)) + chr::nanoseconds(sum.second);
}
struct timespec Time::toTimespec(const steady_tp& tp) {
timespec mono{}, real{};
clock_gettime(CLOCK_MONOTONIC, &mono);
clock_gettime(CLOCK_REALTIME, &real);
Time::steady_tp now = Time::steadyNow();
Time::system_tp nowSys = Time::systemNow();
s_ns stdSteady, stdReal;
stdSteady = Time::secNsec(now);
stdReal = Time::secNsec(nowSys);
// timespec difference, REAL - MONO
s_ns diff;
diff.first = real.tv_sec - mono.tv_sec;
if (real.tv_nsec >= mono.tv_nsec)
diff.second = real.tv_nsec - mono.tv_nsec;
else {
diff.second = TIMESPEC_NSEC_PER_SEC + real.tv_nsec - mono.tv_nsec;
diff.first -= 1;
}
// STD difference, REAL - MONO
s_ns diff2 = timediff(stdReal, stdSteady);
s_ns diffFinal;
s_ns tpTime = secNsec(tp);
if (diff.first >= diff2.first || (diff.first == diff2.first && diff.second >= diff2.second))
diffFinal = timediff(diff, diff2);
else
diffFinal = timediff(diff2, diff);
auto sum = timeadd(tpTime, diffFinal);
return timespec{.tv_sec = sum.first, .tv_nsec = sum.second};
}
Time::steady_dur Time::till(const timespec& ts) {
timespec mono{};
clock_gettime(CLOCK_MONOTONIC, &mono);
const auto delay = (ts.tv_sec - mono.tv_sec) * 1000000000 + (ts.tv_nsec - mono.tv_nsec);
return std::chrono::nanoseconds(delay);
}
|