if HAVE_LIBLTTNG_UST_CTL
liblttng_sessiond_common_la_SOURCES += trace-ust.cpp ust-registry.cpp ust-app.cpp \
ust-consumer.cpp ust-consumer.hpp notify-apps.cpp \
- ust-metadata.cpp ust-clock.hpp agent-thread.cpp agent-thread.hpp \
+ ust-metadata.cpp ust-clock.hpp ust-clock.cpp \
+ agent-thread.cpp agent-thread.hpp \
ust-field-utils.hpp ust-field-utils.cpp \
ust-sigbus.cpp \
ust-registry-session.cpp \
--- /dev/null
+/*
+ * Copyright (C) 2010 Pierre-Marc Fournier
+ * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "ust-clock.hpp"
+
+#include <common/time.hpp>
+#include <common/exception.hpp>
+
+#define CLOCK_OFFSET_SAMPLE_COUNT 10
+
+namespace {
+struct offset_sample {
+ /* correlation offset */
+ lttng::ust::clock_attributes_sample::scycles_t offset;
+ /* lower is better */
+ lttng::ust::clock_attributes_sample::cycles_t measure_delta;
+};
+
+lttng::ust::clock_attributes_sample::cycles_t sample_clock_read64()
+{
+ lttng_ust_clock_read64_function read64_cb;
+
+ if (lttng_ust_trace_clock_get_read64_cb(&read64_cb)) {
+ LTTNG_THROW_ERROR("Failed to get clock sample callback");
+ }
+
+ return read64_cb();
+}
+
+lttng::ust::clock_attributes_sample::cycles_t sample_clock_frequency()
+{
+ lttng_ust_clock_freq_function get_freq_cb;
+
+ if (lttng_ust_trace_clock_get_freq_cb(&get_freq_cb)) {
+ LTTNG_THROW_ERROR("Failed to get clock frequency callback");
+ }
+
+ return get_freq_cb();
+}
+
+nonstd::optional<lttng_uuid> sample_clock_uuid()
+{
+ lttng_ust_clock_uuid_function get_uuid_cb;
+
+ if (lttng_ust_trace_clock_get_uuid_cb(&get_uuid_cb)) {
+ return nonstd::nullopt;
+ }
+
+ char uuid_str[LTTNG_UUID_STR_LEN];
+ if (get_uuid_cb(uuid_str)) {
+ return nonstd::nullopt;
+ }
+
+ lttng_uuid uuid;
+ if (lttng_uuid_from_str(uuid_str, uuid)) {
+ LTTNG_THROW_ERROR("Failed to parse UUID from string");
+ }
+
+ return nonstd::optional<lttng_uuid>{uuid};
+}
+
+const char *sample_clock_name()
+{
+ lttng_ust_clock_name_function get_name_cb;
+
+ if (lttng_ust_trace_clock_get_name_cb(&get_name_cb)) {
+ LTTNG_THROW_ERROR("Failed to get clock name callback");
+ }
+
+ const auto name = get_name_cb();
+ if (!name) {
+ LTTNG_THROW_ERROR("Invalid clock name returned by LTTng-UST `lttng_ust_clock_name_function`");
+ }
+
+ return name;
+}
+
+const char *sample_clock_description()
+{
+ lttng_ust_clock_description_function get_description_cb;
+
+ if (lttng_ust_trace_clock_get_description_cb(&get_description_cb)) {
+ LTTNG_THROW_ERROR("Failed to get clock description callback");
+ }
+
+ const auto description = get_description_cb();
+ if (!description) {
+ LTTNG_THROW_ERROR("Invalid clock description returned by LTTng-UST `lttng_ust_clock_description_function`");
+ }
+
+ return description;
+}
+
+/*
+ * The offset between monotonic and realtime clock can be negative if
+ * the system sets the REALTIME clock to 0 after boot.
+ */
+void measure_single_clock_offset(struct offset_sample *sample)
+{
+ lttng::ust::clock_attributes_sample::cycles_t monotonic_avg, monotonic[2], measure_delta,
+ realtime;
+ const auto tcf = sample_clock_frequency();
+ struct timespec rts = { 0, 0 };
+
+ monotonic[0] = sample_clock_read64();
+ if (lttng_clock_gettime(CLOCK_REALTIME, &rts)) {
+ LTTNG_THROW_POSIX("Failed to sample time from clock", errno);
+ }
+
+ monotonic[1] = sample_clock_read64();
+ measure_delta = monotonic[1] - monotonic[0];
+ if (measure_delta > sample->measure_delta) {
+ /*
+ * Discard value if it took longer to read than the best
+ * sample so far.
+ */
+ return;
+ }
+
+ monotonic_avg = (monotonic[0] + monotonic[1]) >> 1;
+ realtime = (lttng::ust::clock_attributes_sample::cycles_t) rts.tv_sec * tcf;
+ if (tcf == NSEC_PER_SEC) {
+ realtime += rts.tv_nsec;
+ } else {
+ realtime += (lttng::ust::clock_attributes_sample::cycles_t) rts.tv_nsec * tcf /
+ NSEC_PER_SEC;
+ }
+
+ sample->offset = (lttng::ust::clock_attributes_sample::scycles_t) realtime - monotonic_avg;
+ sample->measure_delta = measure_delta;
+}
+
+/*
+ * Approximation of NTP time of day to clock monotonic correlation,
+ * taken at start of trace. Keep the measurement that took the less time
+ * to complete, thus removing imprecision caused by preemption.
+ * May return a negative offset.
+ */
+lttng::ust::clock_attributes_sample::scycles_t measure_clock_offset(void)
+{
+ struct offset_sample offset_best_sample = {
+ .offset = 0,
+ .measure_delta = UINT64_MAX,
+ };
+
+ for (auto i = 0; i < CLOCK_OFFSET_SAMPLE_COUNT; i++) {
+ measure_single_clock_offset(&offset_best_sample);
+ }
+
+ return offset_best_sample.offset;
+}
+}
+
+lttng::ust::clock_attributes_sample::clock_attributes_sample() :
+ _name{sample_clock_name()},
+ _description{sample_clock_description()},
+ _uuid{sample_clock_uuid()},
+ _offset{measure_clock_offset()},
+ _frequency{sample_clock_frequency()}
+{
+}
/*
* Copyright (C) 2010 Pierre-Marc Fournier
* Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
*
* SPDX-License-Identifier: GPL-2.0-only
*
#define _UST_CLOCK_H
#include <common/compat/time.hpp>
-#include <sys/time.h>
-#include <stdint.h>
+#include <common/uuid.hpp>
+#include <vendor/optional.hpp>
+
+#include <lttng/ust-clock.h>
#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
-#include <urcu/system.h>
+#include <string>
+#include <sys/time.h>
#include <urcu/arch.h>
-#include <lttng/ust-clock.h>
-
-#include <common/uuid.hpp>
-
-static __inline__
-uint64_t trace_clock_read64(void)
-{
- uint64_t clock_value = 0;
- lttng_ust_clock_read64_function read64_cb;
-
- if (lttng_ust_trace_clock_get_read64_cb(&read64_cb)) {
- goto end;
- }
-
- clock_value = read64_cb();
-end:
- return clock_value;
-}
-
-static __inline__
-uint64_t trace_clock_freq(void)
-{
- uint64_t frequency = 0;
- lttng_ust_clock_freq_function get_freq_cb;
-
- if (lttng_ust_trace_clock_get_freq_cb(&get_freq_cb)) {
- goto end;
- }
-
- frequency = get_freq_cb();
-end:
- return frequency;
-}
-
-static __inline__
-int trace_clock_uuid(char *uuid)
-{
- int ret;
- lttng_ust_clock_uuid_function get_uuid_cb;
-
- if (lttng_ust_trace_clock_get_uuid_cb(&get_uuid_cb)) {
- ret = -EINVAL;
- goto end;
- }
-
- ret = get_uuid_cb(uuid);
-end:
- return ret;
-
-}
-
-static __inline__
-const char *trace_clock_name(void)
-{
- const char *name;
- lttng_ust_clock_name_function get_name_cb;
+#include <urcu/system.h>
- if (lttng_ust_trace_clock_get_name_cb(&get_name_cb)) {
- name = NULL;
- goto end;
- }
+namespace lttng {
+namespace ust {
- name = get_name_cb();
-end:
- return name;
-}
+class clock_attributes_sample {
+public:
+ using cycles_t = uint64_t;
+ using scycles_t = int64_t;
-static __inline__
-const char *trace_clock_description(void)
-{
- const char *description;
- lttng_ust_clock_description_function get_description_cb;
+ clock_attributes_sample();
- if (lttng_ust_trace_clock_get_description_cb(&get_description_cb)) {
- description = NULL;
- goto end;
- }
+ const std::string _name;
+ const std::string _description;
+ const nonstd::optional<lttng_uuid> _uuid;
+ const scycles_t _offset;
+ const cycles_t _frequency;
+};
- description = get_description_cb();
-end:
- return description;
-}
+} /* namespace ust */
+} /* namespace lttng */
#endif /* _UST_CLOCK_H */
*/
#define _LGPL_SOURCE
-#include <stdint.h>
-#include <string.h>
+#include <inttypes.h>
+#include <limits.h>
#include <stdarg.h>
+#include <stdint.h>
#include <stdio.h>
-#include <limits.h>
+#include <string.h>
#include <unistd.h>
-#include <inttypes.h>
+#include <vector>
+
#include <common/common.hpp>
+#include <common/exception.hpp>
#include <common/time.hpp>
-#include <vector>
+#include <common/uuid.hpp>
-#include "ust-registry.hpp"
-#include "ust-clock.hpp"
#include "ust-app.hpp"
-
-#define NR_CLOCK_OFFSET_SAMPLES 10
-
-namespace {
-struct offset_sample {
- /* correlation offset */
- int64_t offset;
- /* lower is better */
- uint64_t measure_delta;
-};
-} /* namespace */
+#include "ust-clock.hpp"
+#include "ust-registry.hpp"
static
int _lttng_field_statedump(ust_registry_session *session,
);
}
-/*
- * The offset between monotonic and realtime clock can be negative if
- * the system sets the REALTIME clock to 0 after boot.
- */
-static
-int measure_single_clock_offset(struct offset_sample *sample)
-{
- uint64_t monotonic_avg, monotonic[2], measure_delta, realtime;
- uint64_t tcf = trace_clock_freq();
- struct timespec rts = { 0, 0 };
- int ret;
-
- monotonic[0] = trace_clock_read64();
- ret = lttng_clock_gettime(CLOCK_REALTIME, &rts);
- if (ret < 0) {
- return ret;
- }
- monotonic[1] = trace_clock_read64();
- measure_delta = monotonic[1] - monotonic[0];
- if (measure_delta > sample->measure_delta) {
- /*
- * Discard value if it took longer to read than the best
- * sample so far.
- */
- return 0;
- }
- monotonic_avg = (monotonic[0] + monotonic[1]) >> 1;
- realtime = (uint64_t) rts.tv_sec * tcf;
- if (tcf == NSEC_PER_SEC) {
- realtime += rts.tv_nsec;
- } else {
- realtime += (uint64_t) rts.tv_nsec * tcf / NSEC_PER_SEC;
- }
- sample->offset = (int64_t) realtime - monotonic_avg;
- sample->measure_delta = measure_delta;
- return 0;
-}
-
-/*
- * Approximation of NTP time of day to clock monotonic correlation,
- * taken at start of trace. Keep the measurement that took the less time
- * to complete, thus removing imprecision caused by preemption.
- * May return a negative offset.
- */
-static
-int64_t measure_clock_offset(void)
-{
- int i;
- struct offset_sample offset_best_sample = {
- .offset = 0,
- .measure_delta = UINT64_MAX,
- };
-
- for (i = 0; i < NR_CLOCK_OFFSET_SAMPLES; i++) {
- if (measure_single_clock_offset(&offset_best_sample)) {
- return 0;
- }
- }
- return offset_best_sample.offset;
-}
-
static
int print_metadata_session_information(ust_registry_session *registry)
{
*/
int ust_metadata_session_statedump(ust_registry_session *session)
{
- char uuid_s[LTTNG_UUID_STR_LEN], clock_uuid_s[LTTNG_UUID_STR_LEN];
int ret = 0;
+ char trace_uuid_str[LTTNG_UUID_STR_LEN];
LTTNG_ASSERT(session);
- lttng_uuid_to_str(session->_uuid, uuid_s);
+ lttng_uuid_to_str(session->_uuid, trace_uuid_str);
/* For crash ABI */
ret = lttng_metadata_printf(session,
session->_long_alignment,
CTF_SPEC_MAJOR,
CTF_SPEC_MINOR,
- uuid_s,
+ trace_uuid_str,
session->_byte_order == BIG_ENDIAN ? "be" : "le"
);
if (ret) {
goto end;
}
- ret = lttng_metadata_printf(session,
- "clock {\n"
- " name = \"%s\";\n",
- trace_clock_name()
- );
- if (ret) {
- goto end;
- }
+ try {
+ const lttng::ust::clock_attributes_sample clock;
- if (!trace_clock_uuid(clock_uuid_s)) {
ret = lttng_metadata_printf(session,
- " uuid = \"%s\";\n",
- clock_uuid_s
- );
+ "clock {\n"
+ " name = \"%s\";\n",
+ clock._name.c_str());
if (ret) {
goto end;
}
- }
- ret = lttng_metadata_printf(session,
- " description = \"%s\";\n"
- " freq = %" PRIu64 "; /* Frequency, in Hz */\n"
- " /* clock value offset from Epoch is: offset * (1/freq) */\n"
- " offset = %" PRId64 ";\n"
- "};\n\n",
- trace_clock_description(),
- trace_clock_freq(),
- measure_clock_offset()
- );
- if (ret) {
- goto end;
- }
+ if (clock._uuid) {
+ char clock_uuid_str[LTTNG_UUID_STR_LEN];
- ret = lttng_metadata_printf(session,
- "typealias integer {\n"
- " size = 27; align = 1; signed = false;\n"
- " map = clock.%s.value;\n"
- "} := uint27_clock_monotonic_t;\n"
- "\n"
- "typealias integer {\n"
- " size = 32; align = %u; signed = false;\n"
- " map = clock.%s.value;\n"
- "} := uint32_clock_monotonic_t;\n"
- "\n"
- "typealias integer {\n"
- " size = 64; align = %u; signed = false;\n"
- " map = clock.%s.value;\n"
- "} := uint64_clock_monotonic_t;\n\n",
- trace_clock_name(),
- session->_uint32_t_alignment,
- trace_clock_name(),
- session->_uint64_t_alignment,
- trace_clock_name()
- );
- if (ret) {
+ lttng_uuid_to_str(*clock._uuid, clock_uuid_str);
+ ret = lttng_metadata_printf(
+ session, " uuid = \"%s\";\n", clock_uuid_str);
+ if (ret) {
+ goto end;
+ }
+ }
+
+ ret = lttng_metadata_printf(session,
+ " description = \"%s\";\n"
+ " freq = %" PRIu64 "; /* Frequency, in Hz */\n"
+ " /* clock value offset from Epoch is: offset * (1/freq) */\n"
+ " offset = %" PRId64 ";\n"
+ "};\n\n",
+ clock._description.c_str(), clock._frequency, clock._offset);
+ if (ret) {
+ goto end;
+ }
+
+ ret = lttng_metadata_printf(session,
+ "typealias integer {\n"
+ " size = 27; align = 1; signed = false;\n"
+ " map = clock.%s.value;\n"
+ "} := uint27_clock_monotonic_t;\n"
+ "\n"
+ "typealias integer {\n"
+ " size = 32; align = %u; signed = false;\n"
+ " map = clock.%s.value;\n"
+ "} := uint32_clock_monotonic_t;\n"
+ "\n"
+ "typealias integer {\n"
+ " size = 64; align = %u; signed = false;\n"
+ " map = clock.%s.value;\n"
+ "} := uint64_clock_monotonic_t;\n\n",
+ clock._name.c_str(), session->_uint32_t_alignment,
+ clock._name.c_str(), session->_uint64_t_alignment,
+ clock._name.c_str());
+ if (ret) {
+ goto end;
+ }
+ } catch (const std::exception &ex) {
+ ERR("Failed to serialize clock description: %s", ex.what());
+ ret = -1;
goto end;
}