sessiond: Move trace_ust_clock to a clock_attributes_sample class
[lttng-tools.git] / src / bin / lttng-sessiond / ust-metadata.cpp
index 7e6b1aba0810933f725a32b64986d8c29e9f1e82..edbad778372023b1aee27a48b5240b99d80eccc9 100644 (file)
@@ -6,33 +6,26 @@
  */
 
 #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 <common/common.h>
-#include <common/time.h>
-
-#include "ust-registry.h"
-#include "ust-clock.h"
-#include "ust-app.h"
+#include <vector>
 
-#ifndef max_t
-#define max_t(type, a, b)      ((type) ((a) > (b) ? (a) : (b)))
-#endif
+#include <common/common.hpp>
+#include <common/exception.hpp>
+#include <common/time.hpp>
+#include <common/uuid.hpp>
 
-#define NR_CLOCK_OFFSET_SAMPLES                10
-
-struct offset_sample {
-       int64_t offset;                 /* correlation offset */
-       uint64_t measure_delta;         /* lower is better */
-};
+#include "ust-app.hpp"
+#include "ust-clock.hpp"
+#include "ust-registry.hpp"
 
 static
-int _lttng_field_statedump(struct ust_registry_session *session,
+int _lttng_field_statedump(ust_registry_session *session,
                const struct lttng_ust_ctl_field *fields, size_t nr_fields,
                size_t *iter_field, size_t nesting);
 
@@ -53,11 +46,11 @@ int get_count_order(unsigned int count)
  * Returns offset where to write in metadata array, or negative error value on error.
  */
 static
-ssize_t metadata_reserve(struct ust_registry_session *session, size_t len)
+ssize_t metadata_reserve(ust_registry_session *session, size_t len)
 {
-       size_t new_len = session->metadata_len + len;
+       size_t new_len = session->_metadata_len + len;
        size_t new_alloc_len = new_len;
-       size_t old_alloc_len = session->metadata_alloc_len;
+       size_t old_alloc_len = session->_metadata_alloc_len;
        ssize_t ret;
 
        if (new_alloc_len > (UINT32_MAX >> 1))
@@ -69,31 +62,31 @@ ssize_t metadata_reserve(struct ust_registry_session *session, size_t len)
                char *newptr;
 
                new_alloc_len =
-                       max_t(size_t, 1U << get_count_order(new_alloc_len), old_alloc_len << 1);
-               newptr = (char *) realloc(session->metadata, new_alloc_len);
+                       std::max<size_t>(1U << get_count_order(new_alloc_len), old_alloc_len << 1);
+               newptr = (char *) realloc(session->_metadata, new_alloc_len);
                if (!newptr)
                        return -ENOMEM;
-               session->metadata = newptr;
+               session->_metadata = newptr;
                /* We zero directly the memory from start of allocation. */
-               memset(&session->metadata[old_alloc_len], 0, new_alloc_len - old_alloc_len);
-               session->metadata_alloc_len = new_alloc_len;
+               memset(&session->_metadata[old_alloc_len], 0, new_alloc_len - old_alloc_len);
+               session->_metadata_alloc_len = new_alloc_len;
        }
-       ret = session->metadata_len;
-       session->metadata_len += len;
+       ret = session->_metadata_len;
+       session->_metadata_len += len;
        return ret;
 }
 
 static
-int metadata_file_append(struct ust_registry_session *session,
+int metadata_file_append(ust_registry_session *session,
                const char *str, size_t len)
 {
        ssize_t written;
 
-       if (session->metadata_fd < 0) {
+       if (session->_metadata_fd < 0) {
                return 0;
        }
        /* Write to metadata file */
-       written = lttng_write(session->metadata_fd, str, len);
+       written = lttng_write(session->_metadata_fd, str, len);
        if (written != len) {
                return -1;
        }
@@ -107,7 +100,7 @@ int metadata_file_append(struct ust_registry_session *session,
  * protects us from concurrent writes.
  */
 static ATTR_FORMAT_PRINTF(2, 3)
-int lttng_metadata_printf(struct ust_registry_session *session,
+int lttng_metadata_printf(ust_registry_session *session,
                const char *fmt, ...)
 {
        char *str = NULL;
@@ -128,7 +121,7 @@ int lttng_metadata_printf(struct ust_registry_session *session,
                ret = offset;
                goto end;
        }
-       memcpy(&session->metadata[offset], str, len);
+       memcpy(&session->_metadata[offset], str, len);
        ret = metadata_file_append(session, str, len);
        if (ret) {
                PERROR("Error appending to metadata file");
@@ -143,7 +136,7 @@ end:
 }
 
 static
-int print_tabs(struct ust_registry_session *session, size_t nesting)
+int print_tabs(ust_registry_session *session, size_t nesting)
 {
        size_t i;
 
@@ -177,7 +170,7 @@ void sanitize_ctf_identifier(char *out, const char *in)
 }
 
 static
-int print_escaped_ctf_string(struct ust_registry_session *session, const char *string)
+int print_escaped_ctf_string(ust_registry_session *session, const char *string)
 {
        int ret = 0;
        size_t i;
@@ -215,7 +208,7 @@ error:
 
 /* Called with session registry mutex held. */
 static
-int ust_metadata_enum_statedump(struct ust_registry_session *session,
+int ust_metadata_enum_statedump(ust_registry_session *session,
                const char *enum_name,
                uint64_t enum_id,
                const struct lttng_ust_ctl_integer_type *container_type,
@@ -358,7 +351,7 @@ end:
 }
 
 static
-int _lttng_variant_statedump(struct ust_registry_session *session,
+int _lttng_variant_statedump(ust_registry_session *session,
                uint32_t nr_choices, const char *tag_name,
                uint32_t alignment,
                const struct lttng_ust_ctl_field *fields, size_t nr_fields,
@@ -423,7 +416,7 @@ end:
 }
 
 static
-int _lttng_field_statedump(struct ust_registry_session *session,
+int _lttng_field_statedump(ust_registry_session *session,
                const struct lttng_ust_ctl_field *fields, size_t nr_fields,
                size_t *iter_field, size_t nesting)
 {
@@ -440,7 +433,7 @@ int _lttng_field_statedump(struct ust_registry_session *session,
        }
        field = &fields[*iter_field];
 
-       if (session->byte_order == BIG_ENDIAN) {
+       if (session->_byte_order == BIG_ENDIAN) {
                bo_reverse = bo_le;
        } else {
                bo_reverse = bo_be;
@@ -790,7 +783,7 @@ end:
 }
 
 static
-int _lttng_context_metadata_statedump(struct ust_registry_session *session,
+int _lttng_context_metadata_statedump(ust_registry_session *session,
                size_t nr_ctx_fields,
                struct lttng_ust_ctl_field *ctx)
 {
@@ -813,7 +806,7 @@ int _lttng_context_metadata_statedump(struct ust_registry_session *session,
 }
 
 static
-int _lttng_fields_metadata_statedump(struct ust_registry_session *session,
+int _lttng_fields_metadata_statedump(ust_registry_session *session,
                struct ust_registry_event *event)
 {
        int ret = 0;
@@ -835,7 +828,7 @@ int _lttng_fields_metadata_statedump(struct ust_registry_session *session,
 /*
  * Should be called with session registry mutex held.
  */
-int ust_metadata_event_statedump(struct ust_registry_session *session,
+int ust_metadata_event_statedump(ust_registry_session *session,
                struct ust_registry_channel *chan,
                struct ust_registry_event *event)
 {
@@ -845,6 +838,16 @@ int ust_metadata_event_statedump(struct ust_registry_session *session,
        if (chan->chan_id == -1U)
                return 0;
 
+       /*
+        * We don't want to output an event's metadata before its parent
+        * stream's metadata.  If the stream's metadata hasn't been output yet,
+        * skip this event.  Its metadata will be output when we output the
+        * stream's metadata.
+        */
+       if (!chan->metadata_dumped || event->metadata_dumped) {
+               return 0;
+       }
+
        ret = lttng_metadata_printf(session,
                "event {\n"
                "       name = \"%s\";\n"
@@ -899,11 +902,15 @@ end:
 
 /*
  * Should be called with session registry mutex held.
+ *
+ * RCU read lock must be held by the caller.
  */
-int ust_metadata_channel_statedump(struct ust_registry_session *session,
+int ust_metadata_channel_statedump(ust_registry_session *session,
                struct ust_registry_channel *chan)
 {
-       int ret = 0;
+       int ret;
+
+       ASSERT_RCU_READ_LOCKED();
 
        /* Don't dump metadata events */
        if (chan->chan_id == -1U)
@@ -922,41 +929,69 @@ int ust_metadata_channel_statedump(struct ust_registry_session *session,
                        "struct event_header_compact" :
                        "struct event_header_large");
        if (ret) {
-               goto end;
+               return ret;
        }
 
        if (chan->ctx_fields) {
                ret = lttng_metadata_printf(session,
                        "       event.context := struct {\n");
                if (ret) {
-                       goto end;
+                       return ret;
                }
        }
        ret = _lttng_context_metadata_statedump(session,
                chan->nr_ctx_fields,
                chan->ctx_fields);
        if (ret) {
-               goto end;
+               return ret;
        }
        if (chan->ctx_fields) {
                ret = lttng_metadata_printf(session,
                        "       };\n");
                if (ret) {
-                       goto end;
+                       return ret;
                }
        }
 
        ret = lttng_metadata_printf(session,
                "};\n\n");
+       if (ret) {
+               return ret;
+       }
+
        /* Flag success of metadata dump. */
        chan->metadata_dumped = 1;
 
-end:
-       return ret;
+       /*
+        * Output the metadata of any existing event.
+        *
+        * Sort the events by id.  This is not necessary, but it's nice to have
+        * a more predictable order in the metadata file.
+        */
+       std::vector<ust_registry_event *> events;
+       {
+               cds_lfht_iter event_iter;
+               ust_registry_event *event;
+               cds_lfht_for_each_entry(chan->events->ht, &event_iter, event,
+                               node.node) {
+                       events.push_back(event);
+               }
+       }
+
+       std::sort(events.begin(), events.end(),
+               [] (ust_registry_event *a, ust_registry_event *b) {
+                       return a->id < b->id;
+               });
+
+       for (ust_registry_event *event : events) {
+               ust_metadata_event_statedump(session, chan, event);
+       }
+
+       return 0;
 }
 
 static
-int _lttng_stream_packet_context_declare(struct ust_registry_session *session)
+int _lttng_stream_packet_context_declare(ust_registry_session *session)
 {
        return lttng_metadata_printf(session,
                "struct packet_context {\n"
@@ -981,7 +1016,7 @@ int _lttng_stream_packet_context_declare(struct ust_registry_session *session)
  * id 65535 is reserved to indicate an extended header.
  */
 static
-int _lttng_event_header_declare(struct ust_registry_session *session)
+int _lttng_event_header_declare(ust_registry_session *session)
 {
        return lttng_metadata_printf(session,
        "struct event_header_compact {\n"
@@ -1009,81 +1044,20 @@ int _lttng_event_header_declare(struct ust_registry_session *session)
        "               } extended;\n"
        "       } v;\n"
        "} align(%u);\n\n",
-       session->uint32_t_alignment,
-       session->uint16_t_alignment
+       session->_uint32_t_alignment,
+       session->_uint16_t_alignment
        );
 }
 
-/*
- * 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(struct ust_registry_session *registry)
+int print_metadata_session_information(ust_registry_session *registry)
 {
        int ret;
        struct ltt_session *session = NULL;
        char creation_datetime[ISO8601_STR_LEN];
 
        rcu_read_lock();
-       session = session_find_by_id(registry->tracing_id);
+       session = session_find_by_id(registry->_tracing_id);
        if (!session) {
                ret = -1;
                goto error;
@@ -1138,50 +1112,42 @@ error:
 }
 
 static
-int print_metadata_app_information(struct ust_registry_session *registry,
-               struct ust_app *app)
+int print_metadata_app_information(ust_registry_session *registry)
 {
-       int ret;
-       char datetime[ISO8601_STR_LEN];
-
-       if (!app) {
-               ret = 0;
-               goto end;
+       if (registry->get_buffering_scheme() != LTTNG_BUFFER_PER_PID) {
+               return 0;
        }
 
-       ret = time_to_iso8601_str(
-                       app->registration_time, datetime, sizeof(datetime));
+       const auto *per_pid_session = static_cast<const ust_registry_session_per_pid *>(registry);
+
+       char datetime[ISO8601_STR_LEN];
+       int ret = time_to_iso8601_str(
+               per_pid_session->_app_creation_time, datetime, sizeof(datetime));
        if (ret) {
-               goto end;
+               return ret;
        }
 
        ret = lttng_metadata_printf(registry,
-                       "       tracer_patchlevel = %u;\n"
-                       "       vpid = %d;\n"
-                       "       procname = \"%s\";\n"
-                       "       vpid_datetime = \"%s\";\n",
-                       app->version.patchlevel, (int) app->pid, app->name,
-                       datetime);
-
-end:
+               "       tracer_patchlevel = %u;\n"
+               "       vpid = %d;\n"
+               "       procname = \"%s\";\n"
+               "       vpid_datetime = \"%s\";\n",
+               per_pid_session->_tracer_patch_level_version, (int) per_pid_session->_vpid,
+               per_pid_session->_procname.c_str(), datetime);
        return ret;
 }
 
 /*
  * Should be called with session registry mutex held.
  */
-int ust_metadata_session_statedump(struct ust_registry_session *session,
-               struct ust_app *app,
-               uint32_t major,
-               uint32_t minor)
+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,
@@ -1213,16 +1179,16 @@ int ust_metadata_session_statedump(struct ust_registry_session *session,
                "               uint64_t stream_instance_id;\n"
                "       };\n"
                "};\n\n",
-               session->uint8_t_alignment,
-               session->uint16_t_alignment,
-               session->uint32_t_alignment,
-               session->uint64_t_alignment,
-               session->bits_per_long,
-               session->long_alignment,
+               session->_uint8_t_alignment,
+               session->_uint16_t_alignment,
+               session->_uint32_t_alignment,
+               session->_uint64_t_alignment,
+               session->_bits_per_long,
+               session->_long_alignment,
                CTF_SPEC_MAJOR,
                CTF_SPEC_MINOR,
-               uuid_s,
-               session->byte_order == BIG_ENDIAN ? "be" : "le"
+               trace_uuid_str,
+               session->_byte_order == BIG_ENDIAN ? "be" : "le"
                );
        if (ret) {
                goto end;
@@ -1237,11 +1203,12 @@ int ust_metadata_session_statedump(struct ust_registry_session *session,
                "       tracer_buffering_scheme = \"%s\";\n"
                "       tracer_buffering_id = %u;\n"
                "       architecture_bit_width = %u;\n",
-               major,
-               minor,
-               app ? "pid" : "uid",
-               app ? (int) app->pid : (int) session->tracing_uid,
-               session->bits_per_long);
+               session->_app_tracer_version_major, session->_app_tracer_version_minor,
+               session->get_buffering_scheme() == LTTNG_BUFFER_PER_PID ? "pid" : "uid",
+               session->get_buffering_scheme() == LTTNG_BUFFER_PER_PID ?
+                       (int) static_cast<ust_registry_session_per_pid *>(session)->_vpid :
+                       (int) static_cast<ust_registry_session_per_uid *>(session)->_tracing_uid,
+               session->_bits_per_long);
        if (ret) {
                goto end;
        }
@@ -1255,7 +1222,7 @@ int ust_metadata_session_statedump(struct ust_registry_session *session,
         * If per-application registry, we can output extra information
         * about the application.
         */
-       ret = print_metadata_app_information(session, app);
+       ret = print_metadata_app_information(session);
        if (ret) {
                goto end;
        }
@@ -1267,61 +1234,63 @@ int ust_metadata_session_statedump(struct ust_registry_session *session,
                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;
        }
 
This page took 0.032326 seconds and 4 git commands to generate.