2 * Copyright (C) 2010 Pierre-Marc Fournier
3 * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 * SPDX-License-Identifier: GPL-2.0-only
10 #include "ust-clock-class.hpp"
12 #include <common/time.hpp>
13 #include <common/exception.hpp>
15 #include <lttng/ust-clock.h>
17 #define CLOCK_OFFSET_SAMPLE_COUNT 10
19 namespace lst
= lttng::sessiond::trace
;
22 struct offset_sample
{
23 /* correlation offset */
24 lst::clock_class::scycles_t offset
;
26 lst::clock_class::cycles_t measure_delta
;
29 lst::clock_class::cycles_t
sample_clock_read64()
31 lttng_ust_clock_read64_function read64_cb
;
33 if (lttng_ust_trace_clock_get_read64_cb(&read64_cb
)) {
34 LTTNG_THROW_ERROR("Failed to get clock sample callback");
40 lst::clock_class::cycles_t
sample_clock_frequency()
42 lttng_ust_clock_freq_function get_freq_cb
;
44 if (lttng_ust_trace_clock_get_freq_cb(&get_freq_cb
)) {
45 LTTNG_THROW_ERROR("Failed to get clock frequency callback");
51 nonstd::optional
<lttng_uuid
> sample_clock_uuid()
53 lttng_ust_clock_uuid_function get_uuid_cb
;
55 if (lttng_ust_trace_clock_get_uuid_cb(&get_uuid_cb
)) {
56 return nonstd::nullopt
;
59 char uuid_str
[LTTNG_UUID_STR_LEN
];
60 if (get_uuid_cb(uuid_str
)) {
61 return nonstd::nullopt
;
65 if (lttng_uuid_from_str(uuid_str
, uuid
)) {
66 LTTNG_THROW_ERROR("Failed to parse UUID from string");
69 return nonstd::optional
<lttng_uuid
>{uuid
};
72 const char *sample_clock_name()
74 lttng_ust_clock_name_function get_name_cb
;
76 if (lttng_ust_trace_clock_get_name_cb(&get_name_cb
)) {
77 LTTNG_THROW_ERROR("Failed to get clock name callback");
80 const auto name
= get_name_cb();
82 LTTNG_THROW_ERROR("Invalid clock name returned by LTTng-UST `lttng_ust_clock_name_function`");
88 const char *sample_clock_description()
90 lttng_ust_clock_description_function get_description_cb
;
92 if (lttng_ust_trace_clock_get_description_cb(&get_description_cb
)) {
93 LTTNG_THROW_ERROR("Failed to get clock description callback");
96 const auto description
= get_description_cb();
98 LTTNG_THROW_ERROR("Invalid clock description returned by LTTng-UST `lttng_ust_clock_description_function`");
105 * The offset between monotonic and realtime clock can be negative if
106 * the system sets the REALTIME clock to 0 after boot.
108 void measure_single_clock_offset(struct offset_sample
*sample
)
110 lst::clock_class::cycles_t monotonic_avg
, monotonic
[2], measure_delta
,
112 const auto tcf
= sample_clock_frequency();
113 struct timespec rts
= { 0, 0 };
115 monotonic
[0] = sample_clock_read64();
116 if (lttng_clock_gettime(CLOCK_REALTIME
, &rts
)) {
117 LTTNG_THROW_POSIX("Failed to sample time from clock", errno
);
120 monotonic
[1] = sample_clock_read64();
121 measure_delta
= monotonic
[1] - monotonic
[0];
122 if (measure_delta
> sample
->measure_delta
) {
124 * Discard value if it took longer to read than the best
130 monotonic_avg
= (monotonic
[0] + monotonic
[1]) >> 1;
131 realtime
= (lst::clock_class::cycles_t
) rts
.tv_sec
* tcf
;
132 if (tcf
== NSEC_PER_SEC
) {
133 realtime
+= rts
.tv_nsec
;
135 realtime
+= (lst::clock_class::cycles_t
) rts
.tv_nsec
* tcf
/
139 sample
->offset
= (lst::clock_class::scycles_t
) realtime
- monotonic_avg
;
140 sample
->measure_delta
= measure_delta
;
144 * Approximation of NTP time of day to clock monotonic correlation,
145 * taken at start of trace. Keep the measurement that took the less time
146 * to complete, thus removing imprecision caused by preemption.
147 * May return a negative offset.
149 lst::clock_class::scycles_t
measure_clock_offset(void)
151 struct offset_sample offset_best_sample
= {
153 .measure_delta
= UINT64_MAX
,
156 for (auto i
= 0; i
< CLOCK_OFFSET_SAMPLE_COUNT
; i
++) {
157 measure_single_clock_offset(&offset_best_sample
);
160 return offset_best_sample
.offset
;
164 lttng::sessiond::ust::clock_class::clock_class() :
165 lst::clock_class(sample_clock_name(),
166 sample_clock_description(),
168 measure_clock_offset(),
169 sample_clock_frequency())