1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
18 #define SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
19
20 #include <optional>
21 #include <unordered_map>
22
23 #include "perfetto/trace_processor/ref_counted.h"
24 #include "perfetto/trace_processor/trace_blob_view.h"
25 #include "src/trace_processor/importers/proto/track_event_sequence_state.h"
26 #include "src/trace_processor/util/interned_message_view.h"
27
28 #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
29 #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
30 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
31
32 namespace perfetto {
33 namespace trace_processor {
34
35 using InternedMessageMap =
36 std::unordered_map<uint64_t /*iid*/, InternedMessageView>;
37 using InternedFieldMap =
38 std::unordered_map<uint32_t /*field_id*/, InternedMessageMap>;
39
40 class TraceProcessorContext;
41
42 class StackProfileSequenceState;
43 class ProfilePacketSequenceState;
44 class V8SequenceState;
45
46 using CustomStateClasses = std::tuple<StackProfileSequenceState,
47 ProfilePacketSequenceState,
48 V8SequenceState>;
49
50 // This is the public API exposed to packet tokenizers and parsers to access
51 // state attached to a packet sequence. This state evolves as packets are
52 // processed in sequence order. A packet that requires sequence state to be
53 // properly parsed should snapshot this state by taking a copy of the RefPtr to
54 // the currently active generation and passing it along with parsing specific
55 // data to the sorting stage.
56 class PacketSequenceStateGeneration : public RefCounted {
57 public:
58 // Base class to attach custom state to the sequence state. This state is keep
59 // per sequence and per incremental state interval, that is, each time
60 // incremental state is reset a new instance is created but not each time
61 // `TracePacketDefaults` are updated. Note that this means that different
62 // `PacketSequenceStateGeneration` instances might point to the same
63 // `CustomState` (because they only differ in their `TracePacketDefaults`).
64 //
65 // ATTENTION: You should not create instances of these classes yourself but
66 // use the `PacketSequenceStateGeneration::GetCustomState<>' method instead.
67 class CustomState : public RefCounted {
68 public:
69 virtual ~CustomState();
70
71 protected:
72 template <uint32_t FieldId, typename MessageType>
LookupInternedMessage(uint64_t iid)73 typename MessageType::Decoder* LookupInternedMessage(uint64_t iid) {
74 return generation_->LookupInternedMessage<FieldId, MessageType>(iid);
75 }
76
GetInternedMessageView(uint32_t field_id,uint64_t iid)77 InternedMessageView* GetInternedMessageView(uint32_t field_id,
78 uint64_t iid) {
79 return generation_->GetInternedMessageView(field_id, iid);
80 }
81
82 template <typename T>
GetCustomState()83 std::remove_cv_t<T>* GetCustomState() {
84 return generation_->GetCustomState<T>();
85 }
86
pid_and_tid_valid()87 bool pid_and_tid_valid() const { return generation_->pid_and_tid_valid(); }
pid()88 int32_t pid() const { return generation_->pid(); }
tid()89 int32_t tid() const { return generation_->tid(); }
90
91 private:
92 friend PacketSequenceStateGeneration;
93 // Called when the a new generation is created as a result of
94 // `TracePacketDefaults` being updated.
set_generation(PacketSequenceStateGeneration * generation)95 void set_generation(PacketSequenceStateGeneration* generation) {
96 generation_ = generation;
97 }
98
99 // Note: A `InternedDataTracker` instance can be linked to multiple
100 // `PacketSequenceStateGeneration` instances (when there are multiple
101 // `TracePacketDefaults` in the same interning context). `generation_` will
102 // point to the latest one. We keep this member private to prevent misuse /
103 // confusion around this fact. Instead subclasses should access the public
104 // methods of this class to get any interned data.
105 // TODO(carlscab): Given that CustomState is ref counted this pointer might
106 // become invalid. CustomState should not be ref pointed and instead be
107 // owned by the `PacketSequenceStateGeneration` instance pointed at by
108 // `generation_`.
109 PacketSequenceStateGeneration* generation_ = nullptr;
110 };
111
112 static RefPtr<PacketSequenceStateGeneration> CreateFirst(
113 TraceProcessorContext* context);
114
115 RefPtr<PacketSequenceStateGeneration> OnPacketLoss();
116
117 RefPtr<PacketSequenceStateGeneration> OnIncrementalStateCleared();
118
119 RefPtr<PacketSequenceStateGeneration> OnNewTracePacketDefaults(
120 TraceBlobView trace_packet_defaults);
121
pid_and_tid_valid()122 bool pid_and_tid_valid() const {
123 return track_event_sequence_state_.pid_and_tid_valid();
124 }
pid()125 int32_t pid() const { return track_event_sequence_state_.pid(); }
tid()126 int32_t tid() const { return track_event_sequence_state_.tid(); }
127
128 // Returns |nullptr| if the message with the given |iid| was not found (also
129 // records a stat in this case).
130 template <uint32_t FieldId, typename MessageType>
LookupInternedMessage(uint64_t iid)131 typename MessageType::Decoder* LookupInternedMessage(uint64_t iid) {
132 auto* interned_message_view = GetInternedMessageView(FieldId, iid);
133 if (!interned_message_view)
134 return nullptr;
135
136 return interned_message_view->template GetOrCreateDecoder<MessageType>();
137 }
138
139 InternedMessageView* GetInternedMessageView(uint32_t field_id, uint64_t iid);
140 // Returns |nullptr| if no defaults were set.
GetTracePacketDefaultsView()141 InternedMessageView* GetTracePacketDefaultsView() {
142 if (!trace_packet_defaults_.has_value()) {
143 return nullptr;
144 }
145
146 return &*trace_packet_defaults_;
147 }
148
149 // Returns |nullptr| if no defaults were set.
GetTracePacketDefaults()150 protos::pbzero::TracePacketDefaults::Decoder* GetTracePacketDefaults() {
151 if (!trace_packet_defaults_.has_value()) {
152 return nullptr;
153 }
154 return trace_packet_defaults_
155 ->GetOrCreateDecoder<protos::pbzero::TracePacketDefaults>();
156 }
157
158 // Returns |nullptr| if no TrackEventDefaults were set.
GetTrackEventDefaults()159 protos::pbzero::TrackEventDefaults::Decoder* GetTrackEventDefaults() {
160 auto* packet_defaults_view = GetTracePacketDefaultsView();
161 if (packet_defaults_view) {
162 auto* track_event_defaults_view =
163 packet_defaults_view
164 ->GetOrCreateSubmessageView<protos::pbzero::TracePacketDefaults,
165 protos::pbzero::TracePacketDefaults::
166 kTrackEventDefaultsFieldNumber>();
167 if (track_event_defaults_view) {
168 return track_event_defaults_view
169 ->GetOrCreateDecoder<protos::pbzero::TrackEventDefaults>();
170 }
171 }
172 return nullptr;
173 }
174
175 // Extension point for custom incremental state. Custom state classes need to
176 // inherit from `CustomState`.
177 //
178 // A common use case for this custom state is to store cache mappings between
179 // interning ids (iid) and TraceProcessor objects (e.g. table row). When we
180 // see an iid we need to access the InternedMessageView for that iid, and
181 // possibly do some computations, the result of all of this could then be
182 // cached so that next time we encounter the same iid we could reuse this
183 // cached value. This caching is only valid until incremental state is
184 // cleared, from then on subsequent iid values on the sequence will no longer
185 // refer to the same entities as the iid values before the clear. Custom state
186 // classes no not need to explicitly handle this: they are attached to an
187 // `IncrementalState` instance, and a new one is created when the state is
188 // cleared, so iid values after the clear will be processed by a new (empty)
189 // custom state instance.
190 template <typename T>
191 std::remove_cv_t<T>* GetCustomState();
192
IncrementAndGetTrackEventTimeNs(int64_t delta_ns)193 int64_t IncrementAndGetTrackEventTimeNs(int64_t delta_ns) {
194 return track_event_sequence_state_.IncrementAndGetTrackEventTimeNs(
195 delta_ns);
196 }
197
IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns)198 int64_t IncrementAndGetTrackEventThreadTimeNs(int64_t delta_ns) {
199 return track_event_sequence_state_.IncrementAndGetTrackEventThreadTimeNs(
200 delta_ns);
201 }
202
IncrementAndGetTrackEventThreadInstructionCount(int64_t delta)203 int64_t IncrementAndGetTrackEventThreadInstructionCount(int64_t delta) {
204 return track_event_sequence_state_
205 .IncrementAndGetTrackEventThreadInstructionCount(delta);
206 }
207
track_event_timestamps_valid()208 bool track_event_timestamps_valid() const {
209 return track_event_sequence_state_.timestamps_valid();
210 }
211
SetThreadDescriptor(const protos::pbzero::ThreadDescriptor::Decoder & descriptor)212 void SetThreadDescriptor(
213 const protos::pbzero::ThreadDescriptor::Decoder& descriptor) {
214 track_event_sequence_state_.SetThreadDescriptor(descriptor);
215 }
216
217 // TODO(carlscab): Nobody other than `ProtoTraceReader` should care about
218 // this. Remove.
IsIncrementalStateValid()219 bool IsIncrementalStateValid() const { return is_incremental_state_valid_; }
220
221 private:
222 friend class PacketSequenceStateBuilder;
223
224 using CustomStateArray =
225 std::array<RefPtr<CustomState>, std::tuple_size_v<CustomStateClasses>>;
226
227 // Helper to find the index in a tuple of a given type. Lookups are done
228 // ignoring cv qualifiers. If no index is found size of the tuple is returned.
229 //
230 // ATTENTION: Duplicate types in the tuple will trigger a compiler error.
231 template <typename Tuple, typename Type, size_t index = 0>
FindUniqueType()232 static constexpr size_t FindUniqueType() {
233 constexpr size_t kSize = std::tuple_size_v<Tuple>;
234 if constexpr (index < kSize) {
235 using TypeAtIndex = typename std::tuple_element<index, Tuple>::type;
236 if constexpr (std::is_same_v<std::remove_cv_t<Type>,
237 std::remove_cv_t<TypeAtIndex>>) {
238 static_assert(FindUniqueType<Tuple, Type, index + 1>() == kSize,
239 "Duplicate types.");
240 return index;
241 } else {
242 return FindUniqueType<Tuple, Type, index + 1>();
243 }
244 } else {
245 return kSize;
246 }
247 }
248
PacketSequenceStateGeneration(TraceProcessorContext * context,TrackEventSequenceState track_state,bool is_incremental_state_valid)249 PacketSequenceStateGeneration(TraceProcessorContext* context,
250 TrackEventSequenceState track_state,
251 bool is_incremental_state_valid)
252 : context_(context),
253 track_event_sequence_state_(std::move(track_state)),
254 is_incremental_state_valid_(is_incremental_state_valid) {}
255
256 PacketSequenceStateGeneration(
257 TraceProcessorContext* context,
258 InternedFieldMap interned_data,
259 TrackEventSequenceState track_event_sequence_state,
260 CustomStateArray custom_state,
261 TraceBlobView trace_packet_defaults,
262 bool is_incremental_state_valid);
263
264 // Add an interned message to this incremental state view. This can only be
265 // called by `PacketSequenceStateBuilder' (which is a friend) as packet
266 // tokenizers and parsers should never deal directly with reading interned
267 // data out of trace packets.
268 void InternMessage(uint32_t field_id, TraceBlobView message);
269
270 TraceProcessorContext* const context_;
271 InternedFieldMap interned_data_;
272 TrackEventSequenceState track_event_sequence_state_;
273 CustomStateArray custom_state_;
274 std::optional<InternedMessageView> trace_packet_defaults_;
275 // TODO(carlscab): Should not be needed as clients of this class should not
276 // care about validity.
277 bool is_incremental_state_valid_ = true;
278 };
279
280 template <typename T>
GetCustomState()281 std::remove_cv_t<T>* PacketSequenceStateGeneration::GetCustomState() {
282 constexpr size_t index = FindUniqueType<CustomStateClasses, T>();
283 static_assert(index < std::tuple_size_v<CustomStateClasses>, "Not found");
284 auto& ptr = custom_state_[index];
285 if (PERFETTO_UNLIKELY(ptr.get() == nullptr)) {
286 ptr.reset(new T(context_));
287 ptr->set_generation(this);
288 }
289
290 return static_cast<std::remove_cv_t<T>*>(ptr.get());
291 }
292
293 } // namespace trace_processor
294 } // namespace perfetto
295
296 #endif // SRC_TRACE_PROCESSOR_IMPORTERS_PROTO_PACKET_SEQUENCE_STATE_GENERATION_H_
297