From: Jérémie Galarneau Date: Mon, 4 Jul 2022 19:19:00 +0000 (-0400) Subject: sessiond: add a CTF 2-generating trace class visitor X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=commitdiff_plain;h=da9dd5212ebacf388ebe26aa80fd0ddcf7ffe049 sessiond: add a CTF 2-generating trace class visitor The enumeration_type class is modified to guarantee that a mapping is present. Implicit (or auto) mappings provided by the tracer are converted to an explicit mapping. This results in a slightly more verbose TSDL output which can be fixed later. Change-Id: I4372ad528384c1b7d9321dd5183525e3bd60ded4 Signed-off-by: Jérémie Galarneau --- diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am index 7f8ac379c..7d618afe2 100644 --- a/src/bin/lttng-sessiond/Makefile.am +++ b/src/bin/lttng-sessiond/Makefile.am @@ -76,7 +76,8 @@ liblttng_sessiond_common_la_SOURCES += trace-ust.cpp ust-registry.cpp ust-app.cp ust-registry-channel.cpp ust-registry-channel.hpp \ ust-registry-session-uid.cpp ust-registry-session-uid.hpp \ ust-registry-session-pid.cpp ust-registry-session-pid.hpp \ - tsdl-trace-class-visitor.cpp tsdl-trace-class-visitor.hpp + tsdl-trace-class-visitor.cpp tsdl-trace-class-visitor.hpp \ + ctf2-trace-class-visitor.cpp ctf2-trace-class-visitor.hpp endif # link on liblttngctl for check if sessiond is already alive. diff --git a/src/bin/lttng-sessiond/ctf2-trace-class-visitor.cpp b/src/bin/lttng-sessiond/ctf2-trace-class-visitor.cpp new file mode 100644 index 000000000..169d370bd --- /dev/null +++ b/src/bin/lttng-sessiond/ctf2-trace-class-visitor.cpp @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2022 Jérémie Galarneau + * Copyright (C) 2022 Simon Marchi + * + * SPDX-License-Identifier: GPL-2.0-only + * + */ + +#include "ctf2-trace-class-visitor.hpp" +#include "clock-class.hpp" + +#include +#include + +#include + +#include + +namespace lsc = lttng::sessiond::ctf2; +namespace lst = lttng::sessiond::trace; + +namespace json = nlohmann; + +namespace { +const unsigned int spaces_per_indent = 2; +const std::string record_separator = "\x1e"; + +json::json make_json_fragment(const char *type) +{ + return {{"type", type}}; +} + +json::json to_json(const lst::field_location &location) +{ + json::json location_array; + + switch (location.root_) { + case lst::field_location::root::PACKET_HEADER: + location_array.push_back("packet-header"); + break; + case lst::field_location::root::PACKET_CONTEXT: + location_array.push_back("packet-context"); + break; + case lst::field_location::root::EVENT_RECORD_HEADER: + location_array.push_back("event-record-header"); + break; + case lst::field_location::root::EVENT_RECORD_COMMON_CONTEXT: + location_array.push_back("event-record-common-context"); + break; + case lst::field_location::root::EVENT_RECORD_SPECIFIC_CONTEXT: + location_array.push_back("event-record-specific-context"); + break; + case lst::field_location::root::EVENT_RECORD_PAYLOAD: + location_array.push_back("event-record-payload"); + break; + } + + std::copy(location.elements_.begin(), location.elements_.end(), + std::back_inserter(location_array)); + return location_array; +} + +const char *get_role_name(lst::integer_type::role role) +{ + switch (role) { + case lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP: + return "default-clock-timestamp"; + case lst::integer_type::role::DATA_STREAM_CLASS_ID: + return "data-stream-class-id"; + case lst::integer_type::role::DATA_STREAM_ID: + return "data-stream-id"; + case lst::integer_type::role::PACKET_MAGIC_NUMBER: + return "packet-magic-number"; + case lst::integer_type::role::DISCARDED_EVENT_RECORD_COUNTER_SNAPSHOT: + return "discarded-event-record-counter-snapshot"; + case lst::integer_type::role::PACKET_CONTENT_LENGTH: + return "packet-content-length"; + case lst::integer_type::role::PACKET_END_DEFAULT_CLOCK_TIMESTAMP: + return "packet-end-default-clock-timestamp"; + case lst::integer_type::role::PACKET_SEQUENCE_NUMBER: + return "packet-sequence-number"; + case lst::integer_type::role::PACKET_TOTAL_LENGTH: + return "packet-total-length"; + case lst::integer_type::role::EVENT_RECORD_CLASS_ID: + return "event-record-class-id"; + default: + abort(); + } +} + +const char *get_role_name(lst::static_length_blob_type::role role) +{ + switch (role) { + case lst::static_length_blob_type::role::METADATA_STREAM_UUID: + return "metadata-stream-uuid"; + default: + abort(); + } +} + +namespace ctf2 { +class trace_environment_visitor : public lst::trace_class_environment_visitor { +public: + trace_environment_visitor() + { + } + + virtual void visit(const lst::environment_field& field) override + { + _visit(field); + } + + virtual void visit(const lst::environment_field& field) override + { + _visit(field); + } + + /* Only call once. */ + json::json transfer_fragment() + { + return std::move(_environment); + } + +private: + template + void _visit(const FieldType& field) + { + _environment[field.name] = field.value; + } + + json::json _environment; +}; + +class field_visitor : public lttng::sessiond::trace::field_visitor, + public lttng::sessiond::trace::type_visitor { +public: + field_visitor() + { + } + + /* Only call once. */ + json::json transfer_fragment() + { + return std::move(_fragment); + } + +private: + virtual void visit(const lst::field& field) override final + { + field_visitor field_type_visitor; + field.get_type().accept(field_type_visitor); + + _fragment["name"] = field.name; + _fragment["field-class"] = field_type_visitor.transfer_fragment(); + } + + virtual void visit(const lst::integer_type& type) override final + { + _fragment["type"] = type.signedness_ == lst::integer_type::signedness::SIGNED ? + "fixed-length-signed-integer" : + "fixed-length-unsigned-integer"; + _fragment["length"] = type.size; + _fragment["byte-order"] = type.byte_order == lst::byte_order::BIG_ENDIAN_ ? + "big-endian" : + "little-endian"; + _fragment["alignment"] = type.alignment; + _fragment["preferred-display-base"] = (unsigned int) type.base_; + + if (type.roles_.size() > 0) { + json::json role_array = json::json::array(); + + for (const auto role : type.roles_) { + role_array.push_back(get_role_name(role)); + } + + _fragment["roles"] = std::move(role_array); + } + } + + virtual void visit(const lst::floating_point_type& type) override final + { + _fragment["type"] = "fixed-length-floating-point-number"; + _fragment["length"] = type.exponent_digits + type.mantissa_digits; + _fragment["byte-order"] = type.byte_order == lst::byte_order::BIG_ENDIAN_ ? + "big-endian" : + "little-endian"; + _fragment["alignment"] = type.alignment; + } + + template + void visit_enumeration(const EnumerationType& type) + { + _fragment["type"] = std::is_signed::value ? + "fixed-length-signed-enumeration" : + "fixed-length-unsigned-enumeration"; + _fragment["length"] = type.size; + _fragment["byte-order"] = type.byte_order == lst::byte_order::BIG_ENDIAN_ ? + "big-endian" : + "little-endian"; + _fragment["alignment"] = type.alignment; + _fragment["preferred-display-base"] = (unsigned int) type.base_; + + if (type.roles_.size() > 0) { + if (std::is_signed::value) { + LTTNG_THROW_ERROR(fmt::format( + "Failed to serialize {}: unexpected role", + _fragment["type"])); + } + + auto role_array = json::json::array(); + + for (const auto role : type.roles_) { + role_array.push_back(get_role_name(role)); + } + + _fragment["roles"] = std::move(role_array); + } + + if (type.mappings_->size() < 1) { + LTTNG_THROW_ERROR(fmt::format( + "Failed to serialize {}: enumeration must have at least one mapping", + _fragment["type"])); + } + + json::json mappings_value; + for (const auto &mapping : *type.mappings_) { + mappings_value[mapping.name] = {{mapping.range.begin, mapping.range.end}}; + } + + _fragment["mappings"] = std::move(mappings_value); + } + + virtual void visit(const lst::signed_enumeration_type& type) override final + { + visit_enumeration(type); + } + + virtual void visit(const lst::unsigned_enumeration_type& type) override final + { + visit_enumeration(type); + } + + virtual void visit(const lst::static_length_array_type& type) override final + { + _fragment["type"] = "static-length-array"; + + ::ctf2::field_visitor element_visitor; + type.element_type->accept(element_visitor); + _fragment["element-field-class"] = element_visitor.transfer_fragment(); + + if (type.alignment != 0) { + _fragment["minimum-alignment"] = type.alignment; + } + + _fragment["length"] = type.length; + } + + virtual void visit(const lst::dynamic_length_array_type& type) override final + { + _fragment["type"] = "dynamic-length-array"; + + ::ctf2::field_visitor element_visitor; + type.element_type->accept(element_visitor); + _fragment["element-field-class"] = element_visitor.transfer_fragment(); + + if (type.alignment != 0) { + _fragment["minimum-alignment"] = type.alignment; + } + + _fragment["length-field-location"] = to_json(type.length_field_location); + } + + virtual void visit(const lst::static_length_blob_type& type) override final + { + _fragment["type"] = "static-length-blob"; + _fragment["length"] = type.length_bytes; + + if (type.roles_.size() > 0) { + auto role_array = json::json::array(); + + for (const auto role : type.roles_) { + role_array.push_back(get_role_name(role)); + } + + _fragment["roles"] = std::move(role_array); + } + } + + virtual void visit(const lst::dynamic_length_blob_type& type) override final + { + _fragment["type"] = "dynamic-length-blob"; + _fragment["length-field-location"] = to_json(type.length_field_location); + } + + virtual void visit(const lst::null_terminated_string_type& type + __attribute__((unused))) override final + { + _fragment["type"] = "null-terminated-string"; + } + + virtual void visit(const lst::structure_type& type) override final + { + _fragment["type"] = "structure"; + + if (type.alignment != 0) { + _fragment["minimum-alignment"] = type.alignment; + } + + auto member_classes_value = json::json::array(); + for (const auto &field : type.fields_) { + ::ctf2::field_visitor member_visitor; + json::json member_class; + + field->accept(member_visitor); + member_classes_value.emplace_back(member_visitor.transfer_fragment()); + } + + _fragment["member-classes"] = std::move(member_classes_value); + } + + template + void visit_variant(const lst::variant_type& type) + { + _fragment["type"] = "variant"; + _fragment["selector-field-location"] = to_json(type.selector_field_location); + + auto options_value = json::json::array(); + for (const auto& option : type.choices_) { + ::ctf2::field_visitor option_visitor; + json::json member_class; + + /* TODO missing selector-field-range. */ + member_class["selector-field-ranges"] = {{option.first.range.begin, option.first.range.end}}; + option.second->accept(option_visitor); + member_class["field-class"] = option_visitor.transfer_fragment(); + options_value.emplace_back(std::move(member_class)); + } + + _fragment["options"] = std::move(options_value); + } + + virtual void visit(const lst::variant_type& type) override final + { + visit_variant(type); + } + + virtual void visit(const lst::variant_type& type) override final + { + visit_variant(type); + } + + virtual void visit(const lst::static_length_string_type& type) override final + { + _fragment["type"] = "static-length-string"; + _fragment["length"] = type.length; + } + + virtual void visit(const lst::dynamic_length_string_type& type) override final + { + _fragment["type"] = "dynamic-length-string"; + _fragment["length-field-location"] = to_json(type.length_field_location); + } + + json::json _fragment; +}; +} /* namespace ctf2 */ + +}; /* namespace */ + +lsc::trace_class_visitor::trace_class_visitor(const lst::abi& trace_abi, + lsc::append_metadata_fragment_function append_metadata_fragment) : + _trace_abi{trace_abi}, _append_metadata_fragment(append_metadata_fragment) +{ +} + +void lsc::trace_class_visitor::visit(const lst::trace_class& trace_class) +{ + { + auto preamble_fragment = make_json_fragment("preamble"); + + preamble_fragment["version"] = 2; + preamble_fragment["uuid"] = trace_class.uuid; + append_metadata_fragment(preamble_fragment); + } + + auto trace_class_fragment = make_json_fragment("trace-class"); + + ::ctf2::trace_environment_visitor environment_visitor; + trace_class.accept(environment_visitor); + trace_class_fragment["environment"] = environment_visitor.transfer_fragment(); + + const auto packet_header = trace_class.get_packet_header(); + if (packet_header) { + ::ctf2::field_visitor field_visitor; + + packet_header->accept(field_visitor); + trace_class_fragment["packet-header-field-class"] = field_visitor.transfer_fragment(); + } + + append_metadata_fragment(trace_class_fragment); +} + +void lsc::trace_class_visitor::visit(const lst::clock_class& clock_class) +{ + auto clock_class_fragment = make_json_fragment("clock-class"); + + json::json offset; + offset.update({{"seconds", clock_class.offset / clock_class.frequency}, + {"cycles", clock_class.offset % clock_class.frequency}}); + + clock_class_fragment.update({ + {"name", clock_class.name}, + {"description", clock_class.description}, + {"frequency", clock_class.frequency}, + {"offset", std::move(offset)}}); + + if (clock_class.uuid) { + clock_class_fragment["uuid"] = *clock_class.uuid; + } + + append_metadata_fragment(clock_class_fragment); +} + +void lsc::trace_class_visitor::visit(const lst::stream_class& stream_class) +{ + auto stream_class_fragment = make_json_fragment("data-stream-class"); + + stream_class_fragment["id"] = stream_class.id; + if (stream_class.default_clock_class_name) { + stream_class_fragment["default-clock-class-name"] = + *stream_class.default_clock_class_name; + } + + const auto packet_context = stream_class.get_packet_context(); + if (packet_context) { + ::ctf2::field_visitor visitor; + + packet_context->accept(visitor); + stream_class_fragment["packet-context-field-class"] = visitor.transfer_fragment(); + } + + const auto event_header = stream_class.get_event_header(); + if (event_header) { + ::ctf2::field_visitor visitor; + + event_header->accept(visitor); + stream_class_fragment["event-record-header-field-class"] = + visitor.transfer_fragment(); + } + + const auto event_context = stream_class.get_event_context(); + if (event_context) { + ::ctf2::field_visitor visitor; + + event_context->accept(visitor); + stream_class_fragment["event-record-common-context-field-class"] = + visitor.transfer_fragment(); + } + + append_metadata_fragment(stream_class_fragment); +} + +void lsc::trace_class_visitor::visit(const lst::event_class& event_class) +{ + auto event_class_fragment = make_json_fragment("event-record-class"); + + event_class_fragment["id"] = event_class.id; + event_class_fragment["data-stream-class-id"] = event_class.stream_class_id; + event_class_fragment["name"] = event_class.name; + + if (event_class.payload) { + ::ctf2::field_visitor visitor; + + event_class.payload->accept(visitor); + event_class_fragment["payload-field-class"] = visitor.transfer_fragment(); + } + + append_metadata_fragment(event_class_fragment); +} + +void lsc::trace_class_visitor::append_metadata_fragment(const nlohmann::json& fragment) const +{ + _append_metadata_fragment(record_separator + fragment.dump(spaces_per_indent).c_str()); +} diff --git a/src/bin/lttng-sessiond/ctf2-trace-class-visitor.hpp b/src/bin/lttng-sessiond/ctf2-trace-class-visitor.hpp new file mode 100644 index 000000000..0d2896123 --- /dev/null +++ b/src/bin/lttng-sessiond/ctf2-trace-class-visitor.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 Jérémie Galarneau + * + * SPDX-License-Identifier: GPL-2.0-only + * + */ + +#ifndef LTTNG_CTF2_TRACE_CLASS_VISITOR_H +#define LTTNG_CTF2_TRACE_CLASS_VISITOR_H + +#include "trace-class.hpp" +#include "stream-class.hpp" +#include "event-class.hpp" + +#include +#include + +#include + +namespace lttng { +namespace sessiond { +namespace ctf2 { + +using append_metadata_fragment_function = std::function; + +class trace_class_visitor : public lttng::sessiond::trace::trace_class_visitor { +public: + trace_class_visitor(const lttng::sessiond::trace::abi& trace_abi, + append_metadata_fragment_function append_metadata); + + virtual void visit(const lttng::sessiond::trace::trace_class& trace_class) override final; + virtual void visit(const lttng::sessiond::trace::clock_class& clock_class) override final; + virtual void visit(const lttng::sessiond::trace::stream_class& stream_class) override final; + virtual void visit(const lttng::sessiond::trace::event_class& event_class) override final; + +private: + void append_metadata_fragment(const nlohmann::json& fragment) const; + + const lttng::sessiond::trace::abi& _trace_abi; + const append_metadata_fragment_function _append_metadata_fragment; +}; + +} /* namespace ctf2 */ +} /* namespace sessiond */ +} /* namespace lttng */ + +#endif /* LTTNG_CTF2_TRACE_CLASS_VISITOR_H */ diff --git a/src/bin/lttng-sessiond/field.cpp b/src/bin/lttng-sessiond/field.cpp index 35f4aa0eb..4a7915e20 100644 --- a/src/bin/lttng-sessiond/field.cpp +++ b/src/bin/lttng-sessiond/field.cpp @@ -375,7 +375,7 @@ void lst::null_terminated_string_type::accept(type_visitor& visitor) const } lst::structure_type::structure_type(unsigned int in_alignment, fields in_fields) : - type(in_alignment), _fields{std::move(in_fields)} + type(in_alignment), fields_{std::move(in_fields)} { } @@ -383,10 +383,10 @@ bool lst::structure_type::_is_equal(const type& base_other) const noexcept { const auto &other = static_cast(base_other); - return fields_are_equal(this->_fields, other._fields); + return fields_are_equal(this->fields_, other.fields_); } void lst::structure_type::accept(type_visitor& visitor) const { visitor.visit(*this); -} +} \ No newline at end of file diff --git a/src/bin/lttng-sessiond/field.hpp b/src/bin/lttng-sessiond/field.hpp index 930915728..a774d133a 100644 --- a/src/bin/lttng-sessiond/field.hpp +++ b/src/bin/lttng-sessiond/field.hpp @@ -211,8 +211,7 @@ public: { } - /* Mapping with an implicit value. */ - enumeration_mapping(std::string in_name) : name{std::move(in_name)} + enumeration_mapping(std::string in_name, MappingIntegerType value) : name{std::move(in_name)}, range{value, value} { } @@ -221,7 +220,12 @@ public: } const std::string name; - const nonstd::optional range; + /* + * Only one range per mapping is supported for the moment as + * the tracers (and CTF 1.8) can't express multiple ranges per + * mapping, which is allowed by CTF 2. + */ + const range_t range; }; template @@ -256,13 +260,13 @@ public: integer_type::signedness::UNSIGNED, in_base, std::move(in_roles)), - _mappings{std::move(in_mappings)} + mappings_{std::move(in_mappings)} { } virtual void accept(type_visitor& visitor) const override final; - const std::shared_ptr _mappings; + const std::shared_ptr mappings_; private: virtual bool _is_equal(const type& base_other) const noexcept override final @@ -270,7 +274,7 @@ private: const auto& other = static_cast&>( base_other); - return integer_type::_is_equal(base_other) && *this->_mappings == *other._mappings; + return integer_type::_is_equal(base_other) && *this->mappings_ == *other.mappings_; } }; @@ -320,7 +324,7 @@ class static_length_blob_type : public type { public: enum class role { /* Packet header field class specific role. */ - TRACE_CLASS_UUID, + METADATA_STREAM_UUID, }; using roles = std::vector; @@ -407,7 +411,7 @@ public: virtual void accept(type_visitor& visitor) const override final; - const fields _fields; + const fields fields_; private: virtual bool _is_equal(const type& base_other) const noexcept override final; @@ -432,14 +436,15 @@ public: choices in_choices) : type(in_alignment), selector_field_location{std::move(in_selector_field_location)}, - _choices{std::move(in_choices)} + choices_{std::move(in_choices)} { } virtual void accept(type_visitor& visitor) const override final; const field_location selector_field_location; - const choices _choices; + const choices choices_; +; private: static bool _choices_are_equal(const choices& a, const choices& b) @@ -462,7 +467,7 @@ private: const auto& other = static_cast(base_other); return selector_field_location == other.selector_field_location && - _choices_are_equal(_choices, other._choices); + _choices_are_equal(choices_, other.choices_); } }; diff --git a/src/bin/lttng-sessiond/trace-class.cpp b/src/bin/lttng-sessiond/trace-class.cpp index 21a0c52dc..b9c9b326f 100644 --- a/src/bin/lttng-sessiond/trace-class.cpp +++ b/src/bin/lttng-sessiond/trace-class.cpp @@ -21,15 +21,10 @@ void lttng::sessiond::trace::trace_class::accept(trace_class_visitor& trace_clas { trace_class_visitor.visit(*this); _accept_on_clock_classes(trace_class_visitor); - - trace_class_visitor.environment_begin(); - _visit_environment(trace_class_visitor); - trace_class_visitor.environment_end(); - _accept_on_stream_classes(trace_class_visitor); } -void lst::trace_class_visitor::visit(const environment_field& field) +void lst::trace_class_environment_visitor::visit(const environment_field& field) { visit(environment_field(field.name, field.value.c_str())); } diff --git a/src/bin/lttng-sessiond/trace-class.hpp b/src/bin/lttng-sessiond/trace-class.hpp index 52dcb76a9..ed72f3f57 100644 --- a/src/bin/lttng-sessiond/trace-class.hpp +++ b/src/bin/lttng-sessiond/trace-class.hpp @@ -20,6 +20,7 @@ class clock_class; class stream_class; class event_class; class trace_class_visitor; +class trace_class_environment_visitor; struct abi { unsigned int bits_per_long; @@ -39,54 +40,50 @@ public: { } - const char * const name; + const char* const name; const ValueType& value; }; class trace_class { public: + + virtual ~trace_class() = default; + /* * Derived classes must implement the _accept_on_*() * to continue the traversal to the trace class' children. */ virtual void accept(trace_class_visitor& trace_class_visitor) const; + virtual void accept(trace_class_environment_visitor& environment_visitor) const = 0; virtual const lttng::sessiond::trace::type *get_packet_header() const noexcept = 0; - virtual ~trace_class() = default; - const struct abi abi; const lttng_uuid uuid; protected: trace_class(const struct abi& abi, const lttng_uuid& trace_uuid); virtual void _accept_on_clock_classes(trace_class_visitor& trace_class_visitor) const = 0; - virtual void _visit_environment(trace_class_visitor& trace_class_visitor) const = 0; virtual void _accept_on_stream_classes(trace_class_visitor& trace_class_visitor) const = 0; }; +class trace_class_environment_visitor { +public: + virtual ~trace_class_environment_visitor() = default; + + virtual void visit(const environment_field& field) = 0; + virtual void visit(const environment_field& field) = 0; + virtual void visit(const environment_field& field); +}; + class trace_class_visitor { public: using cuptr = std::unique_ptr; virtual ~trace_class_visitor() = default; - /* trace class visitor interface. */ virtual void visit(const lttng::sessiond::trace::trace_class& trace_class) = 0; - - /* clock class visitor interface. */ virtual void visit(const lttng::sessiond::trace::clock_class& clock_class) = 0; - - /* environment visitor interface. */ - virtual void environment_begin() = 0; - virtual void visit(const environment_field& field) = 0; - virtual void visit(const environment_field& field) = 0; - void visit(const environment_field& field); - virtual void environment_end() = 0; - - /* stream class visitor interface. */ virtual void visit(const lttng::sessiond::trace::stream_class& stream_class) = 0; - - /* event class visitor interface. */ virtual void visit(const lttng::sessiond::trace::event_class& event_class) = 0; }; diff --git a/src/bin/lttng-sessiond/tsdl-trace-class-visitor.cpp b/src/bin/lttng-sessiond/tsdl-trace-class-visitor.cpp index c02addceb..c28af2424 100644 --- a/src/bin/lttng-sessiond/tsdl-trace-class-visitor.cpp +++ b/src/bin/lttng-sessiond/tsdl-trace-class-visitor.cpp @@ -128,9 +128,10 @@ public: { } - std::string& get_description() + /* Only call once. */ + std::string transfer_description() { - return _description; + return std::move(_description); } private: @@ -269,31 +270,29 @@ private: tsdl_field_visitor integer_visitor{_trace_abi, _indentation_level}; integer_visitor.visit(static_cast(type)); - _description += integer_visitor.get_description() + " {\n"; + _description += integer_visitor.transfer_description() + " {\n"; const auto mappings_indentation_level = _indentation_level + 1; bool first_mapping = true; - for (const auto& mapping : *type._mappings) { + for (const auto& mapping : *type.mappings_) { if (!first_mapping) { _description += ",\n"; } _description.resize(_description.size() + mappings_indentation_level, '\t'); - if (!mapping.range) { - _description += fmt::format("\"{}\"", mapping.name); - } else if (mapping.range->begin == mapping.range->end) { + if (mapping.range.begin == mapping.range.end) { _description += fmt::format( "\"{mapping_name}\" = {mapping_value}", fmt::arg("mapping_name", mapping.name), - fmt::arg("mapping_value", mapping.range->begin)); + fmt::arg("mapping_value", mapping.range.begin)); } else { _description += fmt::format( "\"{mapping_name}\" = {mapping_range_begin} ... {mapping_range_end}", fmt::arg("mapping_name", mapping.name), fmt::arg("mapping_range_begin", - mapping.range->begin), - fmt::arg("mapping_range_end", mapping.range->end)); + mapping.range.begin), + fmt::arg("mapping_range_end", mapping.range.end)); } first_mapping = false; @@ -394,7 +393,7 @@ private: const auto previous_bypass_identifier_escape = _bypass_identifier_escape; _bypass_identifier_escape = false; - for (const auto& field : type._fields) { + for (const auto& field : type.fields_) { _description += "\n"; _description.resize(_description.size() + _indentation_level, '\t'); field->accept(*this); @@ -403,7 +402,7 @@ private: _bypass_identifier_escape = previous_bypass_identifier_escape; _indentation_level--; - if (type._fields.size() != 0) { + if (type.fields_.size() != 0) { _description += "\n"; _description.resize(_description.size() + _indentation_level, '\t'); } @@ -437,7 +436,8 @@ private: */ const auto previous_bypass_identifier_escape = _bypass_identifier_escape; _bypass_identifier_escape = true; - for (const auto& field : type._choices) { + for (const auto& field : type.choices_ +) { _description.resize(_description.size() + _indentation_level, '\t'); field.second->accept(*this); _description += fmt::format(" {};\n", field.first.name); @@ -513,6 +513,34 @@ private: bool _bypass_identifier_escape; const char *_default_clock_class_name; }; + +class tsdl_trace_environment_visitor : public lst::trace_class_environment_visitor { +public: + tsdl_trace_environment_visitor() : _environment{"env {\n"} + { + } + + virtual void visit(const lst::environment_field& field) override + { + _environment += fmt::format(" {} = {};\n", field.name, field.value); + } + + virtual void visit(const lst::environment_field& field) override + { + _environment += fmt::format(" {} = \"{}\";\n", field.name, + escape_tsdl_env_string_value(field.value)); + } + + /* Only call once. */ + std::string transfer_description() + { + _environment += "};\n\n"; + return std::move(_environment); + } + +private: + std::string _environment; +}; } /* namespace */ tsdl::trace_class_visitor::trace_class_visitor(const lst::abi& trace_abi, @@ -555,10 +583,14 @@ void tsdl::trace_class_visitor::visit(const lttng::sessiond::trace::trace_class& fmt::arg("uuid", lttng::utils::uuid_to_str(trace_class.uuid)), fmt::arg("byte_order", trace_class.abi.byte_order == lst::byte_order::BIG_ENDIAN_ ? "be" : "le"), - fmt::arg("packet_header_layout", packet_header_visitor.get_description())); + fmt::arg("packet_header_layout", packet_header_visitor.transfer_description())); /* Declare trace scope and type aliases. */ append_metadata_fragment(trace_class_tsdl); + + tsdl_trace_environment_visitor environment_visitor; + trace_class.accept(environment_visitor); + append_metadata_fragment(environment_visitor.transfer_description()); } void tsdl::trace_class_visitor::visit(const lttng::sessiond::trace::clock_class& clock_class) @@ -600,7 +632,7 @@ void tsdl::trace_class_visitor::visit(const lttng::sessiond::trace::stream_class event_header->accept(event_header_visitor); stream_class_str += fmt::format(" event.header := {};\n", - event_header_visitor.get_description()); + event_header_visitor.transfer_description()); } const auto *packet_context = stream_class.get_packet_context(); @@ -610,7 +642,7 @@ void tsdl::trace_class_visitor::visit(const lttng::sessiond::trace::stream_class packet_context->accept(packet_context_visitor); stream_class_str += fmt::format(" packet.context := {};\n", - packet_context_visitor.get_description()); + packet_context_visitor.transfer_description()); } const auto *event_context = stream_class.get_event_context(); @@ -619,7 +651,7 @@ void tsdl::trace_class_visitor::visit(const lttng::sessiond::trace::stream_class event_context->accept(event_context_visitor); stream_class_str += fmt::format(" event.context := {};\n", - event_context_visitor.get_description()); + event_context_visitor.transfer_description()); } stream_class_str += "};\n\n"; @@ -649,32 +681,7 @@ void tsdl::trace_class_visitor::visit(const lttng::sessiond::trace::event_class& event_class.payload->accept(static_cast(payload_visitor)); event_class_str += fmt::format( - " fields := {};\n}};\n\n", payload_visitor.get_description()); + " fields := {};\n}};\n\n", payload_visitor.transfer_description()); append_metadata_fragment(event_class_str); } - -void tsdl::trace_class_visitor::environment_begin() -{ - _environment += "env {\n"; -} - -void tsdl::trace_class_visitor::visit( - const lttng::sessiond::trace::environment_field& field) -{ - _environment += fmt::format(" {} = {};\n", field.name, field.value); -} - -void tsdl::trace_class_visitor::visit( - const lttng::sessiond::trace::environment_field& field) -{ - _environment += fmt::format( - " {} = \"{}\";\n", field.name, escape_tsdl_env_string_value(field.value)); -} - -void tsdl::trace_class_visitor::environment_end() -{ - _environment += "};\n\n"; - append_metadata_fragment(_environment); - _environment.clear(); -} diff --git a/src/bin/lttng-sessiond/tsdl-trace-class-visitor.hpp b/src/bin/lttng-sessiond/tsdl-trace-class-visitor.hpp index 6d629e2be..d06ea9983 100644 --- a/src/bin/lttng-sessiond/tsdl-trace-class-visitor.hpp +++ b/src/bin/lttng-sessiond/tsdl-trace-class-visitor.hpp @@ -27,22 +27,9 @@ public: trace_class_visitor(const lttng::sessiond::trace::abi& trace_abi, append_metadata_fragment_function append_metadata); - /* trace class visitor interface. */ virtual void visit(const lttng::sessiond::trace::trace_class& trace_class) override final; - - /* clock class visitor interface. */ virtual void visit(const lttng::sessiond::trace::clock_class& clock_class) override final; - - /* environment visitor interface. */ - virtual void environment_begin() override final; - virtual void visit(const lttng::sessiond::trace::environment_field& field) override final; - virtual void visit(const lttng::sessiond::trace::environment_field& field) override final; - virtual void environment_end() override final; - - /* stream class visitor interface. */ virtual void visit(const lttng::sessiond::trace::stream_class& stream_class) override final; - - /* event class visitor interface. */ virtual void visit(const lttng::sessiond::trace::event_class& event_class) override final; private: @@ -51,7 +38,6 @@ private: const lttng::sessiond::trace::abi& _trace_abi; const append_metadata_fragment_function _append_metadata_fragment; - std::string _environment; }; } /* namespace tsdl */ diff --git a/src/bin/lttng-sessiond/ust-field-convert.cpp b/src/bin/lttng-sessiond/ust-field-convert.cpp index 74c41939e..91ab45c1a 100644 --- a/src/bin/lttng-sessiond/ust-field-convert.cpp +++ b/src/bin/lttng-sessiond/ust-field-convert.cpp @@ -594,15 +594,15 @@ typename lst::variant_type::choices create_ty * field's name. */ const auto mapping_it = std::find_if( - typed_enumeration._mappings->begin(), - typed_enumeration._mappings->end(), + typed_enumeration.mappings_->begin(), + typed_enumeration.mappings_->end(), [&field](const typename std::remove_reference< decltype(typed_enumeration)>::type:: mapping& mapping) { return mapping.name == field->name; }); - if (mapping_it == typed_enumeration._mappings->end()) { + if (mapping_it == typed_enumeration.mappings_->end()) { LTTNG_THROW_PROTOCOL_ERROR(fmt::format( "Invalid variant choice: `{}` does not match any mapping in `{}` enumeration", field->name, selector_field.name)); @@ -768,6 +768,35 @@ void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current, lookup_root, current_field_location_elements))); } +std::vector::iterator lookup_field_in_vector( + std::vector& fields, const lst::field_location& location) +{ + if (location.elements_.size() != 1) { + LTTNG_THROW_ERROR(fmt::format( + "Unexpected field location received during field look-up: location = {}", + location)); + } + + /* + * In the context of fields received from LTTng-UST, field + * look-up is extremely naive as the protocol can only + * express empty structures. It is safe to assume that + * location has a depth of 1 and directly refers to a field + * in the 'fields' vector. + */ + const auto field_it = std::find_if(fields.begin(), fields.end(), + [location](lst::field::cuptr &field) { + return field->name == location.elements_[0]; + }); + + if (field_it == fields.end()) { + LTTNG_THROW_PROTOCOL_ERROR( + fmt::format("Failed to look-up field: location = {}", location)); + } + + return field_it; +} + /* * `lttng_ust_ctl_field`s can be nested, in which case creating a field will consume * more than one lttng_ust_ctl_field. create_field_from_ust_ctl_fields returns the @@ -812,34 +841,8 @@ std::vector create_fields_from_ust_ctl_fields( }, [&fields](const lst::field_location& location) -> lookup_field_fn::result_type { - if (location.elements_.size() != 1) { - LTTNG_THROW_ERROR(fmt::format( - "Unexpected field location received during field look-up: location = {}", - location)); - } - - /* - * In the context of fields received from LTTng-UST, field - * look-up is extremely naive as the protocol can only - * express empty structures. It is safe to assume that - * location has a depth of 1 and directly refers to a field - * in the 'fields' vector. - */ - const auto field_it = std::find_if(fields.begin(), - fields.end(), - [&location](decltype(fields)::value_type& - field) { - return field->name == - location.elements_[0]; - }); - - if (field_it == fields.end()) { - LTTNG_THROW_PROTOCOL_ERROR(fmt::format( - "Failed to look-up field: location = {}", - location)); - } - - return **field_it; + /* Resolve location to a previously-constructed field. */ + return **lookup_field_in_vector(fields, location); }, lookup_root, current_field_location_elements); diff --git a/src/bin/lttng-sessiond/ust-registry-channel.cpp b/src/bin/lttng-sessiond/ust-registry-channel.cpp index b6092d197..de14432fa 100644 --- a/src/bin/lttng-sessiond/ust-registry-channel.cpp +++ b/src/bin/lttng-sessiond/ust-registry-channel.cpp @@ -87,7 +87,7 @@ lst::type::cuptr create_event_header(const lst::abi& trace_abi, lst::stream_clas auto enum_mappings = std::make_shared(); lst::unsigned_enumeration_type::mapping compact_mapping{ "compact", lst::unsigned_enumeration_type::mapping::range_t(0, 30)}; - lst::unsigned_enumeration_type::mapping extended_mapping{"extended"}; + lst::unsigned_enumeration_type::mapping extended_mapping{"extended", 31}; enum_mappings->emplace_back(compact_mapping); enum_mappings->emplace_back(extended_mapping); @@ -149,7 +149,7 @@ lst::type::cuptr create_event_header(const lst::abi& trace_abi, lst::stream_clas auto enum_mappings = std::make_shared(); lst::unsigned_enumeration_type::mapping compact_mapping{"compact", lst::unsigned_enumeration_type::mapping::range_t(0, 65534)}; - lst::unsigned_enumeration_type::mapping extended_mapping{"extended"}; + lst::unsigned_enumeration_type::mapping extended_mapping{"extended", 65535}; enum_mappings->emplace_back(compact_mapping); enum_mappings->emplace_back(extended_mapping); diff --git a/src/bin/lttng-sessiond/ust-registry-session-pid.cpp b/src/bin/lttng-sessiond/ust-registry-session-pid.cpp index 7e091fdac..db7bf58ce 100644 --- a/src/bin/lttng-sessiond/ust-registry-session-pid.cpp +++ b/src/bin/lttng-sessiond/ust-registry-session-pid.cpp @@ -37,9 +37,9 @@ lttng_buffer_type lsu::registry_session_per_pid::get_buffering_scheme() const no return LTTNG_BUFFER_PER_PID; } -void lsu::registry_session_per_pid::_visit_environment(lst::trace_class_visitor& visitor) const +void lsu::registry_session_per_pid::accept(lst::trace_class_environment_visitor& visitor) const { - registry_session::_visit_environment(visitor); + registry_session::accept(visitor); visitor.visit(lst::environment_field("tracer_buffering_id", _vpid)); visitor.visit(lst::environment_field( "tracer_patchlevel", _tracer_patch_level_version)); diff --git a/src/bin/lttng-sessiond/ust-registry-session-pid.hpp b/src/bin/lttng-sessiond/ust-registry-session-pid.hpp index aa6cfb91b..4fd541d58 100644 --- a/src/bin/lttng-sessiond/ust-registry-session-pid.hpp +++ b/src/bin/lttng-sessiond/ust-registry-session-pid.hpp @@ -34,12 +34,10 @@ public: uint64_t tracing_id); virtual lttng_buffer_type get_buffering_scheme() const noexcept override final; + virtual void accept(lttng::sessiond::trace::trace_class_environment_visitor& + environment_visitor) const override final; private: - virtual void _visit_environment( - lttng::sessiond::trace::trace_class_visitor& trace_class_visitor) - const override final; - const unsigned int _tracer_patch_level_version; const pid_t _vpid; const std::string _procname; diff --git a/src/bin/lttng-sessiond/ust-registry-session-uid.cpp b/src/bin/lttng-sessiond/ust-registry-session-uid.cpp index 8aa79dd7b..77c46fd7c 100644 --- a/src/bin/lttng-sessiond/ust-registry-session-uid.cpp +++ b/src/bin/lttng-sessiond/ust-registry-session-uid.cpp @@ -32,8 +32,8 @@ lttng_buffer_type lsu::registry_session_per_uid::get_buffering_scheme() const no return LTTNG_BUFFER_PER_UID; } -void lsu::registry_session_per_uid::_visit_environment(lst::trace_class_visitor& visitor) const +void lsu::registry_session_per_uid::accept(lst::trace_class_environment_visitor& visitor) const { - registry_session::_visit_environment(visitor); + registry_session::accept(visitor); visitor.visit(lst::environment_field("tracer_buffering_id", _tracing_uid)); } diff --git a/src/bin/lttng-sessiond/ust-registry-session-uid.hpp b/src/bin/lttng-sessiond/ust-registry-session-uid.hpp index 665bfa5d0..10da75818 100644 --- a/src/bin/lttng-sessiond/ust-registry-session-uid.hpp +++ b/src/bin/lttng-sessiond/ust-registry-session-uid.hpp @@ -32,11 +32,10 @@ public: uid_t tracing_uid); virtual lttng_buffer_type get_buffering_scheme() const noexcept override final; + virtual void accept(lttng::sessiond::trace::trace_class_environment_visitor& + environment_visitor) const override final; private: - virtual void _visit_environment( - lttng::sessiond::trace::trace_class_visitor& trace_class_visitor) - const override final; const uid_t _tracing_uid; }; diff --git a/src/bin/lttng-sessiond/ust-registry-session.cpp b/src/bin/lttng-sessiond/ust-registry-session.cpp index 03a87e286..e1089bd58 100644 --- a/src/bin/lttng-sessiond/ust-registry-session.cpp +++ b/src/bin/lttng-sessiond/ust-registry-session.cpp @@ -11,6 +11,7 @@ #include "session.hpp" #include "trace-class.hpp" #include "tsdl-trace-class-visitor.hpp" +#include "ctf2-trace-class-visitor.hpp" #include "ust-app.hpp" #include "ust-field-convert.hpp" #include "ust-registry.hpp" @@ -222,7 +223,6 @@ unsigned long ht_hash_enum(void *_key, unsigned long seed) LTTNG_ASSERT(key); return hash_key_str(key->name.c_str(), seed); } - } /* namespace */ void lsu::details::locked_registry_session_release(lsu::registry_session *session) @@ -302,7 +302,7 @@ lst::type::cuptr lsu::registry_session::_create_packet_header() const /* uuid */ packet_header_fields.emplace_back(lttng::make_unique("uuid", lttng::make_unique(0, 16, - std::initializer_list({lst::static_length_blob_type::role::TRACE_CLASS_UUID})))); + std::initializer_list({lst::static_length_blob_type::role::METADATA_STREAM_UUID})))); /* uint32_t stream_id */ packet_header_fields.emplace_back(lttng::make_unique("stream_id", @@ -495,8 +495,8 @@ void lsu::registry_session::remove_channel(uint64_t channel_key, bool notify) destroy_channel(&channel, notify); } -void lsu::registry_session::_visit_environment( - lttng::sessiond::trace::trace_class_visitor& visitor) const +void lsu::registry_session::accept( + lttng::sessiond::trace::trace_class_environment_visitor& visitor) const { ASSERT_LOCKED(_lock); @@ -647,7 +647,7 @@ void lsu::registry_session::_reset_metadata() void lsu::registry_session::_generate_metadata() { - accept(*_metadata_generating_visitor); + trace_class::accept(*_metadata_generating_visitor); } void lsu::registry_session::regenerate_metadata() diff --git a/src/bin/lttng-sessiond/ust-registry-session.hpp b/src/bin/lttng-sessiond/ust-registry-session.hpp index fc425dca0..5f59e6160 100644 --- a/src/bin/lttng-sessiond/ust-registry-session.hpp +++ b/src/bin/lttng-sessiond/ust-registry-session.hpp @@ -104,9 +104,8 @@ protected: uid_t euid, gid_t egid, uint64_t tracing_id); - virtual void _visit_environment( - lttng::sessiond::trace::trace_class_visitor& trace_class_visitor) - const override; + virtual void accept( + trace::trace_class_environment_visitor& environment_visitor) const override; void _generate_metadata(); private: diff --git a/src/bin/lttng-sessiond/ust-registry.hpp b/src/bin/lttng-sessiond/ust-registry.hpp index c43821100..2095cdda3 100644 --- a/src/bin/lttng-sessiond/ust-registry.hpp +++ b/src/bin/lttng-sessiond/ust-registry.hpp @@ -47,30 +47,29 @@ class registry_session; namespace details { -template -typename trace::typed_enumeration_type::mapping mapping_from_ust_ctl_entry( - const lttng_ust_ctl_enum_entry& entry) -{ - if (entry.u.extra.options & LTTNG_UST_CTL_UST_ENUM_ENTRY_OPTION_IS_AUTO) { - return {entry.string}; - - } else { - return {entry.string, - {(MappingIntegerType) entry.start.value, - (MappingIntegerType) entry.end.value}}; - } -} - template typename trace::typed_enumeration_type::mappings mappings_from_ust_ctl_entries( const lttng_ust_ctl_enum_entry *in_entries, size_t in_entry_count) { typename trace::typed_enumeration_type::mappings mappings; + MappingIntegerType next_range_begin = 0; for (size_t entry_idx = 0; entry_idx < in_entry_count; entry_idx++) { const auto& entry = in_entries[entry_idx]; - - mappings.emplace_back(mapping_from_ust_ctl_entry(entry)); + MappingIntegerType range_begin, range_end; + + if (entry.u.extra.options & LTTNG_UST_CTL_UST_ENUM_ENTRY_OPTION_IS_AUTO) { + range_begin = range_end = next_range_begin; + } else { + range_begin = (MappingIntegerType) entry.start.value; + range_end = (MappingIntegerType) entry.end.value; + } + + next_range_begin = range_end + 1; + mappings.emplace_back(entry.string, + typename trace::typed_enumeration_type< + MappingIntegerType>::mapping::range_t{ + range_begin, range_end}); } return mappings;