| /* |
| * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_H_ |
| #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_H_ |
| |
| #include <string> |
| #include <vector> |
| |
| #include "absl/types/optional.h" |
| #include "api/array_view.h" |
| #include "api/rtc_event_log/rtc_event.h" |
| #include "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h" |
| #include "logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.h" |
| #include "logging/rtc_event_log/events/rtc_event_field_extraction.h" |
| #include "rtc_base/logging.h" |
| |
| namespace webrtc { |
| |
| // To maintain backwards compatibility with past (or future) logs, |
| // the constants in this enum must not be changed. |
| // New field types with numerical IDs 5-7 can be added, but old |
| // parsers will fail to parse events containing the new fields. |
| enum class FieldType : uint8_t { |
| kFixed8 = 0, |
| kFixed32 = 1, |
| kFixed64 = 2, |
| kVarInt = 3, |
| kString = 4, |
| }; |
| |
| // EventParameters map an event name to a numerical ID. |
| struct EventParameters { |
| // The name is primarily used for debugging purposes. |
| const char* const name; |
| // |
| const RtcEvent::Type id; |
| }; |
| |
| // FieldParameters define the encoding for a field. |
| struct FieldParameters { |
| // The name is primarily used for debugging purposes. |
| const char* const name; |
| // Numerical ID for the field. Must be strictly greater than 0, |
| // and unique within each event type. |
| const uint64_t field_id; |
| // Encoding type for the base (i.e. non-delta) field in a batch. |
| const FieldType field_type; |
| // Number of bits after which wrap-around occurs. In most cases, |
| // this should be the number of bits in the field data type, i.e. |
| // 8 for an uint8_t, 32 for a int32_t and so on. However, `value_width` |
| // can be used to achieve a more efficient encoding if it is known |
| // that the field uses a smaller number of bits. For example, a |
| // 15-bit counter could set `value_width` to 15 even if the data is |
| // actually stored in a uint32_t. |
| const uint64_t value_width; |
| // Field ID 0 is reserved for timestamps. |
| static constexpr uint64_t kTimestampField = 0; |
| }; |
| |
| // The EventEncoder is used to encode a batch of events. |
| class EventEncoder { |
| public: |
| EventEncoder(EventParameters params, rtc::ArrayView<const RtcEvent*> batch); |
| |
| void EncodeField(const FieldParameters& params, |
| const std::vector<uint64_t>& values, |
| const std::vector<bool>* positions = nullptr); |
| |
| void EncodeField(const FieldParameters& params, |
| const ValuesWithPositions& values); |
| |
| void EncodeField(const FieldParameters& params, |
| const std::vector<absl::string_view>& values); |
| |
| std::string AsString(); |
| |
| private: |
| size_t batch_size_; |
| uint32_t event_tag_; |
| std::vector<std::string> encoded_fields_; |
| }; |
| |
| std::string EncodeSingleValue(uint64_t value, FieldType field_type); |
| std::string EncodeDeltasV3(FixedLengthEncodingParametersV3 params, |
| uint64_t base, |
| rtc::ArrayView<const uint64_t> values); |
| |
| // Given a batch of RtcEvents and a member pointer, extract that |
| // member from each event in the batch. Signed integer members are |
| // encoded as unsigned, and the bitsize increased so the result can |
| // represented as a std::vector<uint64_t>. |
| // This is intended to be used in conjuction with |
| // EventEncoder::EncodeField to encode a batch of events as follows: |
| // auto values = ExtractRtcEventMember(batch, RtcEventFoo::timestamp_ms); |
| // encoder.EncodeField(timestamp_params, values) |
| template <typename T, |
| typename E, |
| std::enable_if_t<std::is_integral<T>::value, bool> = true> |
| std::vector<uint64_t> ExtractRtcEventMember( |
| rtc::ArrayView<const RtcEvent*> batch, |
| const T E::*member) { |
| std::vector<uint64_t> values; |
| values.reserve(batch.size()); |
| for (const RtcEvent* event : batch) { |
| RTC_CHECK_EQ(event->GetType(), E::kType); |
| T value = static_cast<const E*>(event)->*member; |
| values.push_back(EncodeAsUnsigned(value)); |
| } |
| return values; |
| } |
| |
| // Extract an optional field from a batch of RtcEvents. |
| // The function returns a vector of positions in addition to the vector of |
| // values. The vector `positions` has the same length as the batch where |
| // `positions[i] == true` iff the batch[i]->member has a value. |
| // The values vector only contains the values that exists, so it |
| // may be shorter than the batch. |
| template <typename T, |
| typename E, |
| std::enable_if_t<std::is_integral<T>::value, bool> = true> |
| ValuesWithPositions ExtractRtcEventMember(rtc::ArrayView<const RtcEvent*> batch, |
| const absl::optional<T> E::*member) { |
| ValuesWithPositions result; |
| result.position_mask.reserve(batch.size()); |
| result.values.reserve(batch.size()); |
| for (const RtcEvent* event : batch) { |
| RTC_CHECK_EQ(event->GetType(), E::kType); |
| absl::optional<T> field = static_cast<const E*>(event)->*member; |
| result.position_mask.push_back(field.has_value()); |
| if (field.has_value()) { |
| result.values.push_back(EncodeAsUnsigned(field.value())); |
| } |
| } |
| return result; |
| } |
| |
| // Extract an enum field from a batch of RtcEvents. |
| // Requires specializing RtcEventLogEnum<T> for the enum type T. |
| template <typename T, |
| typename E, |
| std::enable_if_t<std::is_enum<T>::value, bool> = true> |
| std::vector<uint64_t> ExtractRtcEventMember( |
| rtc::ArrayView<const RtcEvent*> batch, |
| const T E::*member) { |
| std::vector<uint64_t> values; |
| values.reserve(batch.size()); |
| for (const RtcEvent* event : batch) { |
| RTC_CHECK_EQ(event->GetType(), E::kType); |
| T value = static_cast<const E*>(event)->*member; |
| values.push_back(RtcEventLogEnum<T>::Encode(value)); |
| } |
| return values; |
| } |
| |
| // Extract a string field from a batch of RtcEvents. |
| template <typename E> |
| std::vector<absl::string_view> ExtractRtcEventMember( |
| rtc::ArrayView<const RtcEvent*> batch, |
| const std::string E::*member) { |
| std::vector<absl::string_view> values; |
| values.reserve(batch.size()); |
| for (const RtcEvent* event : batch) { |
| RTC_CHECK_EQ(event->GetType(), E::kType); |
| absl::string_view str = static_cast<const E*>(event)->*member; |
| values.push_back(str); |
| } |
| return values; |
| } |
| |
| } // namespace webrtc |
| #endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_H_ |