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