1 /*
2 * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_H_
12 #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_H_
13
14 #include <string>
15 #include <vector>
16
17 #include "absl/types/optional.h"
18 #include "api/array_view.h"
19 #include "api/rtc_event_log/rtc_event.h"
20 #include "logging/rtc_event_log/encoder/rtc_event_log_encoder_common.h"
21 #include "logging/rtc_event_log/events/fixed_length_encoding_parameters_v3.h"
22 #include "logging/rtc_event_log/events/rtc_event_field_extraction.h"
23 #include "rtc_base/logging.h"
24
25 namespace webrtc {
26
27 // To maintain backwards compatibility with past (or future) logs,
28 // the constants in this enum must not be changed.
29 // New field types with numerical IDs 5-7 can be added, but old
30 // parsers will fail to parse events containing the new fields.
31 enum class FieldType : uint8_t {
32 kFixed8 = 0,
33 kFixed32 = 1,
34 kFixed64 = 2,
35 kVarInt = 3,
36 kString = 4,
37 };
38
39 // EventParameters map an event name to a numerical ID.
40 struct EventParameters {
41 // The name is primarily used for debugging purposes.
42 const char* const name;
43 //
44 const RtcEvent::Type id;
45 };
46
47 // FieldParameters define the encoding for a field.
48 struct FieldParameters {
49 // The name is primarily used for debugging purposes.
50 const char* const name;
51 // Numerical ID for the field. Must be strictly greater than 0,
52 // and unique within each event type.
53 const uint64_t field_id;
54 // Encoding type for the base (i.e. non-delta) field in a batch.
55 const FieldType field_type;
56 // Number of bits after which wrap-around occurs. In most cases,
57 // this should be the number of bits in the field data type, i.e.
58 // 8 for an uint8_t, 32 for a int32_t and so on. However, `value_width`
59 // can be used to achieve a more efficient encoding if it is known
60 // that the field uses a smaller number of bits. For example, a
61 // 15-bit counter could set `value_width` to 15 even if the data is
62 // actually stored in a uint32_t.
63 const uint64_t value_width;
64 // Field ID 0 is reserved for timestamps.
65 static constexpr uint64_t kTimestampField = 0;
66 };
67
68 // The EventEncoder is used to encode a batch of events.
69 class EventEncoder {
70 public:
71 EventEncoder(EventParameters params, rtc::ArrayView<const RtcEvent*> batch);
72
73 void EncodeField(const FieldParameters& params,
74 const std::vector<uint64_t>& values,
75 const std::vector<bool>* positions = nullptr);
76
77 void EncodeField(const FieldParameters& params,
78 const ValuesWithPositions& values);
79
80 void EncodeField(const FieldParameters& params,
81 const std::vector<absl::string_view>& values);
82
83 std::string AsString();
84
85 private:
86 size_t batch_size_;
87 uint32_t event_tag_;
88 std::vector<std::string> encoded_fields_;
89 };
90
91 std::string EncodeSingleValue(uint64_t value, FieldType field_type);
92 std::string EncodeDeltasV3(FixedLengthEncodingParametersV3 params,
93 uint64_t base,
94 rtc::ArrayView<const uint64_t> values);
95
96 // Given a batch of RtcEvents and a member pointer, extract that
97 // member from each event in the batch. Signed integer members are
98 // encoded as unsigned, and the bitsize increased so the result can
99 // represented as a std::vector<uint64_t>.
100 // This is intended to be used in conjuction with
101 // EventEncoder::EncodeField to encode a batch of events as follows:
102 // auto values = ExtractRtcEventMember(batch, RtcEventFoo::timestamp_ms);
103 // encoder.EncodeField(timestamp_params, values)
104 template <typename T,
105 typename E,
106 std::enable_if_t<std::is_integral<T>::value, bool> = true>
ExtractRtcEventMember(rtc::ArrayView<const RtcEvent * > batch,const T E::* member)107 std::vector<uint64_t> ExtractRtcEventMember(
108 rtc::ArrayView<const RtcEvent*> batch,
109 const T E::*member) {
110 std::vector<uint64_t> values;
111 values.reserve(batch.size());
112 for (const RtcEvent* event : batch) {
113 RTC_CHECK_EQ(event->GetType(), E::kType);
114 T value = static_cast<const E*>(event)->*member;
115 values.push_back(EncodeAsUnsigned(value));
116 }
117 return values;
118 }
119
120 // Extract an optional field from a batch of RtcEvents.
121 // The function returns a vector of positions in addition to the vector of
122 // values. The vector `positions` has the same length as the batch where
123 // `positions[i] == true` iff the batch[i]->member has a value.
124 // The values vector only contains the values that exists, so it
125 // may be shorter than the batch.
126 template <typename T,
127 typename E,
128 std::enable_if_t<std::is_integral<T>::value, bool> = true>
ExtractRtcEventMember(rtc::ArrayView<const RtcEvent * > batch,const absl::optional<T> E::* member)129 ValuesWithPositions ExtractRtcEventMember(rtc::ArrayView<const RtcEvent*> batch,
130 const absl::optional<T> E::*member) {
131 ValuesWithPositions result;
132 result.position_mask.reserve(batch.size());
133 result.values.reserve(batch.size());
134 for (const RtcEvent* event : batch) {
135 RTC_CHECK_EQ(event->GetType(), E::kType);
136 absl::optional<T> field = static_cast<const E*>(event)->*member;
137 result.position_mask.push_back(field.has_value());
138 if (field.has_value()) {
139 result.values.push_back(EncodeAsUnsigned(field.value()));
140 }
141 }
142 return result;
143 }
144
145 // Extract an enum field from a batch of RtcEvents.
146 // Requires specializing RtcEventLogEnum<T> for the enum type T.
147 template <typename T,
148 typename E,
149 std::enable_if_t<std::is_enum<T>::value, bool> = true>
ExtractRtcEventMember(rtc::ArrayView<const RtcEvent * > batch,const T E::* member)150 std::vector<uint64_t> ExtractRtcEventMember(
151 rtc::ArrayView<const RtcEvent*> batch,
152 const T E::*member) {
153 std::vector<uint64_t> values;
154 values.reserve(batch.size());
155 for (const RtcEvent* event : batch) {
156 RTC_CHECK_EQ(event->GetType(), E::kType);
157 T value = static_cast<const E*>(event)->*member;
158 values.push_back(RtcEventLogEnum<T>::Encode(value));
159 }
160 return values;
161 }
162
163 // Extract a string field from a batch of RtcEvents.
164 template <typename E>
ExtractRtcEventMember(rtc::ArrayView<const RtcEvent * > batch,const std::string E::* member)165 std::vector<absl::string_view> ExtractRtcEventMember(
166 rtc::ArrayView<const RtcEvent*> batch,
167 const std::string E::*member) {
168 std::vector<absl::string_view> values;
169 values.reserve(batch.size());
170 for (const RtcEvent* event : batch) {
171 RTC_CHECK_EQ(event->GetType(), E::kType);
172 absl::string_view str = static_cast<const E*>(event)->*member;
173 values.push_back(str);
174 }
175 return values;
176 }
177
178 } // namespace webrtc
179 #endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_FIELD_ENCODING_H_
180