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.hpp"
12 #include <common/time.hpp>
13 #include <common/exception.hpp>
15 #define CLOCK_OFFSET_SAMPLE_COUNT 10
18 struct offset_sample
{
19 /* correlation offset */
20 lttng::ust::clock_attributes_sample::scycles_t offset
;
22 lttng::ust::clock_attributes_sample::cycles_t measure_delta
;
25 lttng::ust::clock_attributes_sample::cycles_t
sample_clock_read64()
27 lttng_ust_clock_read64_function read64_cb
;
29 if (lttng_ust_trace_clock_get_read64_cb(&read64_cb
)) {
30 LTTNG_THROW_ERROR("Failed to get clock sample callback");
36 lttng::ust::clock_attributes_sample::cycles_t
sample_clock_frequency()
38 lttng_ust_clock_freq_function get_freq_cb
;
40 if (lttng_ust_trace_clock_get_freq_cb(&get_freq_cb
)) {
41 LTTNG_THROW_ERROR("Failed to get clock frequency callback");
47 nonstd::optional
<lttng_uuid
> sample_clock_uuid()
49 lttng_ust_clock_uuid_function get_uuid_cb
;
51 if (lttng_ust_trace_clock_get_uuid_cb(&get_uuid_cb
)) {
52 return nonstd::nullopt
;
55 char uuid_str
[LTTNG_UUID_STR_LEN
];
56 if (get_uuid_cb(uuid_str
)) {
57 return nonstd::nullopt
;
61 if (lttng_uuid_from_str(uuid_str
, uuid
)) {
62 LTTNG_THROW_ERROR("Failed to parse UUID from string");
65 return nonstd::optional
<lttng_uuid
>{uuid
};
68 const char *sample_clock_name()
70 lttng_ust_clock_name_function get_name_cb
;
72 if (lttng_ust_trace_clock_get_name_cb(&get_name_cb
)) {
73 LTTNG_THROW_ERROR("Failed to get clock name callback");
76 const auto name
= get_name_cb();
78 LTTNG_THROW_ERROR("Invalid clock name returned by LTTng-UST `lttng_ust_clock_name_function`");
84 const char *sample_clock_description()
86 lttng_ust_clock_description_function get_description_cb
;
88 if (lttng_ust_trace_clock_get_description_cb(&get_description_cb
)) {
89 LTTNG_THROW_ERROR("Failed to get clock description callback");
92 const auto description
= get_description_cb();
94 LTTNG_THROW_ERROR("Invalid clock description returned by LTTng-UST `lttng_ust_clock_description_function`");
101 * The offset between monotonic and realtime clock can be negative if
102 * the system sets the REALTIME clock to 0 after boot.
104 void measure_single_clock_offset(struct offset_sample
*sample
)
106 lttng::ust::clock_attributes_sample::cycles_t monotonic_avg
, monotonic
[2], measure_delta
,
108 const auto tcf
= sample_clock_frequency();
109 struct timespec rts
= { 0, 0 };
111 monotonic
[0] = sample_clock_read64();
112 if (lttng_clock_gettime(CLOCK_REALTIME
, &rts
)) {
113 LTTNG_THROW_POSIX("Failed to sample time from clock", errno
);
116 monotonic
[1] = sample_clock_read64();
117 measure_delta
= monotonic
[1] - monotonic
[0];
118 if (measure_delta
> sample
->measure_delta
) {
120 * Discard value if it took longer to read than the best
126 monotonic_avg
= (monotonic
[0] + monotonic
[1]) >> 1;
127 realtime
= (lttng::ust::clock_attributes_sample::cycles_t
) rts
.tv_sec
* tcf
;
128 if (tcf
== NSEC_PER_SEC
) {
129 realtime
+= rts
.tv_nsec
;
131 realtime
+= (lttng::ust::clock_attributes_sample::cycles_t
) rts
.tv_nsec
* tcf
/
135 sample
->offset
= (lttng::ust::clock_attributes_sample::scycles_t
) realtime
- monotonic_avg
;
136 sample
->measure_delta
= measure_delta
;
140 * Approximation of NTP time of day to clock monotonic correlation,
141 * taken at start of trace. Keep the measurement that took the less time
142 * to complete, thus removing imprecision caused by preemption.
143 * May return a negative offset.
145 lttng::ust::clock_attributes_sample::scycles_t
measure_clock_offset(void)
147 struct offset_sample offset_best_sample
= {
149 .measure_delta
= UINT64_MAX
,
152 for (auto i
= 0; i
< CLOCK_OFFSET_SAMPLE_COUNT
; i
++) {
153 measure_single_clock_offset(&offset_best_sample
);
156 return offset_best_sample
.offset
;
160 lttng::ust::clock_attributes_sample::clock_attributes_sample() :
161 _name
{sample_clock_name()},
162 _description
{sample_clock_description()},
163 _uuid
{sample_clock_uuid()},
164 _offset
{measure_clock_offset()},
165 _frequency
{sample_clock_frequency()}