sessiond: Move trace_ust_clock to a clock_attributes_sample class
[lttng-tools.git] / src / bin / lttng-sessiond / ust-clock.cpp
1 /*
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>
5 *
6 * SPDX-License-Identifier: GPL-2.0-only
7 *
8 */
9
10 #include "ust-clock.hpp"
11
12 #include <common/time.hpp>
13 #include <common/exception.hpp>
14
15 #define CLOCK_OFFSET_SAMPLE_COUNT 10
16
17 namespace {
18 struct offset_sample {
19 /* correlation offset */
20 lttng::ust::clock_attributes_sample::scycles_t offset;
21 /* lower is better */
22 lttng::ust::clock_attributes_sample::cycles_t measure_delta;
23 };
24
25 lttng::ust::clock_attributes_sample::cycles_t sample_clock_read64()
26 {
27 lttng_ust_clock_read64_function read64_cb;
28
29 if (lttng_ust_trace_clock_get_read64_cb(&read64_cb)) {
30 LTTNG_THROW_ERROR("Failed to get clock sample callback");
31 }
32
33 return read64_cb();
34 }
35
36 lttng::ust::clock_attributes_sample::cycles_t sample_clock_frequency()
37 {
38 lttng_ust_clock_freq_function get_freq_cb;
39
40 if (lttng_ust_trace_clock_get_freq_cb(&get_freq_cb)) {
41 LTTNG_THROW_ERROR("Failed to get clock frequency callback");
42 }
43
44 return get_freq_cb();
45 }
46
47 nonstd::optional<lttng_uuid> sample_clock_uuid()
48 {
49 lttng_ust_clock_uuid_function get_uuid_cb;
50
51 if (lttng_ust_trace_clock_get_uuid_cb(&get_uuid_cb)) {
52 return nonstd::nullopt;
53 }
54
55 char uuid_str[LTTNG_UUID_STR_LEN];
56 if (get_uuid_cb(uuid_str)) {
57 return nonstd::nullopt;
58 }
59
60 lttng_uuid uuid;
61 if (lttng_uuid_from_str(uuid_str, uuid)) {
62 LTTNG_THROW_ERROR("Failed to parse UUID from string");
63 }
64
65 return nonstd::optional<lttng_uuid>{uuid};
66 }
67
68 const char *sample_clock_name()
69 {
70 lttng_ust_clock_name_function get_name_cb;
71
72 if (lttng_ust_trace_clock_get_name_cb(&get_name_cb)) {
73 LTTNG_THROW_ERROR("Failed to get clock name callback");
74 }
75
76 const auto name = get_name_cb();
77 if (!name) {
78 LTTNG_THROW_ERROR("Invalid clock name returned by LTTng-UST `lttng_ust_clock_name_function`");
79 }
80
81 return name;
82 }
83
84 const char *sample_clock_description()
85 {
86 lttng_ust_clock_description_function get_description_cb;
87
88 if (lttng_ust_trace_clock_get_description_cb(&get_description_cb)) {
89 LTTNG_THROW_ERROR("Failed to get clock description callback");
90 }
91
92 const auto description = get_description_cb();
93 if (!description) {
94 LTTNG_THROW_ERROR("Invalid clock description returned by LTTng-UST `lttng_ust_clock_description_function`");
95 }
96
97 return description;
98 }
99
100 /*
101 * The offset between monotonic and realtime clock can be negative if
102 * the system sets the REALTIME clock to 0 after boot.
103 */
104 void measure_single_clock_offset(struct offset_sample *sample)
105 {
106 lttng::ust::clock_attributes_sample::cycles_t monotonic_avg, monotonic[2], measure_delta,
107 realtime;
108 const auto tcf = sample_clock_frequency();
109 struct timespec rts = { 0, 0 };
110
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);
114 }
115
116 monotonic[1] = sample_clock_read64();
117 measure_delta = monotonic[1] - monotonic[0];
118 if (measure_delta > sample->measure_delta) {
119 /*
120 * Discard value if it took longer to read than the best
121 * sample so far.
122 */
123 return;
124 }
125
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;
130 } else {
131 realtime += (lttng::ust::clock_attributes_sample::cycles_t) rts.tv_nsec * tcf /
132 NSEC_PER_SEC;
133 }
134
135 sample->offset = (lttng::ust::clock_attributes_sample::scycles_t) realtime - monotonic_avg;
136 sample->measure_delta = measure_delta;
137 }
138
139 /*
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.
144 */
145 lttng::ust::clock_attributes_sample::scycles_t measure_clock_offset(void)
146 {
147 struct offset_sample offset_best_sample = {
148 .offset = 0,
149 .measure_delta = UINT64_MAX,
150 };
151
152 for (auto i = 0; i < CLOCK_OFFSET_SAMPLE_COUNT; i++) {
153 measure_single_clock_offset(&offset_best_sample);
154 }
155
156 return offset_best_sample.offset;
157 }
158 }
159
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()}
166 {
167 }
This page took 0.031846 seconds and 4 git commands to generate.