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/exception.hpp>
13 #include <common/time.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();
83 "Invalid clock name returned by LTTng-UST `lttng_ust_clock_name_function`");
89 const char *sample_clock_description()
91 lttng_ust_clock_description_function get_description_cb
;
93 if (lttng_ust_trace_clock_get_description_cb(&get_description_cb
)) {
94 LTTNG_THROW_ERROR("Failed to get clock description callback");
97 const auto description
= get_description_cb();
100 "Invalid clock description returned by LTTng-UST `lttng_ust_clock_description_function`");
107 * The offset between monotonic and realtime clock can be negative if
108 * the system sets the REALTIME clock to 0 after boot.
110 void measure_single_clock_offset(struct offset_sample
*sample
)
112 lst::clock_class::cycles_t monotonic_avg
, monotonic
[2], measure_delta
, realtime
;
113 const auto tcf
= sample_clock_frequency();
114 struct timespec rts
= { 0, 0 };
116 monotonic
[0] = sample_clock_read64();
117 if (lttng_clock_gettime(CLOCK_REALTIME
, &rts
)) {
118 LTTNG_THROW_POSIX("Failed to sample time from clock", errno
);
121 monotonic
[1] = sample_clock_read64();
122 measure_delta
= monotonic
[1] - monotonic
[0];
123 if (measure_delta
> sample
->measure_delta
) {
125 * Discard value if it took longer to read than the best
131 monotonic_avg
= (monotonic
[0] + monotonic
[1]) >> 1;
132 realtime
= (lst::clock_class::cycles_t
) rts
.tv_sec
* tcf
;
133 if (tcf
== NSEC_PER_SEC
) {
134 realtime
+= rts
.tv_nsec
;
136 realtime
+= (lst::clock_class::cycles_t
) rts
.tv_nsec
* tcf
/ NSEC_PER_SEC
;
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()
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())